package tickets import ( "context" "encoding/json" "errors" "fmt" "github.com/gofiber/fiber/v2" "github.com/themakers/hlog" "go.uber.org/zap" "gopkg.in/telebot.v3" our_errors "heruvym/internal/controllers/errors" "heruvym/internal/model" "heruvym/internal/repository/mongo" "heruvym/internal/tools" "heruvym/internal/utils/jwt_adapter" "heruvym/internal/utils/middleware" ) type Deps struct { Dal *mongo.DAL Notifier *telebot.Bot TgChatID int64 HLogger hlog.Logger ZapLogger *zap.Logger } type TicketController struct { dal *mongo.DAL notifier *telebot.Bot tgChatID int64 hLogger hlog.Logger zapLogger *zap.Logger } func NewTicketController(deps Deps) *TicketController { return &TicketController{ dal: deps.Dal, notifier: deps.Notifier, tgChatID: deps.TgChatID, hLogger: deps.HLogger, zapLogger: deps.ZapLogger, } } type CreateTicketReq struct { Title string `json:"Title"` Message string `json:"Message"` } type CreateTicketResp struct { Ticket string `json:"Ticket"` Sess string `json:"sess"` } func (t *TicketController) CreateTicket(ctx *fiber.Ctx) error { var ( err error request CreateTicketReq ) err = ctx.BodyParser(&request) if err != nil { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } if request.Title == "" { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "title is required"}) } if request.Message == "" { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "message is required"}) } session := jwt_adapter.Get(ctx.Context()) if session == nil { return ctx.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "unauthorized"}) } var ( ticketID string tickets []model.Ticket role = jwt_adapter.GetRole(ctx.Context()) ) if role == "" { tickets, _, err = t.dal.GetTickets4Sess(ctx.Context(), session.Id) } if err != nil || len(tickets) == 0 { ticketID, err = t.dal.CreateTicket( ctx.Context(), session.Id, session.Id, ctx.Get("Origin"), request.Title, request.Message, []string{}, ) if err != nil { return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } if _, err := t.dal.PutMessage(ctx.Context(), request.Message, session.Id, session.Id, ticketID, []string{}, false, // system error flag ); err != nil { return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } domain, ok := ctx.Context().Value(middleware.HostKey).(string) if !ok || domain == "" { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "domain is nil"}) } go func() { if session.Id != "" && role != "admin" { if err == nil && t.notifier != nil { var userLink, supportLink string if session.StandardClaims.Issuer != "" { if len(domain) > 0 && domain[0] == 's' { userLink = fmt.Sprintf("https://sadmin.pena/users/%s", session.Id) supportLink = fmt.Sprintf("https://sadmin.pena/support/%s", ticketID) } else { userLink = fmt.Sprintf("https://admin.pena/users/%s", session.Id) supportLink = fmt.Sprintf("https://admin.pena/support/%s", ticketID) } } else { if len(domain) > 0 && domain[0] == 's' { supportLink = fmt.Sprintf("https://sadmin.pena/support/%s", ticketID) } else { supportLink = fmt.Sprintf("https://admin.pena/support/%s", ticketID) } userLink = "незарегистрированного пользователя" } message := fmt.Sprintf("Вам пришло сообщение от %s сссылка на пользователя с %s, ccылка на чат - %s", userLink, domain, supportLink) if _, err := t.notifier.Send(telebot.ChatID(t.tgChatID), message); err != nil { fmt.Println("CAN NOT NOTIFY", err) } return } } }() } else { ticketID = tickets[0].ID } response, err := json.Marshal(CreateTicketResp{Ticket: ticketID, Sess: session.Id}) if err != nil { t.hLogger.Emit(our_errors.ErrorClose{ Err: err, }) return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return ctx.Status(fiber.StatusOK).JSON(response) } type ReqPutMessage struct { Message string `json:"message"` TicketID string `json:"ticket"` Files []string `json:"files"` Lang string `json:"lang"` System bool `json:"system"` } func (t *TicketController) PutMessage(ctx *fiber.Ctx) error { var request ReqPutMessage err := ctx.BodyParser(&request) if err != nil { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } sess := jwt_adapter.Get(ctx.Context()) request.Files = []string{} domain, ok := ctx.Context().Value(middleware.HostKey).(string) if !ok || domain == "" { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "domain is nil"}) } message, err := t.dal.PutMessage( ctx.Context(), request.Message, sess.Id, sess.Id, request.TicketID, []string{}, request.System, ) if err != nil { return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } role := jwt_adapter.GetRole(ctx.Context()) go func() { if sess.Id != "" && role != "admin" { if err == nil && t.notifier != nil { var userLink, supportLink string if sess.StandardClaims.Issuer != "" { if domain[0] == 's' { userLink = fmt.Sprintf("https://sadmin.pena/users/%s", sess.Id) supportLink = fmt.Sprintf("https://sadmin.pena/support/%s", request.TicketID) } else { userLink = fmt.Sprintf("https://admin.pena/users/%s", sess.Id) supportLink = fmt.Sprintf("https://admin.pena/support/%s", request.TicketID) } } else { if domain[0] == 's' { supportLink = fmt.Sprintf("https://sadmin.pena/support/%s", request.TicketID) } else { supportLink = fmt.Sprintf("https://admin.pena/support/%s", request.TicketID) } userLink = "незарегистрированного пользователя" } var message string if request.System { message = fmt.Sprintf("СИСТЕМНАЯ ОШИБКА! Произошла ошибка в сообщении от %s c %s. Ссылка на чат: %s", userLink, domain, supportLink) } else { message = fmt.Sprintf("Вам пришло сообщение от %s ссылка на пользователя с %s, ссылка на чат - %s", userLink, domain, supportLink) } if _, err := t.notifier.Send(telebot.ChatID(t.tgChatID), message); err != nil { t.zapLogger.Error("CAN NOT NOTIFY", zap.Error(err)) } return } } }() if err := t.dal.UpdateTopMessage(ctx.Context(), request.TicketID, message); err != nil { fmt.Println("PUTMES01", err, request.TicketID, message) return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) //return errors.New("can not update ticket"), http.StatusInternalServerError } return ctx.SendStatus(fiber.StatusOK) } type GetTicketsReq struct { Amount int64 `json:"amt"` Page int64 `json:"page"` Search string `json:"srch"` Status string `json:"status"` } type GetTicketsResp struct { Data []model.Ticket `json:"data"` Count int64 `json:"count"` } func (t *TicketController) GetTickets(ctx *fiber.Ctx) error { var request GetTicketsReq if err := ctx.BodyParser(&request); err != nil { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } role := jwt_adapter.GetRole(ctx.Context()) if role == "admin" { result, count, err := t.dal.GetTicketPage(ctx.Context(), request.Status, request.Search, request.Amount, request.Page, ) if err != nil { return ctx.Status(fiber.StatusNoContent).JSON(fiber.Map{"error": "No Content"}) } return ctx.Status(fiber.StatusOK).JSON(GetTicketsResp{ Data: *result, Count: count, }) } else { sess := jwt_adapter.Get(ctx.Context()) result, count, err := t.dal.YieldUserTickets(ctx.Context(), sess.Id, request.Amount, request.Page*request.Amount) if err != nil { return ctx.Status(fiber.StatusNoContent).JSON(fiber.Map{"error": "No Content"}) } return ctx.Status(fiber.StatusOK).JSON(GetTicketsResp{ Data: result, Count: count, }) } } type GetMessagesReq struct { Amount int64 `json:"amt"` Page int64 `json:"page"` Search string `json:"srch"` TicketID string `json:"ticket"` } // todo тут стоит фильтровать по system? func (t *TicketController) GetMessages(ctx *fiber.Ctx) error { var request GetMessagesReq if err := ctx.BodyParser(&request); err != nil { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } result, err := t.dal.GetMessagesPage(ctx.Context(), request.Search, request.TicketID, request.Amount, request.Page, ) if err != nil { return ctx.Status(fiber.StatusNoContent).JSON(fiber.Map{"error": "No Content"}) } return ctx.Status(fiber.StatusOK).JSON(result) } type PickReq struct { TicketID string `json:"ticket"` } func (t *TicketController) Pick(ctx *fiber.Ctx) error { var request PickReq if err := ctx.BodyParser(&request); err != nil { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } sess := jwt_adapter.Get(ctx.Context()) if err := t.dal.SetAnswerer(ctx.Context(), request.TicketID, sess.Id); err != nil { return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return ctx.SendStatus(fiber.StatusOK) } type DelegateReq struct { TicketID string `json:"ticket"` AnswererID string `json:"answerer"` } func (t *TicketController) Delegate(ctx *fiber.Ctx) error { var request DelegateReq if err := ctx.BodyParser(&request); err != nil { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } if err := t.dal.SetAnswerer(ctx.Context(), request.TicketID, request.AnswererID); err != nil { return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return ctx.SendStatus(fiber.StatusOK) } type VoteReq struct { TicketID string `json:"ticket"` Rate int `json:"rate"` } func (t *TicketController) Vote(ctx *fiber.Ctx) error { var request VoteReq if err := ctx.BodyParser(&request); err != nil { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } if err := t.dal.SetRate(ctx.Context(), request.TicketID, request.Rate); err != nil { return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return ctx.SendStatus(fiber.StatusOK) } type CloseTicketReq struct { TicketID string `json:"ticket"` } type CloseTicketResp struct { TicketID string `json:"ticket"` } func (t *TicketController) CloseTicket(ctx *fiber.Ctx) error { var request CloseTicketReq if err := ctx.BodyParser(&request); err != nil { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } if err := t.dal.SetTicketStatus(ctx.Context(), request.TicketID, model.StateClose); err != nil { return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } // system error flag if _, err := t.dal.PutMessage(ctx.Context(), "close", "close", "close", request.TicketID, []string{}, false); err != nil { return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return ctx.Status(fiber.StatusOK).JSON(CloseTicketResp{ TicketID: request.TicketID, }) } type ShownReq struct { ID string `json:"id"` } func (t *TicketController) SetShown(ctx *fiber.Ctx) error { var request ShownReq if err := ctx.BodyParser(&request); err != nil { return ctx.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": err.Error()}) } err := t.dal.SetShown(ctx.Context(), request.ID, "me") if err != nil { return ctx.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()}) } return ctx.SendStatus(fiber.StatusOK) } var _ tools.DataEmitter = (&TicketController{}).GetList func (t *TicketController) GetList(ctx context.Context) chan interface{} { fmt.Println("GetList") defer func() { if rec := recover(); rec != nil { fmt.Println(rec) } }() sess := jwt_adapter.Get(ctx) fmt.Println("sess", sess) if sess == nil { return nil } output := make(chan interface{}) if sess.Id == "" { go t.unauthorizedTickets(ctx, sess.Id, output) } else { role := jwt_adapter.GetRole(ctx) fmt.Println("ALL TICKETS Sess ", sess.Id, role) if role == "admin" || role == "manager" { go t.allTickets(ctx, output) } else { go t.userTickets(ctx, sess.Id, output) } } return output } func (t *TicketController) allTickets(ctx context.Context, output chan interface{}) { defer func() { if v := recover(); v != nil { fmt.Println("AllTicketsRec", v) } }() //data, count, err := h.dal.YieldTickets(ctx, 20) // //if err != nil { // output <- errors.New("cannot get tickets:" + err.Error()) // return //} // //if data != nil { // output <- GetTicketsResp{data, count} //} if err := t.dal.WatchAllTickets(ctx, func(ticket model.Ticket) error { output <- ticket return nil }); err != nil { output <- errors.New("cannot watch all tickets" + err.Error()) } } func (t *TicketController) userTickets(ctx context.Context, userID string, output chan interface{}) { defer func() { if v := recover(); v != nil { fmt.Println("USERTICKS", v) } }() data, count, err := t.dal.YieldUserTickets(ctx, userID, 20, 0) if err != nil { output <- errors.New("cannot get tickets:" + err.Error()) return } if data != nil { var filteredData []model.Ticket for _, ticket := range data { if !ticket.TopMessage.System { filteredData = append(filteredData, ticket) } } data = filteredData output <- GetTicketsResp{data, count} } if err := t.dal.WatchTickets(ctx, userID, func(ticket model.Ticket) error { if ticket.TopMessage.System { return nil } output <- ticket return nil }); err != nil { output <- errors.New("cannot watch tickets") return } } func (t *TicketController) unauthorizedTickets(ctx context.Context, sess string, output chan interface{}) { //defer close(output) tickets, count, err := t.dal.GetTickets4Sess(ctx, sess) if err != nil { output <- errors.New("no tickets for session") return } if tickets != nil { output <- GetTicketsResp{tickets, count} } } var _ tools.DataEmitter = (&TicketController{}).Subscribe func (t *TicketController) Subscribe(ctx context.Context) chan interface{} { sess := jwt_adapter.Get(ctx) fmt.Println("SESS Subsc", sess) ticketID := ctx.Value(tools.ContextURLKey).(string) output := make(chan interface{}) if sess.Id == "" { go func() { ticket, err := t.dal.GetTicket4Sess(ctx, ticketID, sess.Id) if err != nil || ticket == nil { output <- errors.New("no tickets 4 session") return } /*if err := h.dal.YieldMessages(ctx, ticketID, func(message model.Message) error { output <- message fmt.Println("OOOOOOLd") //if err := h.dal.SetShown(ctx, message.ID, sess.Session); err != nil { // // output <- errors.New("cannot show message " + err.Error()) // return err //} return nil }); err != nil { output <- errors.New("cannot read messages " + err.Error()) }*/ if err := t.dal.WatchMessages(ctx, ticketID, func(message model.Message) error { if !message.System { output <- message } //if err := h.dal.SetShown(ctx, message.ID, sess.Session); err != nil { // fmt.Println("3", err) // output <- errors.New("cannot show watch message " + err.Error()) // return err //} return nil }); err != nil { fmt.Println("4", err) output <- errors.New("cannot watch messages " + err.Error()) } }() } else { role := jwt_adapter.GetRole(ctx) if role == "admin" || role == "manager" { go func() { if err := t.dal.YieldMessages(ctx, ticketID, func(message model.Message) error { output <- message //if err := h.dal.SetShown(ctx, message.ID, sess.User); err != nil { // fmt.Println("2", err) // output <- errors.New("cannot show message " + err.Error()) // return err //} return nil }); err != nil { fmt.Println("1", err) output <- errors.New("cannot read messages " + err.Error()) } if err := t.dal.WatchMessages(ctx, ticketID, func(message model.Message) error { output <- message //if err := h.dal.SetShown(ctx, message.ID, sess.Session); err != nil { // fmt.Println("3", err) // output <- errors.New("cannot show watch message " + err.Error()) // return err //} return nil }); err != nil { fmt.Println("4", err) output <- errors.New("cannot watch messages " + err.Error()) } }() } else { go func() { defer func() { if v := recover(); v != nil { fmt.Println("heryvym panic", v) } }() ticket, err := t.dal.GetTicket4User(ctx, ticketID, sess.Id) if err != nil || ticket == nil { output <- errors.New("no tickets 4 user") } /*if err := h.dal.YieldMessages(ctx, ticketID, func(message model.Message) error { output <- message //if err := h.dal.SetShown(ctx, message.ID, sess.User); err != nil { // fmt.Println("2", err) // output <- errors.New("cannot show message " + err.Error()) // return err //} return nil }); err != nil { fmt.Println("1", err) output <- errors.New("cannot read messages " + err.Error()) }*/ if err := t.dal.WatchMessages(ctx, ticketID, func(message model.Message) error { if !message.System { output <- message } //if err := h.dal.SetShown(ctx, message.ID, sess.Session); err != nil { // fmt.Println("3", err) // output <- errors.New("cannot show watch message " + err.Error()) // return err //} return nil }); err != nil { fmt.Println("4", err) output <- errors.New("cannot watch messages " + err.Error()) } }() } } return output }