Compare commits

...

21 commits
v1.0.0 ... main

Author SHA1 Message Date
5faef9defc
feat(style): mobile tweaks
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
Signed-off-by: Nikurasu <publicmail@nikurasu.gay>
2024-06-30 20:35:46 +02:00
c983a1b19c
feat(style): mobile tweaks
All checks were successful
ci/woodpecker/tag/woodpecker Pipeline was successful
Signed-off-by: Nikurasu <publicmail@nikurasu.gay>
2024-06-29 18:50:20 +02:00
615691e3c5
feat(style): mobile tweaks
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
Signed-off-by: Nikurasu <publicmail@nikurasu.gay>
2024-06-29 18:36:38 +02:00
dc9a1b60f1
fix(i18n): add missing localization
All checks were successful
ci/woodpecker/manual/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-06-17 21:14:37 +02:00
a8bff45a8e
feature(db): switch to cgo-less driver
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-06-16 21:26:50 +02:00
95e64b8ded
Add ui with new translations
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-06-14 01:27:45 +02:00
1d20377ee6
Add function for Erding Event
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-06-14 00:44:28 +02:00
246f0046ae
fix(router): small lil typo
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
added a missing '/' maybe it's important, maybe it's not
2024-05-27 19:07:42 +02:00
2e5993abe7
fix(json-parsing): wrong itemId
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
Fixed that the wrong id was checked for the bar
2024-05-27 18:53:50 +02:00
beeb22dc42
feat(attendies): New view and backend
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
Add an importer for special events with a role selection
2024-05-26 16:27:18 +02:00
8206d16be0
feat(view): add view and backend for regulars tables
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-05-26 01:14:46 +02:00
3fde58c143
feat(ci): add ci
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-05-10 08:01:17 +02:00
5e2fc7f87b
fix(get-attendies): get all orders from pretix
Pretix paginates if there are over 50 orders in one request, request the following orders
2024-03-10 13:05:39 +01:00
123f9c5957
feat(display-attendies): save in db
The waiting list is now saved in the db because before doing so the wating list was calculated on each request on the ui AFTER getting only the attendies that allowed the display which leads to false results. And it is now possible to get if an attendie is on the waiting list even if we only want do get one attendie via the API
2024-03-09 20:19:11 +01:00
bd6e60d461
fix(display-attendies): fix template 2024-03-09 05:19:51 +01:00
be03226aa4
fix(display-attendies): fix template 2024-03-09 05:15:38 +01:00
151151e39e
feat(display-attendies): display restaurant 2024-03-09 05:06:13 +01:00
84eff374ee
fix(localization): small fixes in the localization
Add missing ungendered German forms and remove sadly/leider in a string, because it doesn't sound good
2024-03-05 21:18:02 +01:00
deee8e82b2
feat(translation): fully translated to german 2024-03-04 18:54:18 +01:00
0965f9e115
feat(display-attendies): split list
Split up suiter list in attendies and suiterWaitingList

and added localization with goi18n, btw
2024-03-03 22:55:50 +01:00
a914d6a328
fix(error-handling): Handle the .env not found error
Dont panic at that error
2024-02-25 19:23:55 +01:00
31 changed files with 1092 additions and 71 deletions

3
.gitignore vendored
View file

@ -1,4 +1,5 @@
go.sum
.env
pretix-proxy
main.db
main.db
src/db.db

4
.vscode/launch.json vendored
View file

@ -8,8 +8,8 @@
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "src/main.go"
"mode": "debug",
"program": "src/main.go",
}
]
}

22
.woodpecker.yml Normal file
View file

@ -0,0 +1,22 @@
steps:
- name: build docker
image: docker:25-cli
secrets: [user, pass]
commands:
- apk add git
- REPO=$(echo "$CI_REPO" | tr '[:upper:]' '[:lower:]')
- REGISTRY="dev.cat-enby.club"
- DOCKERFILE="./dev/docker/images/production/backend/Dockerfile"
- MAJOR=$(echo ${CI_COMMIT_TAG} | cut -d '.' -f 1 | tr -d 'v')
- MINOR=$(echo ${CI_COMMIT_TAG} | cut -d '.' -f 2)
- PATCH=$(echo ${CI_COMMIT_TAG} | cut -d '.' -f 3 | cut -d '-' -f 1)
- docker buildx build -t $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR:-0}.$${PATCH-0} -t $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR} -t $${REGISTRY}/$$REPO:v$${MAJOR:-0} -t $${REGISTRY}/$$REPO:latest -f $${DOCKERFILE} .
- docker login --username $USER --password $PASS $${REGISTRY}
- docker push $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR:-0}.$${PATCH-0}
- docker push $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR}
- docker push $${REGISTRY}/$${REPO}:v$${MAJOR:-0}
- docker push $${REGISTRY}/$${REPO}:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
when:
- event: tag

View file

@ -2,9 +2,9 @@ FROM golang:alpine3.17 AS build
WORKDIR /build
COPY ./src ./src
WORKDIR /build/src
RUN ls
RUN apk add gcc libc-dev
RUN go get .
RUN go build -o /build/pretix-proxy
RUN CGO_ENABLED=1 go build -o /build/pretix-proxy
FROM alpine:3.17 AS final
COPY --from=build /build/pretix-proxy /bin/pretix-proxy

View file

@ -1,10 +1,11 @@
package controller
import (
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
"ulmer-furs.de/pretix-proxy/v2/app/service"
"ulmer-furs.de/pretix-proxy/v2/config"
)
// @Description Get the attendies of an event by the name
@ -23,6 +24,13 @@ func GetAttendiesByEventPublic(c *fiber.Ctx) error {
}
func GetAttendiesByEventPublicTable(c *fiber.Ctx) error {
siteLang := c.Query("lang")
var localizer *i18n.Localizer
if siteLang == "de-DE" {
localizer = i18n.NewLocalizer(config.LocaleBundle, language.German.String())
} else {
localizer = i18n.NewLocalizer(config.LocaleBundle)
}
name := c.Params("name")
event, err := service.Get_db_event_by_event(name)
if err != nil {
@ -32,8 +40,74 @@ func GetAttendiesByEventPublicTable(c *fiber.Ctx) error {
if err != nil {
return c.Status(fiber.ErrNotFound.Code).SendString("attendies not found")
}
localizations := map[string]string{
"Attendie": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Attendie",
PluralCount: 2,
}),
"HelloWorld": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "HelloWorld",
}),
"Role": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Role",
PluralCount: 1,
}),
"Name": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Name",
PluralCount: 1,
}),
"Guest": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Guest",
PluralCount: 1,
}),
"Spotter": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Spotter",
PluralCount: 1,
}),
"Suiter": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Suiter",
PluralCount: 1,
}),
"Photographer": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Photographer",
PluralCount: 1,
}),
"SpecialAnimal": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "SpecialAnimal",
PluralCount: 1,
}),
"Registered": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Registered",
}),
"SuiterWaitinglist": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "SuiterWaitinglist",
}),
"WaitinglistDesc": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "WaitinglistDesc",
}),
"Restaurant": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Restaurant",
PluralCount: 1,
}),
"Yes": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Yes",
}),
"No": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "No",
}),
"AfterParty": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "AfterParty",
PluralCount: 1,
}),
"Event": localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: "Event",
PluralCount: 1,
}),
}
return c.Render("app/views/index", fiber.Map{
"Title": fmt.Sprintf("%s Attendies", *event.Event),
"EventName": *(event).Name,
"Attendies": attendies,
"Locals": localizations,
"EventType": *(event).EventType,
})
}

View file

@ -4,8 +4,10 @@ import (
"fmt"
"github.com/gofiber/fiber/v2"
"github.com/yassinebenaid/godump"
"ulmer-furs.de/pretix-proxy/v2/app/service"
"ulmer-furs.de/pretix-proxy/v2/app/util"
"ulmer-furs.de/pretix-proxy/v2/config"
"ulmer-furs.de/pretix-proxy/v2/entities"
)
@ -14,11 +16,10 @@ func PostPretixRoleQuestion(c *fiber.Ctx) error {
if err := c.BodyParser(data); err != nil {
return c.Status(fiber.ErrBadRequest.Code).SendString(err.Error())
}
//TODO: Update attendies from pretix
pretixOrders, err := util.GetPretixOrders(&data.Organizer, &data.Event)
_ = pretixOrders
pretixOrders, err := getAllPretixOrders(&data.Organizer, &data.Event)
if err != nil {
return c.Status(500).SendString("Internal Server Error")
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
event, err := service.Get_db_event_by_event(data.Event)
if err != nil {
@ -27,13 +28,16 @@ func PostPretixRoleQuestion(c *fiber.Ctx) error {
attendies, err := util.GetAttendiesFromPretixJsonWithRoleQuestion(pretixOrders, &event)
if err != nil {
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
if err := service.DeleteAttendiesByEvent(event); err != nil {
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
for _, attendie := range attendies {
if err := service.CreateNewAttendie(attendie); err != nil {
fmt.Print(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
}
return c.SendStatus(fiber.StatusOK)
@ -44,9 +48,7 @@ func PostPretixRoleProduct(c *fiber.Ctx) error {
if err := c.BodyParser(data); err != nil {
return c.Status(fiber.ErrBadRequest.Code).SendString(err.Error())
}
//TODO: Update attendies from pretix
pretixOrders, err := util.GetPretixOrders(&data.Organizer, &data.Event)
_ = pretixOrders
pretixOrders, err := getAllPretixOrders(&data.Organizer, &data.Event)
if err != nil {
return c.Status(500).SendString("Internal Server Error")
}
@ -54,19 +56,132 @@ func PostPretixRoleProduct(c *fiber.Ctx) error {
if err != nil {
return c.Status(fiber.StatusNotFound).SendString("Event not found")
}
fmt.Printf("%+v\n", pretixOrders)
attendies, err := util.GetAttendiesFromPretixJsonWithRoleProduct(pretixOrders, &event)
fmt.Printf("%+v\n", attendies)
if err != nil {
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
if err := service.DeleteAttendiesByEvent(event); err != nil {
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
for _, attendie := range attendies {
if err := service.CreateNewAttendie(attendie); err != nil {
fmt.Print(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
}
return c.SendStatus(fiber.StatusOK)
}
func PostPretixRegularsTable(c *fiber.Ctx) error {
data := new(entities.Pretix_Webhook)
if err := c.BodyParser(data); err != nil {
return c.Status(fiber.ErrBadRequest.Code).SendString(err.Error())
}
pretixOrders, err := getAllPretixOrders(&data.Organizer, &data.Event)
if err != nil {
return c.Status(500).SendString("Internal Server Error")
}
event, err := service.Get_db_event_by_event(data.Event)
if err != nil {
return c.Status(fiber.StatusNotFound).SendString("Event not found")
}
attendies, err := util.GetAttendiesFromPretixJsonWithSeperateSubProducts(pretixOrders, &event)
if err != nil {
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
if err := service.DeleteAttendiesByEvent(event); err != nil {
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
for _, attendie := range attendies {
if err := service.CreateNewAttendie(attendie); err != nil {
fmt.Print(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
}
return c.SendStatus(fiber.StatusOK)
}
func PostPretixSpecialEventWithRoles(c *fiber.Ctx) error {
data := new(entities.Pretix_Webhook)
if err := c.BodyParser(data); err != nil {
return c.Status(fiber.ErrBadRequest.Code).SendString(err.Error())
}
pretixOrders, err := getAllPretixOrders(&data.Organizer, &data.Event)
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
event, err := service.Get_db_event_by_event(data.Event)
if err != nil {
return c.Status(fiber.StatusNotFound).SendString("Event not found")
}
attendies, err := util.GetAttendiesFromPretixJsonWithRoleQuestionNoSubproducts(
pretixOrders,
&event,
)
if err != nil {
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
if err := service.DeleteAttendiesByEvent(event); err != nil {
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
for _, attendie := range attendies {
if err := service.CreateNewAttendie(attendie); err != nil {
fmt.Print(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
}
return c.SendStatus(fiber.StatusOK)
}
func PostPretixEventWithoutMainProduct(c *fiber.Ctx) error {
data := new(entities.Pretix_Webhook)
if err := c.BodyParser(data); err != nil {
return c.Status(fiber.ErrBadRequest.Code).SendString(err.Error())
}
pretixOrders, err := getAllPretixOrders(&data.Organizer, &data.Event)
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
event, err := service.Get_db_event_by_event(data.Event)
if err != nil {
return c.Status(fiber.StatusNotFound).SendString("Event not found")
}
attendies, err := util.GetAttendiesFromPretixJsonFindNameInProducts(pretixOrders, &event)
if err != nil {
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
if err := service.DeleteAttendiesByEvent(event); err != nil {
fmt.Println(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
for _, attendie := range attendies {
if err := service.CreateNewAttendie(attendie); err != nil {
fmt.Print(err)
return c.SendStatus(fiber.StatusInternalServerError)
}
}
return c.SendStatus(fiber.StatusOK)
}
func getAllPretixOrders(organizer, event *string) (*entities.Pretix_Event, error) {
pretixOrders, err := util.GetPretixOrders(organizer, event)
for link := pretixOrders.Next; link != nil; {
next_page, err := util.GetPretixOrdersByLink(link)
if err != nil {
return nil, err
}
pretixOrders.Results = append(pretixOrders.Results, next_page.Results...)
link = next_page.Next
}
if config.Env.Debug {
godump.Dump(pretixOrders)
}
return pretixOrders, err
}

View file

@ -15,8 +15,9 @@ func PrivateRoutes(app *fiber.App) {
event.Get("/:id", controller.ReturnEventById)
event.Delete("/:id", controller.DeleteEventById)
event.Put("/:id", controller.UpdateEventById)
event.Put("", controller.CreateEvent)
event.Post("", controller.CreateEvent)
role := apiv1.Group("/role")
role.Use(config.JwtMiddleware)
role.Get("", controller.ReturnAllRoles)
role.Get("/:id", controller.ReturnRoleById)
role.Delete("/:id", controller.DeleteRoleById)
@ -24,5 +25,5 @@ func PrivateRoutes(app *fiber.App) {
role.Put("", controller.CreateRole)
user := apiv1.Group("/user")
user.Use(config.AuthMiddleware)
user.Put("", controller.CreateUser)
user.Post("", controller.CreateUser)
}

View file

@ -14,6 +14,9 @@ func PublicRoutes(app *fiber.App) {
webhooks := apiv1.Group("/webhooks")
webhooks.Post("/pretix/role_question", controller.PostPretixRoleQuestion)
webhooks.Post("/pretix/role_product", controller.PostPretixRoleProduct)
webhooks.Post("/pretix/subproduct", controller.PostPretixRegularsTable)
webhooks.Post("/pretix/speicalEventRoles", controller.PostPretixSpecialEventWithRoles)
webhooks.Post("/pretix/specialEventWithoutMain", controller.PostPretixEventWithoutMainProduct)
apiv1.Post("/login", controller.LoginUser)
apiv1.Get("/event", controller.ReturnAllEventsPublic)
apiv1.Get("/ping", controller.Ping)

View file

@ -44,9 +44,9 @@ func GetAttendiesByEvent(event entities.Db_Event) ([]entities.Db_Attendies, erro
return attendies, nil
}
func GetAttendiesByEventPrivacy(event entities.Db_Event, privacy bool) ([]entities.Db_Attendies, error) {
func GetAttendiesByEventPrivacy(event entities.Db_Event, privacy bool) (entities.AttendiesList, error) {
var attendies []entities.Db_Attendies
result := config.Database.Model(&entities.Db_Attendies{}).Preload("Event").Preload("Role").Where("event_id = ?", event.ID).Where("privacy = ?", privacy).Find(&attendies)
result := config.Database.Model(&entities.Db_Attendies{}).Preload("Role").Where("event_id = ?", event.ID).Where("privacy = ?", privacy).Find(&attendies)
if result.Error != nil {
return attendies, result.Error
}

View file

@ -8,17 +8,17 @@ import (
"ulmer-furs.de/pretix-proxy/v2/entities"
)
func GetRoleById(id int) (entities.Role, error) {
var role entities.Role
result := config.Database.Find(&role, id)
func GetRoleById(id int) (*entities.Role, error) {
var role *entities.Role
result := config.Database.Find(role, id)
if result.RowsAffected == 0 {
return role, errors.New("role not found")
}
return role, nil
}
func GetRoleByName(name string) (entities.Role, error) {
var role entities.Role
func GetRoleByName(name string) (*entities.Role, error) {
var role *entities.Role
result := config.Database.First(&role, "name = ?", name)
if result.RowsAffected == 0 {
return role, errors.New("role not found")

View file

@ -7,9 +7,10 @@ body {
main {
min-width: 60vw;
max-width: 65vw;
}
h1 {
.textWhite {
color: #ffffff;
}
@ -32,4 +33,21 @@ tbody>tr:nth-child(even) {
tbody>tr:nth-child(odd) {
background-color: #e9e9e9;
}
.tdgreen {
background-color: #8bff6e;
}
.tdred {
background-color: #ff6e6e;
}
.tableWrapper {
overflow-x: auto;
transform: rotate(180deg);
}
.tableWrapper table {
transform: rotate(180deg);
}

View file

@ -0,0 +1,41 @@
package util
import (
"ulmer-furs.de/pretix-proxy/v2/entities"
)
func CreateSuiterWaitingList(attendiesList *entities.AttendiesList, suiterPerSpotter *int, suiter, spotter, specialAnimal *entities.Role) entities.AttendiesList {
spotterCount := attendiesList.CountByRole(*spotter)
suiterCount := spotterCount * *suiterPerSpotter
var suiterCounter int
var suiterWatinglist entities.AttendiesList
var i int
for i < len(*attendiesList) {
if *(*attendiesList)[i].Role == *suiter || *(*attendiesList)[i].Role == *specialAnimal {
suiterCounter++
}
if suiterCounter > suiterCount && (*(*attendiesList)[i].Role == *suiter || *(*attendiesList)[i].Role == *specialAnimal) {
suiterWatinglist = append(suiterWatinglist, (*attendiesList)[i])
*attendiesList = append((*attendiesList)[:i], (*attendiesList)[i+1:]...)
} else {
i++
}
}
return suiterWatinglist
}
func MarkWatingListAttendies(attendiesList *entities.AttendiesList, suiterPerSpotter *int, suiter, spotter, specialAnimal *entities.Role) {
spotterCount := attendiesList.CountByRole(*spotter)
suiterCount := spotterCount * *suiterPerSpotter
var suiterCounter int
var i int
for i < len(*attendiesList) {
if *(*attendiesList)[i].Role == *suiter || *(*attendiesList)[i].Role == *specialAnimal {
suiterCounter++
}
if suiterCounter > suiterCount && (*(*attendiesList)[i].Role == *suiter || *(*attendiesList)[i].Role == *specialAnimal) {
(*attendiesList)[i].OnWaitingList = true
}
i++
}
}

View file

@ -6,9 +6,10 @@ import (
"fmt"
"io"
"net/http"
"slices"
"sort"
"strconv"
"golang.org/x/exp/slices"
"ulmer-furs.de/pretix-proxy/v2/app/service"
"ulmer-furs.de/pretix-proxy/v2/config"
"ulmer-furs.de/pretix-proxy/v2/entities"
@ -36,11 +37,34 @@ func GetPretixOrders(organizer *string, event *string) (*entities.Pretix_Event,
return &unmarshaled_resp, nil
}
func GetPretixOrdersByLink(link *string) (*entities.Pretix_Event, error) {
req, err := http.NewRequest("GET", fmt.Sprintf(*link), nil)
if err != nil {
return nil, errors.New("request error")
}
req.Header.Add("Authorization", fmt.Sprintf("Token %s", config.Env.ApiKeyPretix))
resp, err := config.Client.Do(req)
if err != nil {
return nil, errors.New("request error")
}
respbody, err := io.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return nil, errors.New("request error")
}
var unmarshaled_resp entities.Pretix_Event
if err := json.Unmarshal(respbody, &unmarshaled_resp); err != nil {
return nil, errors.New("request error")
}
return &unmarshaled_resp, nil
}
func GetAttendieListFromPretixJson(pretixEvent entities.Pretix_Event, event entities.Db_Event) entities.Attendies {
var attendies entities.Attendies
var name string
for _, order := range pretixEvent.Results {
indexParticipation := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdParticipation })
indexBadge := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdBadge })
indexRestaurant := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdRestaurant })
@ -76,19 +100,21 @@ func GetAttendieListFromPretixJson(pretixEvent entities.Pretix_Event, event enti
return attendies
}
func GetAttendiesFromPretixJsonWithRoleQuestion(pretixEvent *entities.Pretix_Event, event *entities.Db_Event) ([]entities.Db_Attendies, error) {
var attendies []entities.Db_Attendies
func GetAttendiesFromPretixJsonWithRoleQuestion(pretixEvent *entities.Pretix_Event, event *entities.Db_Event) (entities.AttendiesList, error) {
var attendies entities.AttendiesList
for _, order := range pretixEvent.Results {
fmt.Println("Here")
if order.Status == "c" || order.Status == "e" {
continue
}
var attendie entities.Db_Attendies
attendie.Event = *event
attendie.Event = event
if event.ItemIdParticipation == nil {
return attendies, errors.New("no participation found")
return attendies, errors.New("event has no ItemIdParticipation")
}
indexParticipation := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdParticipation })
if indexParticipation == -1 {
continue
}
if event.ItemIdRestaurant == nil {
attendie.AttendsRestaurant = false
} else {
@ -99,7 +125,6 @@ func GetAttendiesFromPretixJsonWithRoleQuestion(pretixEvent *entities.Pretix_Eve
attendie.AttendsRestaurant = false
}
}
indexName := slices.IndexFunc(order.Positions[indexParticipation].Answers, func(a entities.Pretix_Answer) bool { return a.QuestionsIdentififer == *event.QuestionIdName })
attendie.Nickname = order.Positions[indexParticipation].Answers[indexName].Answer
@ -125,21 +150,26 @@ func GetAttendiesFromPretixJsonWithRoleQuestion(pretixEvent *entities.Pretix_Eve
return attendies, err
}
attendie.RegistrationTime = order.Datetime
attendies = append(attendies, attendie)
}
_, spotter, suiter, _, specialAnimal := GetRoles()
sort.Sort(entities.ByRegistrationTime(attendies))
MarkWatingListAttendies(&attendies, (*event).SuiterPerSpotter, suiter, spotter, specialAnimal)
return attendies, nil
}
func GetAttendiesFromPretixJsonWithRoleProduct(pretixEvent *entities.Pretix_Event, event *entities.Db_Event) ([]entities.Db_Attendies, error) {
var attendies []entities.Db_Attendies
func GetAttendiesFromPretixJsonWithRoleProduct(pretixEvent *entities.Pretix_Event, event *entities.Db_Event) (entities.AttendiesList, error) {
var attendies entities.AttendiesList
for _, order := range pretixEvent.Results {
if order.Status == "c" || order.Status == "e" {
continue
}
var attendie entities.Db_Attendies
attendie.Event = *event
attendie.Event = event
if event.ItemIdParticipation == nil {
return attendies, errors.New("no participation found")
return attendies, errors.New("event has no ItemIdParticipation")
}
indexParticipation := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdParticipation })
if event.ItemIdRestaurant == nil {
@ -180,5 +210,170 @@ func GetAttendiesFromPretixJsonWithRoleProduct(pretixEvent *entities.Pretix_Even
attendies = append(attendies, attendie)
}
_, spotter, suiter, _, specialAnimal := GetRoles()
sort.Sort(entities.ByRegistrationTime(attendies))
MarkWatingListAttendies(&attendies, (*event).SuiterPerSpotter, suiter, spotter, specialAnimal)
return attendies, nil
}
func GetAttendiesFromPretixJsonWithSeperateSubProducts(pretixEvent *entities.Pretix_Event, event *entities.Db_Event) (entities.AttendiesList, error) {
var attendies entities.AttendiesList
for _, order := range pretixEvent.Results {
if order.Status == "c" || order.Status == "e" {
continue
}
var attendie entities.Db_Attendies
attendie.Event = event
if event.ItemIdParticipation == nil {
return attendies, errors.New("event has no ItemIdParticipation")
}
indexParticipation := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdParticipation })
if event.ItemIdRestaurant == nil {
attendie.AttendsRestaurant = false
} else {
indexRestaurant := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdRestaurant })
if indexRestaurant != -1 {
attendie.AttendsRestaurant = true
} else {
attendie.AttendsRestaurant = false
}
}
if event.ItemIdBar == nil {
attendie.AttendsBar = false
} else {
indexBar := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdBar })
if indexBar != -1 {
attendie.AttendsBar = true
} else {
attendie.AttendsBar = false
}
}
indexName := slices.IndexFunc(order.Positions[indexParticipation].Answers, func(a entities.Pretix_Answer) bool { return a.QuestionsIdentififer == *event.QuestionIdName })
indexPrivacy := slices.IndexFunc(order.Positions[indexParticipation].Answers, func(a entities.Pretix_Answer) bool { return a.QuestionsIdentififer == *event.QuestionIdPrivacy })
attendie.RegistrationTime = order.Datetime
attendie.Nickname = order.Positions[indexParticipation].Answers[indexName].Answer
var err error
attendie.Privacy, err = strconv.ParseBool(order.Positions[indexParticipation].Answers[indexPrivacy].Answer)
if err != nil {
return attendies, err
}
attendies = append(attendies, attendie)
}
return attendies, nil
}
func GetAttendiesFromPretixJsonWithRoleQuestionNoSubproducts(pretixEvent *entities.Pretix_Event, event *entities.Db_Event) (entities.AttendiesList, error) {
var attendies entities.AttendiesList
for _, order := range pretixEvent.Results {
if order.Status == "c" || order.Status == "e" {
continue
}
var attendie entities.Db_Attendies
attendie.Event = event
if event.ItemIdParticipation == nil {
return attendies, errors.New("event has no ItemIdParticipation")
}
indexParticipation := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdParticipation })
indexName := slices.IndexFunc(order.Positions[indexParticipation].Answers, func(a entities.Pretix_Answer) bool { return a.QuestionsIdentififer == *event.QuestionIdName })
indexPrivacy := slices.IndexFunc(order.Positions[indexParticipation].Answers, func(a entities.Pretix_Answer) bool { return a.QuestionsIdentififer == *event.QuestionIdPrivacy })
indexRole := slices.IndexFunc(order.Positions[indexParticipation].Answers, func(a entities.Pretix_Answer) bool { return a.QuestionsIdentififer == *event.QuestionIdRole })
attendie.Nickname = getAttendieNickname(&order, &indexName, &indexParticipation)
attendieRole, err := getAttendieRole(&order, event, &indexRole, &indexParticipation)
if err != nil {
return nil, err
}
attendie.Role = attendieRole
attendie.RegistrationTime = order.Datetime
privacy, err := getAttendiePrivacy(&order, &indexPrivacy, &indexParticipation)
if err != nil {
return nil, err
}
attendie.Privacy = privacy
attendies = append(attendies, attendie)
}
_, spotter, suiter, _, specialAnimal := GetRoles()
sort.Sort(entities.ByRegistrationTime(attendies))
if *event.SuiterPerSpotter != -1 {
MarkWatingListAttendies(&attendies, (*event).SuiterPerSpotter, suiter, spotter, specialAnimal)
}
return attendies, nil
}
func GetAttendiesFromPretixJsonFindNameInProducts(pretixEvent *entities.Pretix_Event, event *entities.Db_Event) (entities.AttendiesList, error) {
var attendies entities.AttendiesList
for _, order := range pretixEvent.Results {
if checkCanceled(order) {
continue
}
var attendie entities.Db_Attendies
attendie.Event = event
if event.ItemIdEvent == nil {
return attendies, errors.New("event has no ItemIdEvent")
}
if event.ItemIdRestaurant == nil {
return attendies, errors.New("event has no ItemIdRestaurant")
}
indexEvent := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdEvent })
indexRestaurant := slices.IndexFunc(order.Positions, func(p entities.Pretix_Position) bool { return p.Item == *event.ItemIdRestaurant })
var indexName int
var indexPrivacy int
if indexEvent != -1 {
indexName = slices.IndexFunc(order.Positions[indexEvent].Answers, func(a entities.Pretix_Answer) bool { return a.QuestionsIdentififer == *event.QuestionIdName })
indexPrivacy = slices.IndexFunc(order.Positions[indexEvent].Answers, func(a entities.Pretix_Answer) bool { return a.QuestionsIdentififer == *event.QuestionIdPrivacy })
attendie.AttendsEvent = true
attendie.Nickname = getAttendieNickname(&order, &indexName, &indexEvent)
privacy, err := getAttendiePrivacy(&order, &indexPrivacy, &indexEvent)
if err != nil {
return nil, err
}
attendie.Privacy = !privacy
}
if indexRestaurant != -1 {
indexName = slices.IndexFunc(order.Positions[indexRestaurant].Answers, func(a entities.Pretix_Answer) bool { return a.QuestionsIdentififer == *event.QuestionIdName })
indexPrivacy = slices.IndexFunc(order.Positions[indexRestaurant].Answers, func(a entities.Pretix_Answer) bool { return a.QuestionsIdentififer == *event.QuestionIdPrivacy })
attendie.AttendsRestaurant = true
attendie.Nickname = getAttendieNickname(&order, &indexName, &indexRestaurant)
privacy, err := getAttendiePrivacy(&order, &indexPrivacy, &indexRestaurant)
if err != nil {
return nil, err
}
attendie.Privacy = !privacy
}
attendie.RegistrationTime = order.Datetime
attendies = append(attendies, attendie)
}
return attendies, nil
}
func checkCanceled(pretixResult entities.Pretix_Result) bool {
return pretixResult.Status == "c" || pretixResult.Status == "e"
}
func getAttendieRole(order *entities.Pretix_Result, event *entities.Db_Event, indexRole, indexParticipation *int) (*entities.Role, error) {
roleAnswer := order.Positions[*indexParticipation].Answers[*indexRole].OptionIdentifiers
if slices.Contains(roleAnswer, *event.OptionIdSuiter) {
return service.GetRoleByName("Suiter")
} else if slices.Contains(roleAnswer, *event.OptionIdSpotter) {
return service.GetRoleByName("Spotter")
} else if slices.Contains(roleAnswer, *event.OptionIdPhotograph) {
return service.GetRoleByName("Photograph")
} else if slices.Contains(roleAnswer, *event.OptionIdSpecialAnimal) {
return service.GetRoleByName("SpecialAnimal")
} else if slices.Contains(roleAnswer, *event.OptionIdGuest) {
return service.GetRoleByName("Guest")
}
return nil, fmt.Errorf("role not found")
}
func getAttendieNickname(order *entities.Pretix_Result, indexName, indexParticipation *int) string {
return order.Positions[*indexParticipation].Answers[*indexName].Answer
}
func getAttendiePrivacy(order *entities.Pretix_Result, indexPrivacy, indexParticipation *int) (bool, error) {
privacy, err := strconv.ParseBool(order.Positions[*indexParticipation].Answers[*indexPrivacy].Answer)
if err != nil {
return privacy, err
}
return privacy, err
}

View file

@ -0,0 +1,15 @@
package util
import (
"ulmer-furs.de/pretix-proxy/v2/app/service"
"ulmer-furs.de/pretix-proxy/v2/entities"
)
func GetRoles() (guest, spotter, suiter, photograph, specialAnimal *entities.Role) {
guest, _ = service.GetRoleByName("Guest")
spotter, _ = service.GetRoleByName("Spotter")
suiter, _ = service.GetRoleByName("Suiter")
photograph, _ = service.GetRoleByName("Photograph")
specialAnimal, _ = service.GetRoleByName("SpecialAnimal")
return
}

View file

@ -8,8 +8,16 @@
</head>
<body>
<main>
<h1>{{.Title}}</h1>
{{template "table" .}}
<h1 class="textWhite">{{.Title}}</h1>
{{ if eq .EventType "Suitwalk" }}
{{template "suitwalk" .}}
{{ else if eq .EventType "RegularsTable" }}
{{ template "regularstable" .}}
{{ else if eq .EventType "SpecialEventRoles" }}
{{ template "specialEventRoles" . }}
{{ else if eq .EventType "SpecialEvent" }}
{{ template "specialEvent" . }}
{{ end }}
</main>
</body>
</html>

View file

@ -0,0 +1,51 @@
{{ define "regularstable" }}
<h1 class="textWhite">{{ .EventName }} {{ .Locals.Attendie }}</h1>
<h2 class="textWhite">{{ .Locals.Registered }}</h2>
<div class="tableWrapper">
<table>
<thead>
<tr class="tableHeading">
<th>{{ .Locals.Name }}</th>
<th>{{ .Locals.Restaurant }}</th>
<th>{{ .Locals.AfterParty }}</th>
</tr>
</thead>
<tbody>
{{range $attendie := .Attendies }}
{{if not $attendie.OnWaitingList }}
<tr>
<td>{{ $attendie.Nickname }}</td>
{{ if $attendie.AttendsRestaurant }}
<td class="tdgreen">✓ {{ $.Locals.Yes }}</td>
{{ else }}
<td class="tdred">❌ {{ $.Locals.No }}</td>
{{ end }}
{{ if $attendie.AttendsBar }}
<td class="tdgreen">✓ {{ $.Locals.Yes }}</td>
{{ else }}
<td class="tdred">❌ {{ $.Locals.No }}</td>
{{ end }}
</tr>
{{end}}
{{end}}
</tbody>
</table>
<h2 class="textWhite">{{ .Locals.SuiterWaitinglist }}</h2>
<table>
<thead>
<tr>
<th>{{ .Locals.Name }}</th>
</tr>
</thead>
<tbody>
{{range $attendie := .Attendies }}
{{if $attendie.OnWaitingList }}
<tr>
<td>{{ $attendie.Nickname }}</td>
</tr>
{{end}}
{{end}}
</tbody>
</table>
</div>
{{end}}

View file

@ -0,0 +1,34 @@
{{ define "specialEvent" }}
<h1 class="textWhite">{{ .EventName }} {{ .Locals.Attendie }}</h1>
<h2 class="textWhite">{{ .Locals.Registered }}</h2>
<div class="tableWrapper">
<table>
<thead>
<tr class="tableHeading">
<th>{{ .Locals.Name }}</th>
<th>{{ .Locals.Restaurant }}</th>
<th>{{ .Locals.Event }}</th>
</tr>
</thead>
<tbody>
{{range $attendie := .Attendies }}
{{if not $attendie.OnWaitingList }}
<tr>
<td>{{ $attendie.Nickname }}</td>
{{ if $attendie.AttendsRestaurant }}
<td class="tdgreen">✓ {{ $.Locals.Yes }}</td>
{{ else }}
<td class="tdred">❌ {{ $.Locals.No }}</td>
{{ end }}
{{ if $attendie.AttendsEvent }}
<td class="tdgreen">✓ {{ $.Locals.Yes }}</td>
{{ else }}
<td class="tdred">❌ {{ $.Locals.No }}</td>
{{ end }}
</tr>
{{end}}
{{end}}
</tbody>
</table>
</div>
{{end}}

View file

@ -0,0 +1,69 @@
{{define "specialEventRoles"}}
<h1 class="textWhite">{{ .EventName }} {{ .Locals.Attendie }}</h1>
<h2 class="textWhite">{{ .Locals.Registered }}</h2>
<div class="tableWrapper">
<table>
<thead>
<tr class="tableHeading">
<th>{{ .Locals.Name }}</th>
<th>{{ .Locals.Role }}</th>
</tr>
</thead>
<tbody>
{{range $suiter := .Attendies }}
{{if not $suiter.OnWaitingList }}
<tr>
<td>{{ $suiter.Nickname }}</td>
{{ if eq $suiter.Role.Name "Suiter" }}
<td>{{ $.Locals.Suiter }}</td>
{{ else if eq $suiter.Role.Name "SpecialAnimal" }}
<td>{{ $.Locals.SpecialAnimal }}</td>
{{ else if eq $suiter.Role.Name "Spotter" }}
<td>{{ $.Locals.Spotter }}</td>
{{ else if eq $suiter.Role.Name "Photograph" }}
<td>{{ $.Locals.Photographer }}</td>
{{ else if eq $suiter.Role.Name "Guest" }}
<td>{{ $.Locals.Guest }}</td>
{{ end }}
</tr>
{{end}}
{{end}}
</tbody>
</table>
{{ if gt .Attendies.CountWaitingList 0 }}
<h2 class="textWhite">{{ .Locals.SuiterWaitinglist }}</h2>
<p class="textWhite">{{ .Locals.WaitinglistDesc}}</p>
<table>
<thead>
<tr class="tableHeading">
<th>{{ .Locals.Name }}</th>
<th>{{ .Locals.Role }}</th>
{{ if eq .EventType "Suitwalk" }}
<th>{{ .Locals.Restaurant }}</th>
{{ end }}
</tr>
</thead>
<tbody>
{{range $suiter := .Attendies }}
{{if $suiter.OnWaitingList }}
<tr>
<td>{{ $suiter.Nickname }}</td>
{{ if eq $suiter.Role.Name "Suiter" }}
<td>{{ $.Locals.Suiter }}</td>
{{ else if eq $suiter.Role.Name "SpecialAnimal" }}
<td>{{ $.Locals.SpecialAnimal }}</td>
{{ else if eq $suiter.Role.Name "Spotter" }}
<td>{{ $.Locals.Spotter }}</td>
{{ else if eq $suiter.Role.Name "Photograph" }}
<td>{{ $.Locals.Photographer }}</td>
{{ else if eq $suiter.Role.Name "Guest" }}
<td>{{ $.Locals.Guest }}</td>
{{ end }}
</tr>
{{end}}
{{end}}
</tbody>
</table>
</div>
{{end}}
{{end}}

View file

@ -0,0 +1,86 @@
{{define "suitwalk"}}
<h1 class="textWhite">{{ .EventName }} {{ .Locals.Attendie }}</h1>
<h2 class="textWhite">{{ .Locals.Registered }}</h2>
<div class="tableWrapper">
<table>
<thead>
<tr class="tableHeading">
<th>{{ .Locals.Name }}</th>
<th>{{ .Locals.Role }}</th>
{{ if eq .EventType "Suitwalk" }}
<th>{{ .Locals.Restaurant }}</th>
{{ end }}
</tr>
</thead>
<tbody>
{{range $suiter := .Attendies }}
{{if not $suiter.OnWaitingList }}
<tr>
<td>{{ $suiter.Nickname }}</td>
{{ if eq $suiter.Role.Name "Suiter" }}
<td>{{ $.Locals.Suiter }}</td>
{{ else if eq $suiter.Role.Name "SpecialAnimal" }}
<td>{{ $.Locals.SpecialAnimal }}</td>
{{ else if eq $suiter.Role.Name "Spotter" }}
<td>{{ $.Locals.Spotter }}</td>
{{ else if eq $suiter.Role.Name "Photograph" }}
<td>{{ $.Locals.Photographer }}</td>
{{ else if eq $suiter.Role.Name "Guest" }}
<td>{{ $.Locals.Guest }}</td>
{{ end }}
{{ if eq $.EventType "Suitwalk" }}
{{ if $suiter.AttendsRestaurant }}
<td class="tdgreen">✓ {{ $.Locals.Yes }}</td>
{{ else }}
<td class="tdred">❌ {{ $.Locals.No }}</td>
{{ end }}
{{ end }}
</tr>
{{end}}
{{end}}
</tbody>
</table>
{{ if gt .Attendies.CountWaitingList 0 }}
<h2 class="textWhite">{{ .Locals.SuiterWaitinglist }}</h2>
<p class="textWhite">{{ .Locals.WaitinglistDesc}}</p>
<table>
<thead>
<tr class="tableHeading">
<th>{{ .Locals.Name }}</th>
<th>{{ .Locals.Role }}</th>
{{ if eq .EventType "Suitwalk" }}
<th>{{ .Locals.Restaurant }}</th>
{{ end }}
</tr>
</thead>
<tbody>
{{range $suiter := .Attendies }}
{{if $suiter.OnWaitingList }}
<tr>
<td>{{ $suiter.Nickname }}</td>
{{ if eq $suiter.Role.Name "Suiter" }}
<td>{{ $.Locals.Suiter }}</td>
{{ else if eq $suiter.Role.Name "SpecialAnimal" }}
<td>{{ $.Locals.SpecialAnimal }}</td>
{{ else if eq $suiter.Role.Name "Spotter" }}
<td>{{ $.Locals.Spotter }}</td>
{{ else if eq $suiter.Role.Name "Photograph" }}
<td>{{ $.Locals.Photographer }}</td>
{{ else if eq $suiter.Role.Name "Guest" }}
<td>{{ $.Locals.Guest }}</td>
{{ end }}
{{ if eq $.EventType "Suitwalk" }}
{{ if $suiter.AttendsRestaurant }}
<td class="tdgreen">✓ {{ $.Locals.Yes }}</td>
{{ else }}
<td class="tdred">❌ {{ $.Locals.No }}</td>
{{ end }}
{{ end }}
</tr>
{{end}}
{{end}}
</tbody>
</table>
</div>
{{ end }}
{{end}}

View file

@ -1,18 +0,0 @@
{{define "table"}}
<table>
<thead>
<tr class="tableHeading">
<th>Name</th>
<th>Role</th>
</tr>
</thead>
<tbody>
{{range .Attendies}}
<tr>
<td>{{.Nickname}}</td>
<td>{{.Role.Name}}</td>
</tr>
{{end}}
</tbody>
</table>
{{end}}

View file

@ -4,7 +4,7 @@ import (
"fmt"
"log"
"gorm.io/driver/sqlite"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
"ulmer-furs.de/pretix-proxy/v2/entities"
"ulmer-furs.de/pretix-proxy/v2/seeder"

View file

@ -13,7 +13,7 @@ var Env entities.Environment
func LoadEnv() {
err := godotenv.Load()
if err != nil {
log.Fatalf("unable to load .env file: %e", err)
log.Printf("unable to load .env file: %e", err)
}
err = env.Parse(&Env)
if err != nil {

102
src/config/localization.go Normal file
View file

@ -0,0 +1,102 @@
package config
import (
"embed"
"encoding/json"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
)
var LocaleBundle *i18n.Bundle
func SetupLocalization(locaizationFS *embed.FS) {
LocaleBundle = i18n.NewBundle(language.English)
for _, message := range defaultMessages {
LocaleBundle.AddMessages(language.English, &message)
}
LocaleBundle.RegisterUnmarshalFunc("json", json.Unmarshal)
LocaleBundle.LoadMessageFileFS(locaizationFS, "localization/active.de.json")
}
var defaultMessages = []i18n.Message{
{
ID: "HelloWorld",
Other: "Hello newer World",
},
{
ID: "Attendie",
One: "Attendie",
Other: "Attendies",
},
{
ID: "Role",
One: "Role",
Other: "Roles",
},
{
ID: "Name",
One: "Name",
Other: "Names",
},
{
ID: "Registered",
Other: "Registered",
},
{
ID: "SuiterWaitinglist",
Other: "Suiter Watinglist",
},
{
ID: "WaitinglistDesc",
Other: "We set a ratio of Suiters per Spotter for each event in order to keep the count of suiters manageble for them. If you are listed here we don't have enough spotters yet.",
},
{
ID: "Suiter",
One: "Suiter",
Other: "Suiters",
},
{
ID: "Guest",
One: "Guest",
Other: "Guets",
},
{
ID: "Spotter",
One: "Spotter",
Other: "Spotters",
},
{
ID: "Photographer",
One: "Photographer",
Other: "Photographers",
},
{
ID: "SpecialAnimal",
One: "#SpecialAnimal",
Other: "#SpecialAnimals",
},
{
ID: "Restaurant",
One: "Restaurant",
Other: "Restaurantes",
},
{
ID: "Yes",
Other: "Yes",
},
{
ID: "No",
Other: "No",
},
{
ID: "AfterParty",
One: "AfterParty",
Other: "AfterParties",
},
{
ID: "Event",
One: "Event",
Other: "Events",
},
}

View file

@ -0,0 +1,23 @@
package entities
type AttendiesList []Db_Attendies
func (a AttendiesList) CountByRole(role Role) int {
var count int
for _, attendie := range a {
if *attendie.Role == role {
count++
}
}
return count
}
func (a AttendiesList) CountWaitingList() int {
var count int
for _, attendie := range a {
if attendie.OnWaitingList {
count++
}
}
return count
}

View file

@ -1,16 +1,36 @@
package entities
import (
"time"
"gorm.io/gorm"
)
type ByRegistrationTime AttendiesList
func (a ByRegistrationTime) Len() int {
return len(a)
}
func (a ByRegistrationTime) Less(i, j int) bool {
return a[i].RegistrationTime.Unix() < a[j].RegistrationTime.Unix()
}
func (a ByRegistrationTime) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
type Db_Attendies struct {
gorm.Model
Nickname string `gorm:"column:nickname;not null"`
EventID int `gorm:"not null"`
Event Db_Event
RoleID int `gorm:"not null"`
Role Role
AttendsRestaurant bool `gorm:"column:attends_restaurant;not null"`
Privacy bool `gorm:"column:privacy;not null"`
Event *Db_Event
RoleID int `gorm:""`
Role *Role
AttendsRestaurant bool `gorm:"column:attends_restaurant;not null;default:false"`
AttendsBar bool `gorm:"attends_restaurant;not null;default:false"`
AttendsEvent bool `gorm:"attends_event;not null;default:false"`
Privacy bool `gorm:"column:privacy;not null;default:false"`
RegistrationTime time.Time `gorm:"column:registration_time;not null;default:CURRENT_TIMESTAMP"`
OnWaitingList bool `gorm:"column:on_wating_list;not null;default:false"`
}

View file

@ -11,8 +11,10 @@ type Db_Event struct {
Event *string `gorm:"column:event;not null" validate:"required"`
ItemIdBadge *int `gorm:"column:item_id_badge"`
ItemIdRestaurant *int `gorm:"column:item_id_restaurant"`
ItemIdBar *int `gorm:"column:item_id_bar"`
ItemIdParticipation *int `gorm:"column:item_id_participation"`
ItemIdRole *int `gorm:"column:item_id_role"`
ItemIdEvent *int `gorm:"column:item_id_event"`
QuestionIdRole *string `gorm:"column:question_id_role"`
QuestionIdName *string `gorm:"column:question_id_name"`
QuestionIdPrivacy *string `gorm:"column:question_id_is_private"`
@ -27,6 +29,7 @@ type Db_Event struct {
VariationIdPhotograph *int `gorm:"variation_id_photograph"`
VariationIdSpecialAnimal *int `gorm:"variation_id_special_animal"`
EventType *string `gorm:"cloumn:event_type;not null" validate:"required"`
SuiterPerSpotter *int `gorm:"column:suiter_per_spotter;not null;default:5"`
}
type Db_Event_Public struct {

View file

@ -1,13 +1,17 @@
package entities
import "time"
type Pretix_Event struct {
Count int `json:"count"`
Results []Pretix_Result `json:"results"`
Next *string `json:"next"`
}
type Pretix_Result struct {
Status string `json:"status"`
Positions []Pretix_Position `json:"positions"`
Datetime time.Time `json:"datetime"`
}
type Pretix_Position struct {

View file

@ -1,6 +1,8 @@
module ulmer-furs.de/pretix-proxy/v2
go 1.19
go 1.21
toolchain go1.22.4
require (
github.com/go-playground/validator/v10 v10.15.4
@ -9,19 +11,34 @@ require (
github.com/golang-jwt/jwt/v5 v5.1.0
github.com/jinzhu/copier v0.4.0
github.com/joho/godotenv v1.5.1
github.com/nicksnyder/go-i18n/v2 v2.4.0
golang.org/x/crypto v0.15.0
golang.org/x/text v0.14.0
gorm.io/driver/sqlite v1.5.3
gorm.io/gorm v1.25.4
gorm.io/gorm v1.25.7
)
require (
github.com/MicahParks/keyfunc/v2 v2.1.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/glebarez/sqlite v1.11.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/yassinebenaid/godump v0.7.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/text v0.14.0 // indirect
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect
modernc.org/libc v1.52.1 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.30.1 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
)
require (
@ -30,7 +47,7 @@ require (
github.com/gofiber/template v1.8.2 // indirect
github.com/gofiber/template/html/v2 v2.0.5
github.com/gofiber/utils v1.1.0 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.16.7 // indirect
@ -43,6 +60,6 @@ require (
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.50.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63
golang.org/x/sys v0.14.0 // indirect
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678
golang.org/x/sys v0.19.0 // indirect
)

View file

@ -0,0 +1,81 @@
{
"AfterParty": {
"hash": "sha1-78064d491b346faba9074905e42300788f3b2de7",
"one": "AfterStammi",
"other": "AfterStammis"
},
"Attendie": {
"hash": "sha1-4c29d6c952ccd2b114d1792c7b18fa7f7052ebed",
"one": "Teilnehmer*in",
"other": "Teilnehmende"
},
"Event": {
"hash": "sha1-c5497bca58468ae64aed6c0fd921109217988db3",
"one": "Event",
"other": "Events"
},
"Guest": {
"hash": "sha1-7b7f214bbd4af36f25668b0ddade965422d342fd",
"one": "Gast",
"other": "Gäste"
},
"HelloWorld": {
"hash": "sha1-6225ffc638ce81e53cdf7868fe0c7435594f11e4",
"other": "Hallo neuere Welt"
},
"Name": {
"hash": "sha1-2b7c08c3ab75f37e2da656c1aab228f5f3a793b1",
"one": "Name",
"other": "Namen"
},
"No": {
"hash": "sha1-816c52fd2bdd94a63cd0944823a6c0aa9384c103",
"other": "Nein"
},
"Photographer": {
"hash": "sha1-dc41992cfe878fe6744f94c3a3fc5843d9f1bc11",
"one": "Pfotograph*in",
"other": "Pfotographen"
},
"Registered": {
"hash": "sha1-a844fcf834e7d026e7936e042c0ce2777b7fb4d9",
"other": "Angemeldet"
},
"Restaurant": {
"hash": "sha1-b19c390d03b991e33ecbb225687fcaf21da87a89",
"one": "Restaurant",
"other": "Restaurants"
},
"Role": {
"hash": "sha1-47dcc27d6e87ece8baebe7e3877a261a5467093d",
"one": "Rolle",
"other": "Rollen"
},
"SpecialAnimal": {
"hash": "sha1-7f937e9e4906c8f52977132faa76b81f3a331e45",
"one": "#SpezialTier",
"other": "#SpezialTiere"
},
"Spotter": {
"hash": "sha1-6f53dff03ced62b694851ffe37aab682b4b2b227",
"one": "Spotter*in",
"other": "Spotter"
},
"Suiter": {
"hash": "sha1-eb6248e60da77b4df76de9b35efe44178ee34ead",
"one": "Suiter*in",
"other": "Suiter"
},
"SuiterWaitinglist": {
"hash": "sha1-a5d3dc94fc4f3f0604f0cc5e077c0c9eb43340d4",
"other": "Suiter Warteliste"
},
"WaitinglistDesc": {
"hash": "sha1-295479637ef85418e233d16735fdba609595dee7",
"other": "Wir setzen für jedes Event ein Verhältnis von Suitern pro Spotter fest, damit die Spotter auch noch alle versorgen können. Falls du hier gelistet bist, haben sich noch nicht genügend Spotter angemeldet."
},
"Yes": {
"hash": "sha1-5397e0583f14f6c88de06b1ef28f460a1fb5b0ae",
"other": "Ja"
}
}

View file

@ -0,0 +1,52 @@
{
"AfterParty": {
"one": "AfterParty",
"other": "AfterParties"
},
"Attendie": {
"one": "Attendie",
"other": "Attendies"
},
"Event": {
"one": "Event",
"other": "Events"
},
"Guest": {
"one": "Guest",
"other": "Guets"
},
"HelloWorld": "Hello newer World",
"Name": {
"one": "Name",
"other": "Names"
},
"No": "No",
"Photographer": {
"one": "Photographer",
"other": "Photographers"
},
"Registered": "Registered",
"Restaurant": {
"one": "Restaurant",
"other": "Restaurantes"
},
"Role": {
"one": "Role",
"other": "Roles"
},
"SpecialAnimal": {
"one": "#SpecialAnimal",
"other": "#SpecialAnimals"
},
"Spotter": {
"one": "Spotter",
"other": "Spotters"
},
"Suiter": {
"one": "Suiter",
"other": "Suiters"
},
"SuiterWaitinglist": "Suiter Watinglist",
"WaitinglistDesc": "We set a ratio of Suiters per Spotter for each event in order to keep the count of suiters manageble for them. If you are listed here we don't have enough spotters yet.",
"Yes": "Yes"
}

View file

@ -15,6 +15,9 @@ var viewFS embed.FS
//go:embed app/static/*
var staticFS embed.FS
//go:embed localization/active.*.json
var locaizationFS embed.FS
func main() {
config.LoadEnv()
config.Connect()
@ -23,6 +26,7 @@ func main() {
config.SetupFiber(viewFS, staticFS)
config.SetupCors()
config.SetupHttp()
config.SetupLocalization(&locaizationFS)
if config.Env.Debug {
config.App.Use(cors.New(cors.Config{