Files
catalyst/app/service/service.go
2025-09-02 21:58:08 +02:00

1926 lines
57 KiB
Go

package service
import (
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
"time"
"github.com/SecurityBrewery/catalyst/app/auth"
"github.com/SecurityBrewery/catalyst/app/auth/password"
"github.com/SecurityBrewery/catalyst/app/database"
"github.com/SecurityBrewery/catalyst/app/database/sqlc"
"github.com/SecurityBrewery/catalyst/app/hook"
"github.com/SecurityBrewery/catalyst/app/openapi"
"github.com/SecurityBrewery/catalyst/app/pointer"
"github.com/SecurityBrewery/catalyst/app/reaction/schedule"
"github.com/SecurityBrewery/catalyst/app/settings"
"github.com/SecurityBrewery/catalyst/app/upload"
)
const (
defaultLimit = 100
defaultOffset = 0
)
var _ openapi.StrictServerInterface = (*Service)(nil)
type Service struct {
queries *sqlc.Queries
hooks *hook.Hooks
uploader *upload.Uploader
scheduler *schedule.Scheduler
}
func New(queries *sqlc.Queries, hooks *hook.Hooks, uploader *upload.Uploader, scheduler *schedule.Scheduler) *Service {
return &Service{
queries: queries,
hooks: hooks,
uploader: uploader,
scheduler: scheduler,
}
}
func (s *Service) ListComments(ctx context.Context, request openapi.ListCommentsRequestObject) (openapi.ListCommentsResponseObject, error) {
comments, err := s.queries.ListComments(ctx, sqlc.ListCommentsParams{
Ticket: toString(request.Params.Ticket, ""),
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.ExtendedComment, 0, len(comments))
for _, comment := range comments {
response = append(response, openapi.ExtendedComment{
Author: comment.Author,
Created: comment.Created,
Id: comment.ID,
Message: comment.Message,
Ticket: comment.Ticket,
Updated: comment.Updated,
AuthorName: pointer.Dereference(comment.AuthorName),
})
}
totalCount := 0
if len(comments) > 0 {
totalCount = int(comments[0].TotalCount)
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.CommentsTable.ID, response)
return openapi.ListComments200JSONResponse{
Body: response,
Headers: openapi.ListComments200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) CreateComment(ctx context.Context, request openapi.CreateCommentRequestObject) (openapi.CreateCommentResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.CommentsTable.ID, request.Body)
comment, err := s.queries.CreateComment(ctx, sqlc.CreateCommentParams{
Author: request.Body.Author,
Message: request.Body.Message,
Ticket: request.Body.Ticket,
})
if err != nil {
return nil, err
}
response := openapi.Comment{
Author: comment.Author,
Created: comment.Created,
Id: comment.ID,
Message: comment.Message,
Ticket: comment.Ticket,
Updated: comment.Updated,
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.CommentsTable.ID, response)
return openapi.CreateComment200JSONResponse(response), nil
}
func (s *Service) DeleteComment(ctx context.Context, request openapi.DeleteCommentRequestObject) (openapi.DeleteCommentResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.CommentsTable.ID, request.Id)
err := s.queries.DeleteComment(ctx, request.Id)
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.CommentsTable.ID, request.Id)
return openapi.DeleteComment204Response{}, nil
}
func (s *Service) GetComment(ctx context.Context, request openapi.GetCommentRequestObject) (openapi.GetCommentResponseObject, error) {
comment, err := s.queries.GetComment(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.ExtendedComment{
Author: comment.Author,
AuthorName: pointer.Dereference(comment.AuthorName),
Created: comment.Created,
Id: comment.ID,
Message: comment.Message,
Ticket: comment.Ticket,
Updated: comment.Updated,
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.CommentsTable.ID, response)
return openapi.GetComment200JSONResponse(response), nil
}
func (s *Service) UpdateComment(ctx context.Context, request openapi.UpdateCommentRequestObject) (openapi.UpdateCommentResponseObject, error) {
s.hooks.OnRecordBeforeUpdateRequest.Publish(ctx, database.CommentsTable.ID, request.Body)
comment, err := s.queries.UpdateComment(ctx, sqlc.UpdateCommentParams{
Message: request.Body.Message,
ID: request.Id,
})
if err != nil {
return nil, err
}
response := openapi.Comment{
Author: comment.Author,
Created: comment.Created,
Id: comment.ID,
Message: comment.Message,
Ticket: comment.Ticket,
Updated: comment.Updated,
}
s.hooks.OnRecordAfterUpdateRequest.Publish(ctx, database.CommentsTable.ID, response)
return openapi.UpdateComment200JSONResponse(response), nil
}
func (s *Service) GetDashboardCounts(ctx context.Context, _ openapi.GetDashboardCountsRequestObject) (openapi.GetDashboardCountsResponseObject, error) {
counts, err := s.queries.GetDashboardCounts(ctx)
if err != nil {
return nil, err
}
response := make([]openapi.DashboardCounts, 0, len(counts))
for _, count := range counts {
response = append(response, openapi.DashboardCounts{
Id: count.ID,
Count: int(count.Count),
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.DashboardCountsTable.ID, response)
return openapi.GetDashboardCounts200JSONResponse(response), nil
}
func (s *Service) ListFiles(ctx context.Context, request openapi.ListFilesRequestObject) (openapi.ListFilesResponseObject, error) {
files, err := s.queries.ListFiles(ctx, sqlc.ListFilesParams{
Ticket: toString(request.Params.Ticket, ""),
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.File, 0, len(files))
for _, file := range files {
response = append(response, openapi.File{
Created: file.Created,
Id: file.ID,
Name: file.Name,
Size: file.Size,
Ticket: file.Ticket,
Updated: file.Updated,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.FilesTable.ID, response)
totalCount := 0
if len(files) > 0 {
totalCount = int(files[0].TotalCount)
}
return openapi.ListFiles200JSONResponse{
Body: response,
Headers: openapi.ListFiles200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) CreateFile(ctx context.Context, request openapi.CreateFileRequestObject) (openapi.CreateFileResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.FilesTable.ID, request.Body)
id := database.GenerateID("b")
uniqName, err := s.uploader.CreateFile(id, request.Body.Name, []byte(request.Body.Blob))
if err != nil {
return nil, err
}
file, err := s.queries.InsertFile(ctx, sqlc.InsertFileParams{
ID: id,
Name: request.Body.Name,
Blob: uniqName,
Size: float64(len(request.Body.Blob)),
Ticket: request.Body.Ticket,
Created: time.Now().UTC(),
Updated: time.Now().UTC(),
})
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.FilesTable.ID, file)
return openapi.CreateFile200JSONResponse(openapi.File{
Created: file.Created,
Id: file.ID,
Name: file.Name,
Size: file.Size,
Ticket: file.Ticket,
Updated: file.Updated,
}), nil
}
func (s *Service) DeleteFile(ctx context.Context, request openapi.DeleteFileRequestObject) (openapi.DeleteFileResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.FilesTable.ID, request.Id)
f, err := s.queries.GetFile(ctx, request.Id)
if err != nil {
return nil, err
}
if err := s.uploader.DeleteFile(f.ID, f.Blob); err != nil {
return nil, fmt.Errorf("failed to delete file from uploader: %w", err)
}
if err := s.queries.DeleteFile(ctx, request.Id); err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.FilesTable.ID, request.Id)
return openapi.DeleteFile204Response{}, nil
}
func (s *Service) GetFile(ctx context.Context, request openapi.GetFileRequestObject) (openapi.GetFileResponseObject, error) {
file, err := s.queries.GetFile(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.File{
Created: file.Created,
Id: file.ID,
Name: file.Name,
Size: file.Size,
Ticket: file.Ticket,
Updated: file.Updated,
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.FilesTable.ID, response)
return openapi.GetFile200JSONResponse(response), nil
}
func (s *Service) ListLinks(ctx context.Context, request openapi.ListLinksRequestObject) (openapi.ListLinksResponseObject, error) {
links, err := s.queries.ListLinks(ctx, sqlc.ListLinksParams{
Ticket: toString(request.Params.Ticket, ""),
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.Link, 0, len(links))
for _, link := range links {
response = append(response, openapi.Link{
Id: link.ID,
Name: link.Name,
Created: link.Created,
Updated: link.Updated,
Url: link.Url,
Ticket: link.Ticket,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.LinksTable.ID, response)
totalCount := 0
if len(links) > 0 {
totalCount = int(links[0].TotalCount)
}
return openapi.ListLinks200JSONResponse{
Body: response,
Headers: openapi.ListLinks200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) DownloadFile(ctx context.Context, request openapi.DownloadFileRequestObject) (openapi.DownloadFileResponseObject, error) {
file, err := s.queries.GetFile(ctx, request.Id)
if err != nil {
return nil, err
}
f, contentType, size, err := s.uploader.File(file.ID, file.Blob)
if err != nil {
return nil, fmt.Errorf("failed to get file from uploader: %w", err)
}
return openapi.DownloadFile200ApplicationoctetStreamResponse{
Body: f,
ContentLength: size,
Headers: openapi.DownloadFile200ResponseHeaders{
ContentDisposition: "attachment; filename=\"" + file.Name + "\"",
ContentType: contentType,
},
}, nil
}
func (s *Service) CreateLink(ctx context.Context, request openapi.CreateLinkRequestObject) (openapi.CreateLinkResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.LinksTable.ID, request.Body)
link, err := s.queries.CreateLink(ctx, sqlc.CreateLinkParams{
Name: request.Body.Name,
Url: request.Body.Url,
Ticket: request.Body.Ticket,
})
if err != nil {
return nil, err
}
response := openapi.Link{
Created: link.Created,
Id: link.ID,
Name: link.Name,
Ticket: link.Ticket,
Updated: link.Updated,
Url: link.Url,
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.LinksTable.ID, response)
return openapi.CreateLink200JSONResponse(response), nil
}
func (s *Service) DeleteLink(ctx context.Context, request openapi.DeleteLinkRequestObject) (openapi.DeleteLinkResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.LinksTable.ID, request.Id)
err := s.queries.DeleteLink(ctx, request.Id)
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.LinksTable.ID, request.Id)
return openapi.DeleteLink204Response{}, nil
}
func (s *Service) GetLink(ctx context.Context, request openapi.GetLinkRequestObject) (openapi.GetLinkResponseObject, error) {
link, err := s.queries.GetLink(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.Link{
Id: link.ID,
Name: link.Name,
Created: link.Created,
Updated: link.Updated,
Url: link.Url,
Ticket: link.Ticket,
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.LinksTable.ID, response)
return openapi.GetLink200JSONResponse(response), nil
}
func (s *Service) UpdateLink(ctx context.Context, request openapi.UpdateLinkRequestObject) (openapi.UpdateLinkResponseObject, error) {
s.hooks.OnRecordBeforeUpdateRequest.Publish(ctx, database.LinksTable.ID, request.Body)
link, err := s.queries.UpdateLink(ctx, sqlc.UpdateLinkParams{
ID: request.Id,
Name: request.Body.Name,
Url: request.Body.Url,
})
if err != nil {
return nil, err
}
response := openapi.Link{
Created: link.Created,
Id: link.ID,
Name: link.Name,
Ticket: link.Ticket,
Updated: link.Updated,
Url: link.Url,
}
s.hooks.OnRecordAfterUpdateRequest.Publish(ctx, database.LinksTable.ID, response)
return openapi.UpdateLink200JSONResponse(response), nil
}
func (s *Service) ListReactions(ctx context.Context, request openapi.ListReactionsRequestObject) (openapi.ListReactionsResponseObject, error) {
reactions, err := s.queries.ListReactions(ctx, sqlc.ListReactionsParams{
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.Reaction, 0, len(reactions))
for _, reaction := range reactions {
response = append(response, openapi.Reaction{
Action: reaction.Action,
Actiondata: unmarshal(reaction.Actiondata),
Created: reaction.Created,
Id: reaction.ID,
Name: reaction.Name,
Trigger: reaction.Trigger,
Triggerdata: unmarshal(reaction.Triggerdata),
Updated: reaction.Updated,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.ReactionsTable.ID, response)
totalCount := 0
if len(reactions) > 0 {
totalCount = int(reactions[0].TotalCount)
}
return openapi.ListReactions200JSONResponse{
Body: response,
Headers: openapi.ListReactions200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) CreateReaction(ctx context.Context, request openapi.CreateReactionRequestObject) (openapi.CreateReactionResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.ReactionsTable.ID, request.Body)
reaction, err := s.queries.CreateReaction(ctx, sqlc.CreateReactionParams{
Name: request.Body.Name,
Action: request.Body.Action,
Trigger: request.Body.Trigger,
Actiondata: marshal(request.Body.Actiondata),
Triggerdata: marshal(request.Body.Triggerdata),
})
if err != nil {
return nil, err
}
if err := s.scheduler.AddReaction(&reaction); err != nil {
slog.ErrorContext(ctx, "Failed to add reaction to scheduler", "error", err)
}
response := openapi.Reaction{
Action: reaction.Action,
Actiondata: unmarshal(reaction.Actiondata),
Created: reaction.Created,
Id: reaction.ID,
Name: reaction.Name,
Trigger: reaction.Trigger,
Triggerdata: unmarshal(reaction.Triggerdata),
Updated: reaction.Updated,
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.ReactionsTable.ID, response)
return openapi.CreateReaction200JSONResponse(response), nil
}
func (s *Service) DeleteReaction(ctx context.Context, request openapi.DeleteReactionRequestObject) (openapi.DeleteReactionResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.ReactionsTable.ID, request.Id)
err := s.queries.DeleteReaction(ctx, request.Id)
if err != nil {
return nil, err
}
s.scheduler.RemoveReaction(request.Id)
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.ReactionsTable.ID, request.Id)
return openapi.DeleteReaction204Response{}, nil
}
func (s *Service) GetReaction(ctx context.Context, request openapi.GetReactionRequestObject) (openapi.GetReactionResponseObject, error) {
reaction, err := s.queries.GetReaction(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.Reaction{
Action: reaction.Action,
Actiondata: unmarshal(reaction.Actiondata),
Created: reaction.Created,
Id: reaction.ID,
Name: reaction.Name,
Trigger: reaction.Trigger,
Triggerdata: unmarshal(reaction.Triggerdata),
Updated: reaction.Updated,
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.ReactionsTable.ID, response)
return openapi.GetReaction200JSONResponse(response), nil
}
func (s *Service) UpdateReaction(ctx context.Context, request openapi.UpdateReactionRequestObject) (openapi.UpdateReactionResponseObject, error) {
s.hooks.OnRecordBeforeUpdateRequest.Publish(ctx, database.ReactionsTable.ID, request.Body)
reaction, err := s.queries.UpdateReaction(ctx, sqlc.UpdateReactionParams{
ID: request.Id,
Name: request.Body.Name,
Action: request.Body.Action,
Trigger: request.Body.Trigger,
Actiondata: marshalPointer(request.Body.Actiondata),
Triggerdata: marshalPointer(request.Body.Triggerdata),
})
if err != nil {
return nil, err
}
s.scheduler.RemoveReaction(request.Id)
if err := s.scheduler.AddReaction(&reaction); err != nil {
slog.ErrorContext(ctx, "Failed to add reaction to scheduler", "error", err)
}
response := openapi.Reaction{
Action: reaction.Action,
Actiondata: unmarshal(reaction.Actiondata),
Created: reaction.Created,
Id: reaction.ID,
Name: reaction.Name,
Trigger: reaction.Trigger,
Triggerdata: unmarshal(reaction.Triggerdata),
Updated: reaction.Updated,
}
s.hooks.OnRecordAfterUpdateRequest.Publish(ctx, database.ReactionsTable.ID, response)
return openapi.UpdateReaction200JSONResponse(response), nil
}
func (s *Service) GetSidebar(ctx context.Context, _ openapi.GetSidebarRequestObject) (openapi.GetSidebarResponseObject, error) {
sidebar, err := s.queries.GetSidebar(ctx)
if err != nil {
return nil, err
}
response := make([]openapi.Sidebar, 0, len(sidebar))
for _, s := range sidebar {
response = append(response, openapi.Sidebar{
Id: s.ID,
Singular: s.Singular,
Plural: s.Plural,
Icon: s.Icon,
Count: int(s.Count),
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.SidebarTable.ID, response)
return openapi.GetSidebar200JSONResponse(response), nil
}
func (s *Service) ListTasks(ctx context.Context, request openapi.ListTasksRequestObject) (openapi.ListTasksResponseObject, error) {
tasks, err := s.queries.ListTasks(ctx, sqlc.ListTasksParams{
Ticket: toString(request.Params.Ticket, ""),
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.ExtendedTask, 0, len(tasks))
for _, task := range tasks {
response = append(response, openapi.ExtendedTask{
Id: task.ID,
Name: task.Name,
Created: task.Created,
Updated: task.Updated,
Open: task.Open,
Owner: task.Owner,
Ticket: task.Ticket,
OwnerName: task.OwnerName,
TicketName: pointer.Dereference(task.TicketName),
TicketType: pointer.Dereference(task.TicketType),
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.TasksTable.ID, response)
totalCount := 0
if len(tasks) > 0 {
totalCount = int(tasks[0].TotalCount)
}
return openapi.ListTasks200JSONResponse{
Body: response,
Headers: openapi.ListTasks200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) CreateTask(ctx context.Context, request openapi.CreateTaskRequestObject) (openapi.CreateTaskResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.TasksTable.ID, request.Body)
task, err := s.queries.CreateTask(ctx, sqlc.CreateTaskParams{
Name: request.Body.Name,
Open: request.Body.Open,
Owner: request.Body.Owner,
Ticket: request.Body.Ticket,
})
if err != nil {
return nil, err
}
response := openapi.Task{
Created: task.Created,
Id: task.ID,
Name: task.Name,
Open: task.Open,
Owner: task.Owner,
Ticket: task.Ticket,
Updated: task.Updated,
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.TasksTable.ID, response)
return openapi.CreateTask200JSONResponse(response), nil
}
func (s *Service) DeleteTask(ctx context.Context, request openapi.DeleteTaskRequestObject) (openapi.DeleteTaskResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.TasksTable.ID, request.Id)
err := s.queries.DeleteTask(ctx, request.Id)
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.TasksTable.ID, request.Id)
return openapi.DeleteTask204Response{}, nil
}
func (s *Service) GetTask(ctx context.Context, request openapi.GetTaskRequestObject) (openapi.GetTaskResponseObject, error) {
task, err := s.queries.GetTask(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.ExtendedTask{
Id: task.ID,
Name: task.Name,
Created: task.Created,
Updated: task.Updated,
Open: task.Open,
Owner: task.Owner,
Ticket: task.Ticket,
OwnerName: task.OwnerName,
TicketName: pointer.Dereference(task.TicketName),
TicketType: pointer.Dereference(task.TicketType),
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.TasksTable.ID, response)
return openapi.GetTask200JSONResponse(response), nil
}
func (s *Service) UpdateTask(ctx context.Context, request openapi.UpdateTaskRequestObject) (openapi.UpdateTaskResponseObject, error) {
s.hooks.OnRecordBeforeUpdateRequest.Publish(ctx, database.TasksTable.ID, request.Body)
task, err := s.queries.UpdateTask(ctx, sqlc.UpdateTaskParams{
ID: request.Id,
Name: request.Body.Name,
Open: request.Body.Open,
Owner: request.Body.Owner,
})
if err != nil {
return nil, err
}
response := openapi.Task{
Created: task.Created,
Id: task.ID,
Name: task.Name,
Open: task.Open,
Owner: task.Owner,
Ticket: task.Ticket,
Updated: task.Updated,
}
s.hooks.OnRecordAfterUpdateRequest.Publish(ctx, database.TasksTable.ID, response)
return openapi.UpdateTask200JSONResponse(response), nil
}
func (s *Service) SearchTickets(ctx context.Context, request openapi.SearchTicketsRequestObject) (openapi.SearchTicketsResponseObject, error) {
tickets, err := s.queries.SearchTickets(ctx, sqlc.SearchTicketsParams{
Query: request.Params.Query,
Type: request.Params.Type,
Open: request.Params.Open,
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.TicketSearch, 0, len(tickets))
for _, ticket := range tickets {
response = append(response, openapi.TicketSearch{
Created: ticket.Created,
Description: ticket.Description,
Id: ticket.ID,
Name: ticket.Name,
Open: ticket.Open,
OwnerName: pointer.Dereference(ticket.OwnerName),
State: unmarshal(ticket.State),
Type: ticket.Type,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.TicketsTable.ID, response)
totalCount := 0
if len(tickets) > 0 {
totalCount = int(tickets[0].TotalCount)
}
return openapi.SearchTickets200JSONResponse{
Body: response,
Headers: openapi.SearchTickets200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) ListTickets(ctx context.Context, request openapi.ListTicketsRequestObject) (openapi.ListTicketsResponseObject, error) {
tickets, err := s.queries.ListTickets(ctx, sqlc.ListTicketsParams{
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.ExtendedTicket, 0, len(tickets))
for _, ticket := range tickets {
response = append(response, openapi.ExtendedTicket{
Created: ticket.Created,
Description: ticket.Description,
Id: ticket.ID,
Name: ticket.Name,
Open: ticket.Open,
Owner: ticket.Owner,
OwnerName: ticket.OwnerName,
Resolution: ticket.Resolution,
Type: ticket.Type,
Schema: unmarshal(ticket.Schema),
State: unmarshal(ticket.State),
TypePlural: pointer.Dereference(ticket.TypePlural),
TypeSingular: pointer.Dereference(ticket.TypeSingular),
Updated: ticket.Updated,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, "tickets", response)
totalCount := 0
if len(tickets) > 0 {
totalCount = int(tickets[0].TotalCount)
}
return openapi.ListTickets200JSONResponse{
Body: response,
Headers: openapi.ListTickets200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) CreateTicket(ctx context.Context, request openapi.CreateTicketRequestObject) (openapi.CreateTicketResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.TicketsTable.ID, request.Body)
ticket, err := s.queries.CreateTicket(ctx, sqlc.CreateTicketParams{
Name: request.Body.Name,
Description: request.Body.Description,
Owner: request.Body.Owner,
Open: request.Body.Open,
Resolution: request.Body.Resolution,
Type: request.Body.Type,
State: marshal(request.Body.State),
})
if err != nil {
return nil, err
}
response := openapi.Ticket{
Created: ticket.Created,
Description: ticket.Description,
Id: ticket.ID,
Name: ticket.Name,
Open: ticket.Open,
Owner: ticket.Owner,
Resolution: ticket.Resolution,
Schema: unmarshal(ticket.Schema),
State: unmarshal(ticket.State),
Type: ticket.Type,
Updated: ticket.Updated,
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.TicketsTable.ID, response)
return openapi.CreateTicket200JSONResponse(response), nil
}
func (s *Service) DeleteTicket(ctx context.Context, request openapi.DeleteTicketRequestObject) (openapi.DeleteTicketResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.TicketsTable.ID, request.Id)
err := s.queries.DeleteTicket(ctx, request.Id)
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.TicketsTable.ID, request.Id)
return openapi.DeleteTicket204Response{}, nil
}
func (s *Service) GetTicket(ctx context.Context, request openapi.GetTicketRequestObject) (openapi.GetTicketResponseObject, error) {
ticket, err := s.queries.Ticket(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.ExtendedTicket{
Created: ticket.Created,
Description: ticket.Description,
Id: ticket.ID,
Name: ticket.Name,
Open: ticket.Open,
Owner: ticket.Owner,
OwnerName: ticket.OwnerName,
Resolution: ticket.Resolution,
Schema: unmarshal(ticket.Schema),
State: unmarshal(ticket.State),
Type: ticket.Type,
TypePlural: pointer.Dereference(ticket.TypePlural),
TypeSingular: pointer.Dereference(ticket.TypeSingular),
Updated: ticket.Updated,
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.TicketsTable.ID, response)
return openapi.GetTicket200JSONResponse(response), nil
}
func (s *Service) UpdateTicket(ctx context.Context, request openapi.UpdateTicketRequestObject) (openapi.UpdateTicketResponseObject, error) {
s.hooks.OnRecordBeforeUpdateRequest.Publish(ctx, database.TicketsTable.ID, request.Body)
ticket, err := s.queries.UpdateTicket(ctx, sqlc.UpdateTicketParams{
Name: request.Body.Name,
Description: request.Body.Description,
Open: request.Body.Open,
Owner: request.Body.Owner,
Resolution: request.Body.Resolution,
Schema: marshalPointer(request.Body.Schema),
State: marshalPointer(request.Body.State),
Type: request.Body.Type,
ID: request.Id,
})
if err != nil {
return nil, err
}
response := openapi.Ticket{
Created: ticket.Created,
Description: ticket.Description,
Id: ticket.ID,
Name: ticket.Name,
Open: ticket.Open,
Owner: ticket.Owner,
Resolution: ticket.Resolution,
Schema: unmarshal(ticket.Schema),
State: unmarshal(ticket.State),
Type: ticket.Type,
Updated: ticket.Updated,
}
s.hooks.OnRecordAfterUpdateRequest.Publish(ctx, database.TicketsTable.ID, response)
return openapi.UpdateTicket200JSONResponse(response), nil
}
func (s *Service) ListTimeline(ctx context.Context, request openapi.ListTimelineRequestObject) (openapi.ListTimelineResponseObject, error) {
timeline, err := s.queries.ListTimeline(ctx, sqlc.ListTimelineParams{
Ticket: toString(request.Params.Ticket, ""),
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.TimelineEntry, 0, len(timeline))
for _, timeline := range timeline {
response = append(response, openapi.TimelineEntry{
Id: timeline.ID,
Message: timeline.Message,
Created: timeline.Created,
Updated: timeline.Updated,
Time: timeline.Time,
Ticket: timeline.Ticket,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.TimelinesTable.ID, response)
totalCount := 0
if len(timeline) > 0 {
totalCount = int(timeline[0].TotalCount)
}
return openapi.ListTimeline200JSONResponse{
Body: response,
Headers: openapi.ListTimeline200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) CreateTimeline(ctx context.Context, request openapi.CreateTimelineRequestObject) (openapi.CreateTimelineResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.TimelinesTable.ID, request.Body)
timeline, err := s.queries.CreateTimeline(ctx, sqlc.CreateTimelineParams{
Message: request.Body.Message,
Time: request.Body.Time,
Ticket: request.Body.Ticket,
})
if err != nil {
return nil, err
}
response := openapi.TimelineEntry{
Created: timeline.Created,
Id: timeline.ID,
Message: timeline.Message,
Ticket: timeline.Ticket,
Time: timeline.Time,
Updated: timeline.Updated,
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.TimelinesTable.ID, response)
return openapi.CreateTimeline200JSONResponse(response), nil
}
func (s *Service) DeleteTimeline(ctx context.Context, request openapi.DeleteTimelineRequestObject) (openapi.DeleteTimelineResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.TimelinesTable.ID, request.Id)
err := s.queries.DeleteTimeline(ctx, request.Id)
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.TimelinesTable.ID, request.Id)
return openapi.DeleteTimeline204Response{}, nil
}
func (s *Service) GetTimeline(ctx context.Context, request openapi.GetTimelineRequestObject) (openapi.GetTimelineResponseObject, error) {
timeline, err := s.queries.GetTimeline(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.TimelineEntry{
Id: timeline.ID,
Message: timeline.Message,
Created: timeline.Created,
Updated: timeline.Updated,
Time: timeline.Time,
Ticket: timeline.Ticket,
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.TimelinesTable.ID, response)
return openapi.GetTimeline200JSONResponse(response), nil
}
func (s *Service) UpdateTimeline(ctx context.Context, request openapi.UpdateTimelineRequestObject) (openapi.UpdateTimelineResponseObject, error) {
s.hooks.OnRecordBeforeUpdateRequest.Publish(ctx, database.TimelinesTable.ID, request.Body)
timeline, err := s.queries.UpdateTimeline(ctx, sqlc.UpdateTimelineParams{
ID: request.Id,
Message: request.Body.Message,
Time: request.Body.Time,
})
if err != nil {
return nil, err
}
response := openapi.TimelineEntry{
Created: timeline.Created,
Id: timeline.ID,
Message: timeline.Message,
Ticket: timeline.Ticket,
Time: timeline.Time,
Updated: timeline.Updated,
}
s.hooks.OnRecordAfterUpdateRequest.Publish(ctx, database.TimelinesTable.ID, response)
return openapi.UpdateTimeline200JSONResponse(response), nil
}
func (s *Service) ListTypes(ctx context.Context, request openapi.ListTypesRequestObject) (openapi.ListTypesResponseObject, error) {
types, err := s.queries.ListTypes(ctx, sqlc.ListTypesParams{
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.Type, 0, len(types))
for _, t := range types {
response = append(response, openapi.Type{
Created: t.Created,
Icon: t.Icon,
Id: t.ID,
Plural: t.Plural,
Schema: unmarshal(t.Schema),
Singular: t.Singular,
Updated: t.Updated,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.TypesTable.ID, response)
totalCount := 0
if len(types) > 0 {
totalCount = int(types[0].TotalCount)
}
return openapi.ListTypes200JSONResponse{
Body: response,
Headers: openapi.ListTypes200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) CreateType(ctx context.Context, request openapi.CreateTypeRequestObject) (openapi.CreateTypeResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.TypesTable.ID, request.Body)
t, err := s.queries.CreateType(ctx, sqlc.CreateTypeParams{
Icon: request.Body.Icon,
Plural: request.Body.Plural,
Singular: request.Body.Singular,
Schema: marshal(request.Body.Schema),
})
if err != nil {
return nil, err
}
response := openapi.Type{
Created: t.Created,
Icon: t.Icon,
Id: t.ID,
Plural: t.Plural,
Schema: unmarshal(t.Schema),
Singular: t.Singular,
Updated: t.Updated,
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.TypesTable.ID, response)
return openapi.CreateType200JSONResponse(response), nil
}
func (s *Service) DeleteType(ctx context.Context, request openapi.DeleteTypeRequestObject) (openapi.DeleteTypeResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.TypesTable.ID, request.Id)
if err := s.queries.DeleteType(ctx, request.Id); err != nil {
return nil, fmt.Errorf("failed to delete type: %w", err)
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.TypesTable.ID, request.Id)
return openapi.DeleteType204Response{}, nil
}
func (s *Service) GetType(ctx context.Context, request openapi.GetTypeRequestObject) (openapi.GetTypeResponseObject, error) {
t, err := s.queries.GetType(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.Type{
Created: t.Created,
Icon: t.Icon,
Id: t.ID,
Plural: t.Plural,
Schema: unmarshal(t.Schema),
Singular: t.Singular,
Updated: t.Updated,
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.TypesTable.ID, response)
return openapi.GetType200JSONResponse(response), nil
}
func (s *Service) UpdateType(ctx context.Context, request openapi.UpdateTypeRequestObject) (openapi.UpdateTypeResponseObject, error) {
s.hooks.OnRecordBeforeUpdateRequest.Publish(ctx, database.TypesTable.ID, request.Body)
t, err := s.queries.UpdateType(ctx, sqlc.UpdateTypeParams{
ID: request.Id,
Icon: request.Body.Icon,
Plural: request.Body.Plural,
Singular: request.Body.Singular,
Schema: marshalPointer(request.Body.Schema),
})
if err != nil {
return nil, err
}
response := openapi.Type{
Created: t.Created,
Icon: t.Icon,
Id: t.ID,
Plural: t.Plural,
Schema: unmarshal(t.Schema),
Singular: t.Singular,
Updated: t.Updated,
}
s.hooks.OnRecordAfterUpdateRequest.Publish(ctx, database.TypesTable.ID, response)
return openapi.UpdateType200JSONResponse(response), nil
}
func (s *Service) ListUsers(ctx context.Context, request openapi.ListUsersRequestObject) (openapi.ListUsersResponseObject, error) {
users, err := s.queries.ListUsers(ctx, sqlc.ListUsersParams{
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.User, 0, len(users))
for _, user := range users {
response = append(response, openapi.User{
Avatar: user.Avatar,
Created: user.Created,
Email: user.Email,
Id: user.ID,
LastResetSentAt: user.Lastresetsentat,
LastVerificationSentAt: user.Lastverificationsentat,
Name: user.Name,
Updated: user.Updated,
Username: user.Username,
Active: user.Active,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.UsersTable.ID, response)
totalCount := 0
if len(users) > 0 {
totalCount = int(users[0].TotalCount)
}
return openapi.ListUsers200JSONResponse{
Body: response,
Headers: openapi.ListUsers200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) CreateUser(ctx context.Context, request openapi.CreateUserRequestObject) (openapi.CreateUserResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.UsersTable.ID, request.Body)
tokenKey, err := password.GenerateTokenKey()
if err != nil {
return nil, fmt.Errorf("failed to generate token key: %w", err)
}
user, err := s.queries.CreateUser(ctx, sqlc.CreateUserParams{
Name: request.Body.Name,
Email: request.Body.Email,
Username: request.Body.Username,
PasswordHash: "",
TokenKey: tokenKey,
Avatar: request.Body.Avatar,
Active: request.Body.Active,
})
if err != nil {
return nil, err
}
response := openapi.User{
Avatar: user.Avatar,
Created: user.Created,
Email: user.Email,
Id: user.ID,
LastResetSentAt: user.Lastresetsentat,
LastVerificationSentAt: user.Lastverificationsentat,
Name: user.Name,
Updated: user.Updated,
Username: user.Username,
Active: user.Active,
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.UsersTable.ID, response)
return openapi.CreateUser200JSONResponse(response), nil
}
func (s *Service) DeleteUser(ctx context.Context, request openapi.DeleteUserRequestObject) (openapi.DeleteUserResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.UsersTable.ID, request.Id)
err := s.queries.DeleteUser(ctx, request.Id)
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.UsersTable.ID, request.Id)
return openapi.DeleteUser204Response{}, nil
}
func (s *Service) GetUser(ctx context.Context, request openapi.GetUserRequestObject) (openapi.GetUserResponseObject, error) {
user, err := s.queries.GetUser(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.User{
Avatar: user.Avatar,
Created: user.Created,
Email: user.Email,
Id: user.ID,
LastResetSentAt: user.Lastresetsentat,
LastVerificationSentAt: user.Lastverificationsentat,
Name: user.Name,
Updated: user.Updated,
Username: user.Username,
Active: user.Active,
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.UsersTable.ID, response)
return openapi.GetUser200JSONResponse(response), nil
}
func (s *Service) UpdateUser(ctx context.Context, request openapi.UpdateUserRequestObject) (openapi.UpdateUserResponseObject, error) {
s.hooks.OnRecordBeforeUpdateRequest.Publish(ctx, database.UsersTable.ID, request.Body)
var passwordHash, tokenHash *string
switch {
case request.Body.Password == nil && request.Body.PasswordConfirm == nil:
case request.Body.Password != nil && request.Body.PasswordConfirm != nil:
if *request.Body.Password != *request.Body.PasswordConfirm {
return nil, errors.New("passwords do not match")
}
passwordHashS, tokenHashS, err := password.Hash(*request.Body.Password)
if err != nil {
return nil, fmt.Errorf("failed to hash password: %w", err)
}
passwordHash = &passwordHashS
tokenHash = &tokenHashS
default:
return nil, errors.New("password and password confirm must be provided together")
}
user, err := s.queries.UpdateUser(ctx, sqlc.UpdateUserParams{
Name: request.Body.Name,
Email: request.Body.Email,
Username: request.Body.Username,
PasswordHash: passwordHash,
TokenKey: tokenHash,
Avatar: request.Body.Avatar,
Active: request.Body.Active,
ID: request.Id,
})
if err != nil {
return nil, err
}
response := openapi.User{
Avatar: user.Avatar,
Created: user.Created,
Email: user.Email,
Id: user.ID,
LastResetSentAt: user.Lastresetsentat,
LastVerificationSentAt: user.Lastverificationsentat,
Name: user.Name,
Updated: user.Updated,
Username: user.Username,
Active: user.Active,
}
s.hooks.OnRecordAfterUpdateRequest.Publish(ctx, "users", response)
return openapi.UpdateUser200JSONResponse(response), nil
}
func (s *Service) ListGroups(ctx context.Context, request openapi.ListGroupsRequestObject) (openapi.ListGroupsResponseObject, error) {
groups, err := s.queries.ListGroups(ctx, sqlc.ListGroupsParams{
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.Group, 0, len(groups))
for _, group := range groups {
response = append(response, openapi.Group{
Created: group.Created,
Id: group.ID,
Name: group.Name,
Permissions: auth.FromJSONArray(ctx, group.Permissions),
Updated: group.Updated,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.GroupsTable.ID, response)
totalCount := 0
if len(groups) > 0 {
totalCount = int(groups[0].TotalCount)
}
return openapi.ListGroups200JSONResponse{
Body: response,
Headers: openapi.ListGroups200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) CreateGroup(ctx context.Context, request openapi.CreateGroupRequestObject) (openapi.CreateGroupResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.GroupsTable.ID, request.Body)
group, err := s.queries.CreateGroup(ctx, sqlc.CreateGroupParams{
Name: request.Body.Name,
Permissions: auth.ToJSONArray(ctx, request.Body.Permissions),
})
if err != nil {
return nil, err
}
response := openapi.Group{
Created: group.Created,
Id: group.ID,
Name: group.Name,
Permissions: auth.FromJSONArray(ctx, group.Permissions),
Updated: group.Updated,
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.GroupsTable.ID, response)
return openapi.CreateGroup200JSONResponse(response), nil
}
func (s *Service) DeleteGroup(ctx context.Context, request openapi.DeleteGroupRequestObject) (openapi.DeleteGroupResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.GroupsTable.ID, request.Id)
if request.Id == "admin" {
return nil, errors.New("cannot delete the admin group")
}
err := s.queries.DeleteGroup(ctx, request.Id)
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.GroupsTable.ID, request.Id)
return openapi.DeleteGroup204Response{}, nil
}
func (s *Service) GetGroup(ctx context.Context, request openapi.GetGroupRequestObject) (openapi.GetGroupResponseObject, error) {
group, err := s.queries.GetGroup(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.Group{
Created: group.Created,
Id: group.ID,
Name: group.Name,
Permissions: auth.FromJSONArray(ctx, group.Permissions),
Updated: group.Updated,
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.GroupsTable.ID, response)
return openapi.GetGroup200JSONResponse(response), nil
}
func (s *Service) UpdateGroup(ctx context.Context, request openapi.UpdateGroupRequestObject) (openapi.UpdateGroupResponseObject, error) {
s.hooks.OnRecordBeforeUpdateRequest.Publish(ctx, database.GroupsTable.ID, request.Body)
if request.Id == "admin" {
return nil, errors.New("cannot update the admin group")
}
var permissions *string
if request.Body.Permissions != nil {
p := auth.ToJSONArray(ctx, *request.Body.Permissions)
permissions = &p
}
group, err := s.queries.UpdateGroup(ctx, sqlc.UpdateGroupParams{
Name: request.Body.Name,
Permissions: permissions,
ID: request.Id,
})
if err != nil {
return nil, err
}
response := openapi.Group{
Created: group.Created,
Id: group.ID,
Name: group.Name,
Permissions: auth.FromJSONArray(ctx, group.Permissions),
Updated: group.Updated,
}
s.hooks.OnRecordAfterUpdateRequest.Publish(ctx, database.GroupsTable.ID, response)
return openapi.UpdateGroup200JSONResponse(response), nil
}
func (s *Service) AddGroupParent(ctx context.Context, request openapi.AddGroupParentRequestObject) (openapi.AddGroupParentResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.GroupParentTable.ID, request.Body)
err := s.queries.AssignParentGroup(ctx, sqlc.AssignParentGroupParams{
ChildGroupID: request.Id,
ParentGroupID: request.Body.GroupId,
})
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.GroupParentTable.ID, request.Body)
return openapi.AddGroupParent201Response{}, nil
}
func (s *Service) RemoveGroupParent(ctx context.Context, request openapi.RemoveGroupParentRequestObject) (openapi.RemoveGroupParentResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.GroupParentTable.ID, request.Id)
err := s.queries.RemoveParentGroup(ctx, sqlc.RemoveParentGroupParams{
ChildGroupID: request.Id,
ParentGroupID: request.ParentGroupId,
})
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.GroupParentTable.ID, request.Id)
return openapi.RemoveGroupParent204Response{}, nil
}
func (s *Service) AddUserGroup(ctx context.Context, request openapi.AddUserGroupRequestObject) (openapi.AddUserGroupResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.UserGroupTable.ID, request.Body)
err := s.queries.AssignGroupToUser(ctx, sqlc.AssignGroupToUserParams{
UserID: request.Id,
GroupID: request.Body.GroupId,
})
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.UserGroupTable.ID, request.Body)
return openapi.AddUserGroup201Response{}, nil
}
func (s *Service) RemoveUserGroup(ctx context.Context, request openapi.RemoveUserGroupRequestObject) (openapi.RemoveUserGroupResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.UserGroupTable.ID, request.Id)
err := s.queries.RemoveGroupFromUser(ctx, sqlc.RemoveGroupFromUserParams{
UserID: request.Id,
GroupID: request.GroupId,
})
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.UserGroupTable.ID, request.Id)
return openapi.RemoveUserGroup204Response{}, nil
}
func (s *Service) ListUserPermissions(ctx context.Context, request openapi.ListUserPermissionsRequestObject) (openapi.ListUserPermissionsResponseObject, error) {
permissions, err := s.queries.ListUserPermissions(ctx, request.Id)
if err != nil {
return nil, err
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.UserPermissionTable.ID, permissions)
return openapi.ListUserPermissions200JSONResponse(permissions), nil
}
func (s *Service) ListUserGroups(ctx context.Context, request openapi.ListUserGroupsRequestObject) (openapi.ListUserGroupsResponseObject, error) {
groups, err := s.queries.ListUserGroups(ctx, request.Id)
if err != nil {
return nil, err
}
response := make([]openapi.UserGroup, 0, len(groups))
for _, group := range groups {
response = append(response, openapi.UserGroup{
Created: group.Created,
Id: group.ID,
Name: group.Name,
Permissions: auth.FromJSONArray(ctx, group.Permissions),
Type: group.GroupType,
Updated: group.Updated,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.UserGroupTable.ID, response)
return openapi.ListUserGroups200JSONResponse(response), nil
}
func (s *Service) ListGroupUsers(ctx context.Context, request openapi.ListGroupUsersRequestObject) (openapi.ListGroupUsersResponseObject, error) {
users, err := s.queries.ListGroupUsers(ctx, request.Id)
if err != nil {
return nil, err
}
response := make([]openapi.GroupUser, 0, len(users))
for _, user := range users {
response = append(response, openapi.GroupUser{
Avatar: user.Avatar,
Created: user.Created,
Email: user.Email,
Id: user.ID,
LastResetSentAt: user.Lastresetsentat,
LastVerificationSentAt: user.Lastverificationsentat,
Name: user.Name,
Updated: user.Updated,
Username: user.Username,
Active: user.Active,
Type: user.GroupType,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.GroupUserTable.ID, response)
return openapi.ListGroupUsers200JSONResponse(response), nil
}
func (s *Service) ListParentPermissions(ctx context.Context, request openapi.ListParentPermissionsRequestObject) (openapi.ListParentPermissionsResponseObject, error) {
permissions, err := s.queries.ListParentPermissions(ctx, request.Id)
if err != nil {
return nil, err
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.GroupPermissionTable.ID, permissions)
return openapi.ListParentPermissions200JSONResponse(permissions), nil
}
func (s *Service) ListParentGroups(ctx context.Context, request openapi.ListParentGroupsRequestObject) (openapi.ListParentGroupsResponseObject, error) {
groups, err := s.queries.ListParentGroups(ctx, request.Id)
if err != nil {
return nil, err
}
response := make([]openapi.UserGroup, 0, len(groups))
for _, group := range groups {
response = append(response, openapi.UserGroup{
Created: group.Created,
Id: group.ID,
Name: group.Name,
Permissions: auth.FromJSONArray(ctx, group.Permissions),
Type: group.GroupType,
Updated: group.Updated,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.GroupParentTable.ID, response)
return openapi.ListParentGroups200JSONResponse(response), nil
}
func (s *Service) ListChildGroups(ctx context.Context, request openapi.ListChildGroupsRequestObject) (openapi.ListChildGroupsResponseObject, error) {
groups, err := s.queries.ListChildGroups(ctx, request.Id)
if err != nil {
return nil, err
}
response := make([]openapi.UserGroup, 0, len(groups))
for _, group := range groups {
response = append(response, openapi.UserGroup{
Created: group.Created,
Id: group.ID,
Name: group.Name,
Permissions: auth.FromJSONArray(ctx, group.Permissions),
Type: group.GroupType,
Updated: group.Updated,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.GroupChildTable.ID, response)
return openapi.ListChildGroups200JSONResponse(response), nil
}
func (s *Service) ListWebhooks(ctx context.Context, request openapi.ListWebhooksRequestObject) (openapi.ListWebhooksResponseObject, error) {
webhooks, err := s.queries.ListWebhooks(ctx, sqlc.ListWebhooksParams{
Offset: toInt64(request.Params.Offset, defaultOffset),
Limit: toInt64(request.Params.Limit, defaultLimit),
})
if err != nil {
return nil, err
}
response := make([]openapi.Webhook, 0, len(webhooks))
for _, webhook := range webhooks {
response = append(response, openapi.Webhook{
Id: webhook.ID,
Name: webhook.Name,
})
}
s.hooks.OnRecordsListRequest.Publish(ctx, database.WebhooksTable.ID, response)
totalCount := 0
if len(webhooks) > 0 {
totalCount = int(webhooks[0].TotalCount)
}
return openapi.ListWebhooks200JSONResponse{
Body: response,
Headers: openapi.ListWebhooks200ResponseHeaders{
XTotalCount: totalCount,
},
}, nil
}
func (s *Service) CreateWebhook(ctx context.Context, request openapi.CreateWebhookRequestObject) (openapi.CreateWebhookResponseObject, error) {
s.hooks.OnRecordBeforeCreateRequest.Publish(ctx, database.WebhooksTable.ID, request.Body)
webhook, err := s.queries.CreateWebhook(ctx, sqlc.CreateWebhookParams{
Name: request.Body.Name,
Destination: request.Body.Destination,
Collection: request.Body.Collection,
})
if err != nil {
return nil, err
}
response := openapi.Webhook{
Id: webhook.ID,
Name: webhook.Name,
Created: webhook.Created,
Updated: webhook.Updated,
Destination: webhook.Destination,
Collection: webhook.Collection,
}
s.hooks.OnRecordAfterCreateRequest.Publish(ctx, database.WebhooksTable.ID, response)
return openapi.CreateWebhook200JSONResponse(response), nil
}
func (s *Service) DeleteWebhook(ctx context.Context, request openapi.DeleteWebhookRequestObject) (openapi.DeleteWebhookResponseObject, error) {
s.hooks.OnRecordBeforeDeleteRequest.Publish(ctx, database.WebhooksTable.ID, request.Id)
err := s.queries.DeleteWebhook(ctx, request.Id)
if err != nil {
return nil, err
}
s.hooks.OnRecordAfterDeleteRequest.Publish(ctx, database.WebhooksTable.ID, request.Id)
return openapi.DeleteWebhook204Response{}, nil
}
func (s *Service) GetWebhook(ctx context.Context, request openapi.GetWebhookRequestObject) (openapi.GetWebhookResponseObject, error) {
webhook, err := s.queries.GetWebhook(ctx, request.Id)
if err != nil {
return nil, err
}
response := openapi.Webhook{
Id: webhook.ID,
Name: webhook.Name,
Created: webhook.Created,
Updated: webhook.Updated,
Destination: webhook.Destination,
Collection: webhook.Collection,
}
s.hooks.OnRecordViewRequest.Publish(ctx, database.WebhooksTable.ID, response)
return openapi.GetWebhook200JSONResponse(response), nil
}
func (s *Service) UpdateWebhook(ctx context.Context, request openapi.UpdateWebhookRequestObject) (openapi.UpdateWebhookResponseObject, error) {
s.hooks.OnRecordBeforeUpdateRequest.Publish(ctx, database.WebhooksTable.ID, request.Body)
webhook, err := s.queries.UpdateWebhook(ctx, sqlc.UpdateWebhookParams{
ID: request.Id,
Name: request.Body.Name,
Destination: request.Body.Destination,
Collection: request.Body.Collection,
})
if err != nil {
return nil, err
}
response := openapi.Webhook{
Id: webhook.ID,
Name: webhook.Name,
Created: webhook.Created,
Updated: webhook.Updated,
Destination: webhook.Destination,
Collection: webhook.Collection,
}
s.hooks.OnRecordAfterUpdateRequest.Publish(ctx, database.WebhooksTable.ID, response)
return openapi.UpdateWebhook200JSONResponse(response), nil
}
func (s *Service) GetConfig(ctx context.Context, _ openapi.GetConfigRequestObject) (openapi.GetConfigResponseObject, error) {
flags := []string{}
features, err := database.PaginateItems(ctx, func(ctx context.Context, offset, limit int64) ([]sqlc.ListFeaturesRow, error) {
return s.queries.ListFeatures(ctx, sqlc.ListFeaturesParams{Limit: limit, Offset: offset})
})
if err != nil {
return nil, err
}
for _, feature := range features {
flags = append(flags, feature.Key)
}
tables := []openapi.Table{}
for _, table := range database.Tables() {
tables = append(tables, openapi.Table{
Id: table.ID,
Name: table.Name,
})
}
response := openapi.Config{
Flags: flags,
Permissions: auth.All(),
Tables: tables,
}
return openapi.GetConfig200JSONResponse(response), nil
}
func (s *Service) GetSettings(ctx context.Context, _ openapi.GetSettingsRequestObject) (openapi.GetSettingsResponseObject, error) {
settings, err := settings.Load(ctx, s.queries)
if err != nil {
return nil, err
}
return openapi.GetSettings200JSONResponse(mapSettings(settings)), nil
}
func (s *Service) UpdateSettings(ctx context.Context, request openapi.UpdateSettingsRequestObject) (openapi.UpdateSettingsResponseObject, error) {
se, err := settings.Update(ctx, s.queries, func(settings *settings.Settings) {
settings.Meta.AppName = request.Body.Meta.AppName
settings.Meta.AppURL = request.Body.Meta.AppUrl
settings.Meta.SenderAddress = request.Body.Meta.SenderAddress
settings.Meta.SenderName = request.Body.Meta.SenderName
settings.SMTP.Enabled = request.Body.Smtp.Enabled
settings.SMTP.Host = request.Body.Smtp.Host
settings.SMTP.Port = request.Body.Smtp.Port
settings.SMTP.Username = request.Body.Smtp.Username
settings.SMTP.Password = request.Body.Smtp.Password
settings.SMTP.AuthMethod = request.Body.Smtp.AuthMethod
settings.SMTP.TLS = request.Body.Smtp.Tls
settings.SMTP.LocalName = request.Body.Smtp.LocalName
})
if err != nil {
return nil, fmt.Errorf("failed to save settings: %w", err)
}
return openapi.UpdateSettings200JSONResponse(mapSettings(se)), err
}
func toString(value *string, defaultValue string) string {
if value == nil {
return defaultValue
}
return *value
}
func toInt64(value *int, defaultValue int64) int64 {
if value == nil {
return defaultValue
}
return int64(*value)
}
func marshal(state map[string]any) json.RawMessage {
b, _ := json.Marshal(state) //nolint:errchkjson
return b
}
func marshalPointer(state *map[string]any) json.RawMessage {
if state == nil {
return json.RawMessage("{}")
}
b, _ := json.Marshal(*state) //nolint:errchkjson
return b
}
func unmarshal(data json.RawMessage) map[string]any {
var m map[string]any
if err := json.Unmarshal([]byte(data), &m); err != nil {
return nil
}
return m
}
func mapSettings(settings *settings.Settings) openapi.Settings {
return openapi.Settings{
Meta: openapi.SettingsMeta{
AppName: settings.Meta.AppName,
AppUrl: settings.Meta.AppURL,
SenderAddress: settings.Meta.SenderAddress,
SenderName: settings.Meta.SenderName,
ResetPasswordTemplate: openapi.EmailTemplate{
Body: settings.Meta.ResetPasswordTemplate.Body,
Subject: settings.Meta.ResetPasswordTemplate.Subject,
},
},
Smtp: openapi.SettingsSmtp{
AuthMethod: settings.SMTP.AuthMethod,
Enabled: settings.SMTP.Enabled,
Host: settings.SMTP.Host,
LocalName: settings.SMTP.LocalName,
Password: settings.SMTP.Password,
Port: settings.SMTP.Port,
Tls: settings.SMTP.TLS,
Username: settings.SMTP.Username,
},
}
}