heruvym/internal/controllers/tickets/tickets.go
skeris 59e5b723ad
All checks were successful
Deploy / CreateImage (push) Successful in 1m19s
Deploy / DeployService (push) Successful in 34s
add tg token for staging
2025-02-23 02:41:42 +03:00

660 lines
18 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 tickets
import (
"context"
"errors"
"fmt"
"gitea.pena/PenaSide/heruvym/internal/model"
"gitea.pena/PenaSide/heruvym/internal/repository/mongo"
"gitea.pena/PenaSide/heruvym/internal/tools"
"gitea.pena/PenaSide/heruvym/internal/utils/jwt_adapter"
"gitea.pena/PenaSide/heruvym/internal/utils/middleware"
"gitea.pena/PenaSide/hlog"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
"gopkg.in/telebot.v3"
)
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"`
System bool `json:"System"`
}
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,
request.System,
[]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{},
request.System, // 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
}
return ctx.Status(fiber.StatusOK).JSON(CreateTicketResp{Ticket: ticketID, Sess: session.Id})
}
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"`
}
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()})
}
role := jwt_adapter.GetRole(ctx.Context())
result, err := t.dal.GetMessagesPage(ctx.Context(),
request.Search,
request.TicketID,
role,
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
}