heruvym/internal/controllers/other/other.go
2024-09-30 22:31:57 +03:00

400 lines
9.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package other
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/go-redis/redis/v8"
"github.com/gofiber/fiber/v2"
"github.com/rs/xid"
"gopkg.in/telebot.v3"
tb "gopkg.in/tucnak/telebot.v2"
"heruvym/internal/repository/minio"
"heruvym/internal/repository/mongo"
"heruvym/internal/utils/jwt_adapter"
"heruvym/internal/utils/middleware"
"heruvym/utils"
"io"
"strings"
"sync"
"time"
)
type Deps struct {
Dal *mongo.DAL
RedisClient *redis.Client
BS *minio.BlobStore
Notifier *telebot.Bot
TgChatID int64
}
type OtherController struct {
dal *mongo.DAL
redisClient *redis.Client
bs *minio.BlobStore
notifier *telebot.Bot
tgChatID int64
}
func NewOtherController(deps Deps) *OtherController {
return &OtherController{
dal: deps.Dal,
redisClient: deps.RedisClient,
bs: deps.BS,
notifier: deps.Notifier,
tgChatID: deps.TgChatID,
}
}
type ReqScreenshot struct {
TicketID string `json:"ticket"`
Lang string `json:"lang"`
}
func (o *OtherController) RequestScreenshot(ctx *fiber.Ctx) error {
var request ReqScreenshot
sess := jwt_adapter.Get(ctx.Context())
_, err := o.dal.PutSCRequest(
ctx.Context(),
sess.Id,
sess.Id,
request.TicketID,
)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return ctx.SendStatus(fiber.StatusOK)
}
// MB Size constants
const (
MB = 1 << 20
)
var fileTypeLimits = map[string]int64{
"image": 5 * MB,
"video": 50 * MB,
"document": 10 * MB,
}
type PutFileReq struct {
Ticket string `json:"ticket"`
}
type PutFileResp struct {
Message string `json:"message"`
}
// todo чекнуть надо как я переписал
func (o *OtherController) PutFile(ctx *fiber.Ctx) error {
sess := jwt_adapter.Get(ctx.Context())
if sess == nil {
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "not authorized"})
}
TimeKey := fmt.Sprintf("sendLockHeruvym:%s", sess.Id)
isNewKey, err := o.redisClient.SetNX(ctx.Context(), TimeKey, time.Now().Unix(), 30*time.Second).Result()
if err != nil {
return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
if !isNewKey {
return ctx.Status(fiber.StatusTooManyRequests).JSON(fiber.Map{"error": "file upload limit exceeded"})
}
form, err := ctx.MultipartForm()
if err != nil {
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "can not parse multipart: " + err.Error()})
}
if form == nil || form.File == nil {
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "no multipart or file"})
}
files := form.File
for _, fileHeaders := range files {
for _, fileHeader := range fileHeaders {
fileSize := fileHeader.Size
fileType := utils.GetFileType(fileHeader.Filename)
if limit, ok := fileTypeLimits[fileType]; ok {
if fileSize > limit {
return ctx.Status(fiber.StatusRequestEntityTooLarge).JSON(fiber.Map{"error": fileType + " file size exceeds the limit"})
}
} else {
return ctx.Status(fiber.StatusNotAcceptable).JSON(fiber.Map{"error": "Unsupported file type"})
}
}
}
filesCount := len(files)
if filesCount == 0 {
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "no files"})
}
var req PutFileReq
if ticket := form.Value["ticket"]; len(ticket) > 0 {
req.Ticket = ticket[0]
}
var (
fileIDs, filenames []string
errFile error
)
wg := new(sync.WaitGroup)
m := new(sync.Mutex)
wg.Add(filesCount)
for name, file := range files {
file := file
name := name
go func() {
defer wg.Done()
freader, err := file[0].Open()
if err != nil {
fmt.Println("can not open ", err.Error())
errFile = err
return
}
hash := sha256.New()
if _, err := io.Copy(hash, freader); err != nil {
fmt.Println("error calculating file hash: ", err)
errFile = err
return
}
_, err = freader.Seek(0, 0)
if err != nil {
fmt.Println("error seeking back to the beginning of the file: ", err)
errFile = err
return
}
hashInBytes := hash.Sum(nil)
fileHash := hex.EncodeToString(hashInBytes)
splitted := strings.Split(name, ".")
filename := fmt.Sprintf("%s_%s.%s", fileHash, sess.Id, splitted[len(splitted)-1])
defer func() {
if err := freader.Close(); err != nil {
errFile = err
}
}()
exists, err := o.bs.FileExists(ctx.Context(), filename)
if err != nil {
errFile = err
return
}
if exists {
response := struct {
File string `json:"file"`
}{
File: filename,
}
resp, err := json.Marshal(response)
if err != nil {
ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "error marshaling response: " + err.Error()})
return
}
ctx.Status(fiber.StatusAlreadyReported).Send(resp)
m.Lock()
defer m.Unlock()
fileIDs = append(fileIDs, filename)
filenames = append(filenames, name)
return
}
if err := o.bs.PutFile(
ctx.Context(),
filename,
freader,
file[0].Size); err != nil {
errFile = err
}
m.Lock()
defer m.Unlock()
fileIDs = append(fileIDs, filename)
filenames = append(filenames, name)
}()
}
wg.Wait()
if errFile != nil || len(fileIDs) == 0 {
return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "can not store files: " + errFile.Error()})
}
message, err := o.dal.PutMessage(
ctx.Context(),
strings.Join(filenames, ", "),
sess.Id,
sess.Id,
req.Ticket,
fileIDs,
)
if err != nil {
for _, filename := range filenames {
if err := o.bs.DeleteFile(ctx.Context(), filename); err != nil {
fmt.Println("can not delete", err)
}
}
return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "can not store message: " + err.Error()})
}
domain := ctx.Context().Value(middleware.HostKey).(string)
if domain == "" {
fmt.Println("domain is nil err")
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "domain is nil"})
}
role := jwt_adapter.GetRole(ctx.Context())
go func() {
if sess.Id != "" && role != "admin" {
if err == nil && o.notifier != nil {
var userLink, supportLink string
if sess.StandardClaims.Issuer != "" {
fmt.Println("MABNAT", domain)
if domain[0] == 's' {
userLink = fmt.Sprintf("https://sadmin.pena/users/%s", sess.Id)
supportLink = fmt.Sprintf("https://sadmin.pena/support/%s", req.Ticket)
} else {
userLink = fmt.Sprintf("https://admin.pena/users/%s", sess.Id)
supportLink = fmt.Sprintf("https://admin.pena/support/%s", req.Ticket)
}
} else {
if domain[0] == 's' {
supportLink = fmt.Sprintf("https://sadmin.pena/support/%s", req.Ticket)
} else {
supportLink = fmt.Sprintf("https://admin.pena/support/%s", req.Ticket)
}
userLink = "незарегистрированного пользователя"
}
message := fmt.Sprintf("Вам пришло сообщение от %s сссылка на пользователя с %s, ccылка на чат - %s",
userLink, domain, supportLink)
if _, err := o.notifier.Send(tb.ChatID(o.tgChatID), message); err != nil {
fmt.Println("CAN NOT NOTIFY", err)
}
return
}
}
}()
return ctx.Status(fiber.StatusOK).JSON(PutFileResp{Message: message.ID})
}
type PutSCReq struct {
Ticket string `json:"ticket"`
}
type PutSCResp struct {
Message string `json:"message"`
}
// todo чекнуть надо как я переписал
func (o *OtherController) PutSC(ctx *fiber.Ctx) error {
form, err := ctx.MultipartForm()
if err != nil {
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "can not parse multipart: " + err.Error()})
}
if form == nil || form.File == nil {
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "no multipart or file"})
}
files := form.File
filesCount := len(files)
if filesCount == 0 {
return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "no files"})
}
sess := jwt_adapter.Get(ctx.Context())
if sess == nil {
return ctx.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "not authorized"})
}
var req PutFileReq
if ticket := form.Value["ticket"]; len(ticket) > 0 {
req.Ticket = ticket[0]
}
var (
fileIDs, filenames []string
errFile error
)
wg := new(sync.WaitGroup)
m := new(sync.Mutex)
wg.Add(filesCount)
for name, file := range files {
file := file
name := name
go func() {
defer wg.Done()
freader, err := file[0].Open()
if err != nil {
fmt.Println("can not open ", err.Error())
return
}
defer func() {
if err := freader.Close(); err != nil {
errFile = err
}
}()
splitted := strings.Split(name, ".")
filename := fmt.Sprintf("%s.%s", xid.New().String(), splitted[len(splitted)-1])
if err := o.bs.PutFile(ctx.Context(), filename, freader, file[0].Size); err != nil {
errFile = err
return
}
m.Lock()
defer m.Unlock()
fileIDs = append(fileIDs, filename)
filenames = append(filenames, name)
}()
}
wg.Wait()
if errFile != nil {
return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "can not store files: " + errFile.Error()})
}
message, err := o.dal.PutSCResponse(
ctx.Context(),
strings.Join(filenames, ", "),
sess.Id,
sess.Id,
req.Ticket,
fileIDs,
)
if err != nil {
for _, filename := range filenames {
if err := o.bs.DeleteFile(ctx.Context(), filename); err != nil {
fmt.Println("can not delete file:", err)
}
}
return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "can not store message: " + err.Error()})
}
return ctx.Status(fiber.StatusOK).JSON(PutFileResp{Message: message.ID})
}