Compare commits
5 Commits
bd70ac4542
...
c227c291c9
Author | SHA1 | Date | |
---|---|---|---|
c227c291c9 | |||
389922f22d | |||
670290b60b | |||
3345571bd8 | |||
d51e78a442 |
3
.dockerignore
Normal file
3
.dockerignore
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
tmp
|
||||||
|
docker-compose.yaml
|
||||||
|
.air.toml
|
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
FROM golang:1.23-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -o server
|
||||||
|
|
||||||
|
FROM scratch
|
||||||
|
COPY --from=builder /app/server /server
|
||||||
|
ADD https://curl.haxx.se/ca/cacert.pem /etc/ssl/certs/ca-certificates.crt
|
||||||
|
ENTRYPOINT [ "/server" ]
|
@ -15,11 +15,11 @@ import (
|
|||||||
// @Description Generate a contract based on the provided data
|
// @Description Generate a contract based on the provided data
|
||||||
// @Tags contracts
|
// @Tags contracts
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param data body models.Contract true "Contract data"
|
// @Param data body models.ContractRequest true "Contract data"
|
||||||
// @Produce application/pdf
|
// @Produce application/pdf
|
||||||
// @Router /contracts [post]
|
// @Router /contracts [post]
|
||||||
func GenerateContract(c *fiber.Ctx) error {
|
func GenerateContract(c *fiber.Ctx) error {
|
||||||
contract := new(models.Contract)
|
contract := new(models.ContractRequest)
|
||||||
if err := c.BodyParser(contract); err != nil {
|
if err := c.BodyParser(contract); err != nil {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
@ -31,14 +31,7 @@ func GenerateContract(c *fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var duplicates int = 2
|
contract.Runners = repeatRunnerArrayItems(contract.Runners, 2)
|
||||||
var duplicatedRunners []models.Runner
|
|
||||||
for _, runner := range contract.Runners {
|
|
||||||
for i := 0; i < duplicates; i++ {
|
|
||||||
duplicatedRunners = append(duplicatedRunners, runner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
contract.Runners = duplicatedRunners
|
|
||||||
|
|
||||||
generator := services.DefaultTemplater{}
|
generator := services.DefaultTemplater{}
|
||||||
templateString, err := templates.GetTemplate(contract.Locale, "contract")
|
templateString, err := templates.GetTemplate(contract.Locale, "contract")
|
||||||
@ -55,7 +48,7 @@ func GenerateContract(c *fiber.Ctx) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := generator.Execute(template, &models.ContractTemplateOptions{
|
genConfig := &models.ContractTemplateOptions{
|
||||||
Runners: contract.Runners,
|
Runners: contract.Runners,
|
||||||
CurrencySymbol: "€",
|
CurrencySymbol: "€",
|
||||||
Disclaimer: "This is a disclaimer",
|
Disclaimer: "This is a disclaimer",
|
||||||
@ -64,7 +57,9 @@ func GenerateContract(c *fiber.Ctx) error {
|
|||||||
SponsoringHeader: templates.ImageSponsoringHeaderBase64,
|
SponsoringHeader: templates.ImageSponsoringHeaderBase64,
|
||||||
BarcodeFormat: "ean13",
|
BarcodeFormat: "ean13",
|
||||||
BarcodePrefix: "1",
|
BarcodePrefix: "1",
|
||||||
})
|
}
|
||||||
|
|
||||||
|
result, err := generator.Execute(template)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
@ -82,3 +77,13 @@ func GenerateContract(c *fiber.Ctx) error {
|
|||||||
c.Set(fiber.HeaderContentType, "application/pdf")
|
c.Set(fiber.HeaderContentType, "application/pdf")
|
||||||
return c.Send(pdf)
|
return c.Send(pdf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func repeatRunnerArrayItems(runners []Runner, duplicates int) []Runner {
|
||||||
|
var duplicatedRunners []models.Runner
|
||||||
|
for _, runner := range contract.Runners {
|
||||||
|
for i := 0; i < duplicates; i++ {
|
||||||
|
duplicatedRunners = append(duplicatedRunners, runner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return duplicatedRunners
|
||||||
|
}
|
||||||
|
21
models/card.go
Normal file
21
models/card.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
type CardRequest struct {
|
||||||
|
Cards []Card `json:"card"`
|
||||||
|
Locale string `json:"locale" enums:"en,de"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Card struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Runner Runner `json:"runner"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContractTemplateOptions struct {
|
||||||
|
Cards []Card `json:"cards"`
|
||||||
|
EventName string `json:"event_name"`
|
||||||
|
CardSubtitle string `json:"card_subtitle"`
|
||||||
|
BarcodeFormat string `json:"barcode_format"`
|
||||||
|
BarcodePrefix string `json:"barcode_prefix"`
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
type Contract struct {
|
type ContractRequest struct {
|
||||||
Runners []Runner `json:"runners"`
|
Runners []Runner `json:"runners"`
|
||||||
Locale string `json:"locale" enums:"en,de"`
|
Locale string `json:"locale" enums:"en,de"`
|
||||||
}
|
}
|
||||||
|
@ -30,25 +30,25 @@
|
|||||||
<body class="A4 landscape">
|
<body class="A4 landscape">
|
||||||
<div class="sheet">
|
<div class="sheet">
|
||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
{{#each cards}}
|
{{ range .cards }}
|
||||||
<div class="column is-half runnercard">
|
<div class="column is-half runnercard">
|
||||||
<p class="title is-5" style="text-align: center; padding-bottom: 0; margin-top: -0.75rem;">{{../eventname}}</p>
|
<p class="title is-5" style="text-align: center; padding-bottom: 0; margin-top: -0.75rem;">{{ $.EventName }}</p>
|
||||||
<p style="text-align: center; margin-top: -1.5rem; font-size: small;">{{../card_subtitle}}</p>
|
<p style="text-align: center; margin-top: -1.5rem; font-size: small;">{{ $.CardSubtitle }}</p>
|
||||||
<p style="font-size: small;">Mit Unterstützung von:</p>
|
<p style="font-size: small;">Mit Unterstützung von:</p>
|
||||||
<div class="columns" style="height: 6rem; overflow: hidden;">
|
<div class="columns" style="height: 6rem; overflow: hidden;">
|
||||||
<div class="column is-half">
|
<div class="column is-half">
|
||||||
<!--SPONSOR LOGO HERE-->
|
<!--SPONSOR LOGO HERE-->
|
||||||
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
||||||
src="{{--sponsor this.id}}" />
|
src="data:image/png;base64,{{ sponsorLogo .ID }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-half">
|
<div class="column is-half">
|
||||||
<!--BARCODE HERE-->
|
<!--BARCODE HERE-->
|
||||||
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
||||||
src="{{--bc this.code ../codeformat}}" />
|
src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>{{this.runner.lastname}}, {{this.runner.firstname}} {{this.runner.middlename}}</p>
|
<p>{{ .Runner.LastName }}, {{ .Runner.FirstName }} {{ .Runner.MiddleName }}</p>
|
||||||
<p>{{this.runner.group.fullName}}</p>
|
<p>{{ .Runner.Group.Name }}</p>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
@ -59,9 +59,9 @@
|
|||||||
<div class="column is-half runnercard" style="justify-content: center; align-items: center; text-align: center;">
|
<div class="column is-half runnercard" style="justify-content: center; align-items: center; text-align: center;">
|
||||||
<!--SPONSOR LOGO FIRST-->
|
<!--SPONSOR LOGO FIRST-->
|
||||||
<div style="height: 2cm; padding: 0 0 2.25cm 0">
|
<div style="height: 2cm; padding: 0 0 2.25cm 0">
|
||||||
<img style="object-fit: cover; max-height: 2cm;" src="{{--sponsor this.id}}" />
|
<img style="object-fit: cover; max-height: 2cm;" src="data:image/png;base64,{{ sponsorLogo .ID }}" />
|
||||||
</div>
|
</div>
|
||||||
<img style="object-fit: cover; max-height: 2.5cm; position: relative;" src="{{--bc this.code ../codeformat}}" />
|
<img style="object-fit: cover; max-height: 2.5cm; position: relative;" src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,23 +32,23 @@
|
|||||||
<div class="columns is-multiline">
|
<div class="columns is-multiline">
|
||||||
{{#each cards}}
|
{{#each cards}}
|
||||||
<div class="column is-half runnercard">
|
<div class="column is-half runnercard">
|
||||||
<p class="title is-5" style="text-align: center; padding-bottom: 0; margin-top: -0.75rem;">{{../eventname}}</p>
|
<p class="title is-5" style="text-align: center; padding-bottom: 0; margin-top: -0.75rem;">{{ $.EventName }}</p>
|
||||||
<p style="text-align: center; margin-top: -1.5rem; font-size: small;">{{../card_subtitle}}</p>
|
<p style="text-align: center; margin-top: -1.5rem; font-size: small;">{{ $.CardSubtitle }}</p>
|
||||||
<p style="font-size: small;">Supported by:</p>
|
<p style="font-size: small;">Supported by:</p>
|
||||||
<div class="columns" style="height: 6rem; overflow: hidden;">
|
<div class="columns" style="height: 6rem; overflow: hidden;">
|
||||||
<div class="column is-half">
|
<div class="column is-half">
|
||||||
<!--SPONSOR LOGO HERE-->
|
<!--SPONSOR LOGO HERE-->
|
||||||
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
||||||
src="{{--sponsor this.id}}" />
|
src="data:image/png;base64,{{ sponsorLogo .ID }}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-half">
|
<div class="column is-half">
|
||||||
<!--BARCODE HERE-->
|
<!--BARCODE HERE-->
|
||||||
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
<img style="vertical-align: revert; margin-top: auto; object-fit: cover; max-height: 2cm;"
|
||||||
src="{{--bc this.code ../codeformat}}" />
|
src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>{{this.runner.lastname}}, {{this.runner.firstname}} {{this.runner.middlename}}</p>
|
<p>{{ .Runner.LastName }}, {{ .Runner.FirstName }} {{ .Runner.MiddleName }}</p>
|
||||||
<p>{{this.runner.group.fullName}}</p>
|
<p>{{ .Runner.Group.Name }}</p>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
@ -59,9 +59,9 @@
|
|||||||
<div class="column is-half runnercard" style="justify-content: center; align-items: center; text-align: center;">
|
<div class="column is-half runnercard" style="justify-content: center; align-items: center; text-align: center;">
|
||||||
<!--SPONSOR LOGO FIRST-->
|
<!--SPONSOR LOGO FIRST-->
|
||||||
<div style="height: 2cm; padding: 0 0 2.25cm 0">
|
<div style="height: 2cm; padding: 0 0 2.25cm 0">
|
||||||
<img style="object-fit: cover; max-height: 2cm;" src="{{--sponsor this.id}}" />
|
<img style="object-fit: cover; max-height: 2cm;" src="data:image/png;base64,{{ sponsorLogo .ID }}" />
|
||||||
</div>
|
</div>
|
||||||
<img style="object-fit: cover; max-height: 2.5cm; position: relative;" src="{{--bc this.code ../codeformat}}" />
|
<img style="object-fit: cover; max-height: 2.5cm; position: relative;" src="data:image/png;base64,{{ barcode .Code $.BarcodeFormat $.BarcodePrefix }}" />
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user