From 7d22a32cb442c575f3b2544e52f771da4145cf75 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Tue, 3 Dec 2024 18:44:17 +0100 Subject: [PATCH] feat(cards): Implement endpoint for card generation --- docs/docs.go | 66 +++++++++++++++++++++++++++++++++++++-- docs/swagger.json | 66 +++++++++++++++++++++++++++++++++++++-- docs/swagger.yaml | 45 +++++++++++++++++++++++++-- handlers/card.go | 74 ++++++++++++++++++++++++++++++++++++++++++++ handlers/contract.go | 6 ++-- main.go | 1 + models/card.go | 2 +- 7 files changed, 250 insertions(+), 10 deletions(-) create mode 100644 handlers/card.go diff --git a/docs/docs.go b/docs/docs.go index 1c545a7..342345a 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -15,6 +15,33 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/cards": { + "post": { + "description": "Generate cards based on the provided data", + "consumes": [ + "application/json" + ], + "produces": [ + "application/pdf" + ], + "tags": [ + "cards" + ], + "summary": "Generate runner cards", + "parameters": [ + { + "description": "Card data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.CardRequest" + } + } + ], + "responses": {} + } + }, "/contracts": { "post": { "description": "Generate a contract based on the provided data", @@ -35,7 +62,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/models.Contract" + "$ref": "#/definitions/models.ContractRequest" } } ], @@ -44,7 +71,42 @@ const docTemplate = `{ } }, "definitions": { - "models.Contract": { + "models.Card": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "runner": { + "$ref": "#/definitions/models.Runner" + } + } + }, + "models.CardRequest": { + "type": "object", + "properties": { + "card": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Card" + } + }, + "locale": { + "type": "string", + "enum": [ + "en", + "de" + ] + } + } + }, + "models.ContractRequest": { "type": "object", "properties": { "locale": { diff --git a/docs/swagger.json b/docs/swagger.json index 4d57eeb..47feace 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -6,6 +6,33 @@ "contact": {} }, "paths": { + "/cards": { + "post": { + "description": "Generate cards based on the provided data", + "consumes": [ + "application/json" + ], + "produces": [ + "application/pdf" + ], + "tags": [ + "cards" + ], + "summary": "Generate runner cards", + "parameters": [ + { + "description": "Card data", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.CardRequest" + } + } + ], + "responses": {} + } + }, "/contracts": { "post": { "description": "Generate a contract based on the provided data", @@ -26,7 +53,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/models.Contract" + "$ref": "#/definitions/models.ContractRequest" } } ], @@ -35,7 +62,42 @@ } }, "definitions": { - "models.Contract": { + "models.Card": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "runner": { + "$ref": "#/definitions/models.Runner" + } + } + }, + "models.CardRequest": { + "type": "object", + "properties": { + "card": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Card" + } + }, + "locale": { + "type": "string", + "enum": [ + "en", + "de" + ] + } + } + }, + "models.ContractRequest": { "type": "object", "properties": { "locale": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 2072fc0..b37e9d9 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,5 +1,28 @@ definitions: - models.Contract: + models.Card: + properties: + code: + type: string + enabled: + type: boolean + id: + type: integer + runner: + $ref: '#/definitions/models.Runner' + type: object + models.CardRequest: + properties: + card: + items: + $ref: '#/definitions/models.Card' + type: array + locale: + enum: + - en + - de + type: string + type: object + models.ContractRequest: properties: locale: enum: @@ -39,6 +62,24 @@ info: for pdf generation. title: LfK Document Server API paths: + /cards: + post: + consumes: + - application/json + description: Generate cards based on the provided data + parameters: + - description: Card data + in: body + name: data + required: true + schema: + $ref: '#/definitions/models.CardRequest' + produces: + - application/pdf + responses: {} + summary: Generate runner cards + tags: + - cards /contracts: post: consumes: @@ -50,7 +91,7 @@ paths: name: data required: true schema: - $ref: '#/definitions/models.Contract' + $ref: '#/definitions/models.ContractRequest' produces: - application/pdf responses: {} diff --git a/handlers/card.go b/handlers/card.go new file mode 100644 index 0000000..e437471 --- /dev/null +++ b/handlers/card.go @@ -0,0 +1,74 @@ +package handlers + +import ( + "log" + "slices" + + "git.odit.services/lfk/document-server/models" + "git.odit.services/lfk/document-server/services" + "git.odit.services/lfk/document-server/templates" + "github.com/gofiber/fiber/v2" +) + +// GenerateCard godoc +// @Summary Generate runner cards +// @Description Generate cards based on the provided data +// @Tags cards +// @Accept json +// @Param data body models.CardRequest true "Card data" +// @Produce application/pdf +// @Router /cards [post] +func GenerateCard(c *fiber.Ctx) error { + cardRequest := new(models.CardRequest) + if err := c.BodyParser(cardRequest); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": err.Error(), + }) + } + if !slices.Contains([]string{"en", "de"}, cardRequest.Locale) { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "Invalid locale", + }) + } + + generator := services.DefaultTemplater{} + templateString, err := templates.GetTemplate(cardRequest.Locale, "card") + if err != nil { + log.Println(err) + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ + "error": "Template not found", + }) + } + template, err := generator.StringToTemplate(templateString) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": err.Error(), + }) + } + + genConfig := &models.CardTemplateOptions{ + Cards: cardRequest.Cards, + EventName: "Event name", + CardSubtitle: "Card subtitle", + BarcodeFormat: "ean13", + BarcodePrefix: "", + } + + result, err := generator.Execute(template, genConfig) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": err.Error(), + }) + } + + converter := services.GotenbergConverter{BaseUrl: "http://localhost:3001"} + pdf, err := converter.ToPdf(result, "a5", true) + if err != nil { + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": err.Error(), + }) + } + + c.Set(fiber.HeaderContentType, "application/pdf") + return c.Send(pdf) +} diff --git a/handlers/contract.go b/handlers/contract.go index f4e861e..90b93e1 100644 --- a/handlers/contract.go +++ b/handlers/contract.go @@ -59,7 +59,7 @@ func GenerateContract(c *fiber.Ctx) error { BarcodePrefix: "1", } - result, err := generator.Execute(template) + result, err := generator.Execute(template, genConfig) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ "error": err.Error(), @@ -78,9 +78,9 @@ func GenerateContract(c *fiber.Ctx) error { return c.Send(pdf) } -func repeatRunnerArrayItems(runners []Runner, duplicates int) []Runner { +func repeatRunnerArrayItems(runners []models.Runner, duplicates int) []models.Runner { var duplicatedRunners []models.Runner - for _, runner := range contract.Runners { + for _, runner := range runners { for i := 0; i < duplicates; i++ { duplicatedRunners = append(duplicatedRunners, runner) } diff --git a/main.go b/main.go index bf44334..5d72e08 100644 --- a/main.go +++ b/main.go @@ -35,6 +35,7 @@ func main() { return c.SendString("Hello, World!") }) v1.Post("/contracts", handlers.GenerateContract) + v1.Post("/cards", handlers.GenerateCard) app.Use(handlers.NotFoundHandler) docs.SwaggerInfo.BasePath = "/" diff --git a/models/card.go b/models/card.go index d32a037..cf7c574 100644 --- a/models/card.go +++ b/models/card.go @@ -12,7 +12,7 @@ type Card struct { Code string `json:"code"` } -type ContractTemplateOptions struct { +type CardTemplateOptions struct { Cards []Card `json:"cards"` EventName string `json:"event_name"` CardSubtitle string `json:"card_subtitle"`