diff --git a/cmd/convert/main.go b/cmd/convert/main.go deleted file mode 100644 index 118bf5c..0000000 --- a/cmd/convert/main.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (C) 2024 the lets-party maintainers -// See root-dir/LICENSE for more information - -package main - -import ( - "context" - "log/slog" - "os" - - bolt "go.etcd.io/bbolt" - - "github.com/quixsi/core/internal/db" - "github.com/quixsi/core/internal/db/jsondb" - "github.com/quixsi/core/internal/db/kvdb" -) - -func main() { - var ( - // inputType = flag.String("input-type", "json", "") - // inputPath = flag.String("input-path", "json", "") - // outputType = flag.String("output-type", "kvdb", "") - // outputPath = flag.String("output-path", "json", "") - ) - - jsonHandler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{}) - logger := slog.New(jsonHandler) - - jdb := newJsonDB(logger, "../../testdata") - kdb := newKVDB(logger, "output.db") - logger.Info("start converting") - into(kdb, jdb) - logger.Info("finished converting") -} - -type database interface { - db.EventStore - db.GuestStore - db.InvitationStore - db.TranslationStore - Close() error -} - -type dbWrapper struct { - db.EventStore - db.GuestStore - db.InvitationStore - db.TranslationStore - - closeFN func() error -} - -func (d *dbWrapper) Close() error { - return d.closeFN() -} - -func into(dst, src database) { - defer src.Close() - defer dst.Close() - ctx := context.Background() - - guests, err := src.ListGuests(ctx) - if err != nil { - panic(err) - } - for _, g := range guests { - if _, err := dst.CreateGuest(ctx, g); err != nil { - panic(err) - } - } - invites, err := src.ListInvitations(ctx) - if err != nil { - panic(err) - } - for _, inv := range invites { - if _, err := dst.CreateInvitation(ctx, inv.GuestIDs...); err != nil { - panic(err) - } - } - event, err := src.GetEvent(ctx) - if err != nil { - panic(err) - } - if err := dst.UpdateEvent(ctx, event); err != nil { - panic(err) - } - list, err := src.ListLanguages(ctx) - if err != nil { - panic(err) - } - for _, key := range list { - t, err := src.ByLanguage(ctx, key) - if err != nil { - panic(err) - } - if err := dst.CreateLanguage(ctx, key, t); err != nil { - panic(err) - } - } -} - -func newKVDB(logger *slog.Logger, path string) database { - bdb, err := bolt.Open(path, 0600, nil) - if err != nil { - logger.Error("could not initialize guest store", "error", err) - os.Exit(1) - } - - guestsStore, err := kvdb.NewGuestStore(bdb) - if err != nil { - logger.Error("could not initialize guest bucket", "error", err) - os.Exit(1) - } - - invitationStore, err := kvdb.NewInvitationStore(bdb) - if err != nil { - logger.Error("could not initialize guest bucket", "error", err) - os.Exit(1) - } - - eventStore, err := kvdb.NewEventStore(bdb) - if err != nil { - logger.Error("could not initialize event bucket", "error", err) - os.Exit(1) - } - - translationStore, err := kvdb.NewTranslationStore(bdb) - if err != nil { - logger.Error("initialize translation bucket", "error", err) - } - - return &dbWrapper{ - GuestStore: guestsStore, - TranslationStore: translationStore, - InvitationStore: invitationStore, - EventStore: eventStore, - closeFN: bdb.Close, - } -} - -func newJsonDB(logger *slog.Logger, path string) database { - logger.Info("jsondb storage folder", "path", path) - guestsStore, err := jsondb.NewGuestStore(path + "/guests.json") - if err != nil { - logger.Error("could not initialize guest store", "error", path) - os.Exit(1) - } - translationStore, err := jsondb.NewTranslationStore(path + "/translations.json") - if err != nil { - logger.Error("could not initialize translation store", "error", path) - os.Exit(1) - } - invitationStore, err := jsondb.NewInvitationStore(path + "/invitations.json") - if err != nil { - logger.Error("could not initialize invitation store", "error", path) - os.Exit(1) - } - eventStore, err := jsondb.NewEventStore(path + "/event.json") - if err != nil { - logger.Error("could not initialize event store", "error", path) - os.Exit(1) - } - return &dbWrapper{ - GuestStore: guestsStore, - TranslationStore: translationStore, - InvitationStore: invitationStore, - EventStore: eventStore, - closeFN: func() error { return nil }, - } -} diff --git a/cmd/server/main.go b/cmd/server/main.go index 7089e05..78987d9 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -22,7 +22,6 @@ import ( "google.golang.org/grpc/credentials/insecure" "github.com/quixsi/core/internal/db" - "github.com/quixsi/core/internal/db/jsondb" "github.com/quixsi/core/internal/db/kvdb" "github.com/quixsi/core/internal/server" ) @@ -31,7 +30,7 @@ func main() { var ( serviceName = flag.String("service-name", "party-invite", "otel service name") addr = flag.String("addr", "0.0.0.0:8080", "default server address") - dbStr = flag.String("db", "json://testdata", "database connection string") + dbStr = flag.String("db", "kvdb://testdata/test.db", "database connection string") otlpAddr = flag.String("otlp-grpc", "", "default otlp/gRPC address, by default disabled. Example value: localhost:4317") logLevelArg = flag.String("log-level", "INFO", "log level") staticDir = flag.String("static-dir", "", "path to static directory") @@ -100,29 +99,6 @@ func main() { } switch u.Scheme { - case "json": - base := u.Host + u.Path - logger.Info("jsondb storage folder", "path", base) - guestsStore, err = jsondb.NewGuestStore(base + "/guests.json") - if err != nil { - logger.Error("could not initialize guest store", "error", err) - os.Exit(1) - } - translationStore, err = jsondb.NewTranslationStore(base + "/translations.json") - if err != nil { - logger.Error("could not initialize translation store", "error", err) - os.Exit(1) - } - invitationStore, err = jsondb.NewInvitationStore(base + "/invitations.json") - if err != nil { - logger.Error("could not initialize invitation store", "error", err) - os.Exit(1) - } - eventStore, err = jsondb.NewEventStore(base + "/event.json") - if err != nil { - logger.Error("could not initialize event store", "error", err) - os.Exit(1) - } case "kvdb": path := u.Host + u.Path db, err := bolt.Open(path, 0600, nil) diff --git a/internal/db/jsondb/event_store.go b/internal/db/jsondb/event_store.go deleted file mode 100644 index 6115453..0000000 --- a/internal/db/jsondb/event_store.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (C) 2024 the lets-party maintainers -// See root-dir/LICENSE for more information - -package jsondb - -import ( - "context" - "encoding/json" - "errors" - "os" - "sync" - "time" - - "github.com/google/uuid" - "go.opentelemetry.io/otel/trace" - - "github.com/quixsi/core/internal/model" -) - -func NewEventStore(filename string) (*EventStore, error) { - store := &EventStore{ - filename: filename, - event: createDemoEvent(), - } - if err := store.loadFromFile(); err != nil { - return nil, err - } - return store, nil -} - -type EventStore struct { - mu sync.RWMutex - - filename string - event *model.Event -} - -func (e *EventStore) GetEvent(ctx context.Context) (*model.Event, error) { - var span trace.Span - _, span = tracer.Start(ctx, "GetEvent") - defer span.End() - - span.AddEvent("Lock") - e.mu.Lock() - defer span.AddEvent("RUlock") - defer e.mu.Unlock() - - return e.event, nil -} - -func (e *EventStore) UpdateEvent(ctx context.Context, _ *model.Event) error { - var span trace.Span - _, span = tracer.Start(ctx, "UpdateEvent") - defer span.End() - - span.AddEvent("RLock") - e.mu.RLock() - defer span.AddEvent("RUnlock") - defer e.mu.RUnlock() - - err := errors.New("not implemented") - span.RecordError(err) - return err -} - -func (e *EventStore) loadFromFile() error { - if _, err := os.Stat(e.filename); os.IsNotExist(err) { - // File does not exist, no guests to load - return nil - } - - fileData, err := os.ReadFile(e.filename) - if err != nil { - return err - } - - e.mu.Lock() - defer e.mu.Unlock() - - return json.Unmarshal(fileData, &e.event) -} - -func createDemoEvent() *model.Event { - return &model.Event{ - Location: &model.Location{ - ID: uuid.MustParse("851ec3b7-f4ce-4319-96f9-67cc755b06ec"), - Name: "Party location", - ZipCode: "1337", - Street: "Milky Way", - StreetNumber: "42", - City: "Somewhere", - Country: "Germany", - Longitude: 106.6333, - Latitude: 10.8167, - }, - Hotels: []*model.Location{ - { - ID: uuid.MustParse("4e657dd1-2f75-48c7-ac87-1d3da0cc9b93"), - Name: "Demo Hotel 1", - ZipCode: "1337", - Street: "Milky Way", - StreetNumber: "42", - City: "Somewhere", - Country: "Germany", - Longitude: 106.6333, - Latitude: 10.8167, - }, - }, - Airports: []*model.Location{ - { - ID: uuid.MustParse("4716775f-575d-4524-a0bb-20630cb017b4"), - Name: "Demo Airport 1", - ZipCode: "1337", - Street: "Milky Way", - StreetNumber: "42", - City: "Somewhere", - Country: "Germany", - Longitude: 106.6333, - Latitude: 10.8167, - }, - }, - Date: time.Date(2023, 12, 24, 0, 0, 0, 0, time.Local), - } -} diff --git a/internal/db/jsondb/guest_store.go b/internal/db/jsondb/guest_store.go deleted file mode 100644 index 5ee5858..0000000 --- a/internal/db/jsondb/guest_store.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (C) 2024 the lets-party maintainers -// See root-dir/LICENSE for more information - -package jsondb - -import ( - "context" - "encoding/json" - "errors" - "os" - "sync" - "time" - - "github.com/google/uuid" - "go.opentelemetry.io/otel/trace" - - "github.com/quixsi/core/internal/model" -) - -// GuestStore is an implementation of the GuestStore interface -// that stores guest data in a JSON file. -type GuestStore struct { - filename string - mu sync.RWMutex - guests map[uuid.UUID]*model.Guest -} - -// NewGuestStoreFile creates a new GuestStore instance. -func NewGuestStore(filename string) (*GuestStore, error) { - store := &GuestStore{ - filename: filename, - guests: make(map[uuid.UUID]*model.Guest), - } - - if err := store.loadFromFile(); err != nil { - return nil, err - } - return store, nil -} - -// CreateGuest adds a new guest to the store and stores it in the JSON file. -func (g *GuestStore) CreateGuest(ctx context.Context, guest *model.Guest) (uuid.UUID, error) { - var span trace.Span - ctx, span = tracer.Start(ctx, "CreateGuest") - defer span.End() - - span.AddEvent("Lock") - g.mu.Lock() - defer span.AddEvent("Unlock") - defer g.mu.Unlock() - - if guest.ID == uuid.Nil { - guest.ID = uuid.New() - } - - span.AddEvent("check if guest exists") - // Add the guest to the store - if _, ok := g.guests[guest.ID]; ok { - err := errors.New("guest already exists") - span.RecordError(err) - return uuid.Nil, err - } - span.AddEvent("create new guest") - now := time.Now() - guest.CreatedAt = &now - g.guests[guest.ID] = guest - - span.AddEvent("save to file") - // Save the updated store to the JSON file - if err := g.saveToFile(ctx); err != nil { - return uuid.Nil, err - } - - return guest.ID, nil -} - -// UpdateGuest updates an existing guest's information in the store and JSON file. -func (g *GuestStore) UpdateGuest(ctx context.Context, guest *model.Guest) error { - var span trace.Span - ctx, span = tracer.Start(ctx, "UpdateGuest") - defer span.End() - - if guest.ID == uuid.Nil { - err := errors.New("guest ID is required for updating") - span.RecordError(err) - return err - } - - span.AddEvent("Lock") - g.mu.Lock() - defer span.AddEvent("Unlock") - defer g.mu.Unlock() - - // Check if the guest exists in the store - if _, ok := g.guests[guest.ID]; !ok { - err := errors.New("guest not found") - span.RecordError(err) - return err - } - - now := time.Now() - guest.UpdatedAt = &now - // Update the guest in the store - g.guests[guest.ID] = guest - - // Save the updated store to the JSON file - if err := g.saveToFile(ctx); err != nil { - return err - } - - return nil -} - -// ListGuests returns a list of all guests in the store. -func (g *GuestStore) ListGuests(ctx context.Context) ([]*model.Guest, error) { - var span trace.Span - _, span = tracer.Start(ctx, "ListGuests") - defer span.End() - - span.AddEvent("Lock") - g.mu.RLock() - defer span.AddEvent("Unlock") - defer g.mu.RUnlock() - - guestList := make([]*model.Guest, 0, len(g.guests)) - for _, guest := range g.guests { - guestList = append(guestList, guest) - } - - return guestList, nil -} - -// GetGuestByID retrieves a guest by ID from the store. -func (g *GuestStore) GetGuestByID(ctx context.Context, id uuid.UUID) (*model.Guest, error) { - var span trace.Span - _, span = tracer.Start(ctx, "GetGuestByID") - defer span.End() - - span.AddEvent("RLock") - g.mu.RLock() - defer span.AddEvent("RUnlock") - defer g.mu.RUnlock() - - guest, ok := g.guests[id] - if !ok { - err := errors.New("guest not found") - span.RecordError(err) - return nil, err - } - - return guest, nil -} - -// saveToFile saves the current guest store to the JSON file. -func (g *GuestStore) saveToFile(ctx context.Context) error { - var span trace.Span - _, span = tracer.Start(ctx, "SaveToFile") - defer span.End() - - fileData, err := json.MarshalIndent(g.guests, "", " ") - if err != nil { - span.RecordError(err) - return err - } - - err = os.WriteFile(g.filename, fileData, 0644) - if err != nil { - span.RecordError(err) - return err - } - return nil -} - -// loadFromFile loads guest data from the JSON file into the store. -func (g *GuestStore) loadFromFile() error { - if _, err := os.Stat(g.filename); os.IsNotExist(err) { - // File does not exist, no guests to load - return nil - } - - fileData, err := os.ReadFile(g.filename) - if err != nil { - return err - } - - g.mu.Lock() - defer g.mu.Unlock() - - return json.Unmarshal(fileData, &g.guests) -} - -// DeleteGuest deletes an existing guest in the store and JSON file. -func (g *GuestStore) DeleteGuest(ctx context.Context, guestID uuid.UUID) error { - var span trace.Span - _, span = tracer.Start(ctx, "DeleteGuest") - defer span.End() - - if guestID == uuid.Nil { - err := errors.New("guest ID is required for updating") - span.RecordError(err) - return err - } - - span.AddEvent("Lock") - g.mu.Lock() - defer span.AddEvent("RUnlock") - defer g.mu.Unlock() - - // Check if the guest exists in the store - guest, ok := g.guests[guestID] - if !ok { - err := errors.New("guest not found") - span.RecordError(err) - return err - } - - if !guest.Deleteable { - err := errors.New("guest can not be deleted") - span.RecordError(err) - return err - } - - // Delete the guest from the store - delete(g.guests, guestID) - - // Save the updated store to the JSON file - if err := g.saveToFile(ctx); err != nil { - return err - } - - return nil -} diff --git a/internal/db/jsondb/invitation_store.go b/internal/db/jsondb/invitation_store.go deleted file mode 100644 index 5a2427e..0000000 --- a/internal/db/jsondb/invitation_store.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (C) 2024 the lets-party maintainers -// See root-dir/LICENSE for more information - -package jsondb - -import ( - "context" - "encoding/json" - "fmt" - "os" - "sync" - - "github.com/google/uuid" - "go.opentelemetry.io/otel/trace" - - "github.com/quixsi/core/internal/model" -) - -func NewInvitationStore(filename string) (*InvitationStore, error) { - store := &InvitationStore{ - invitations: make(map[uuid.UUID][]uuid.UUID), - filename: filename, - } - - if err := store.loadFromFile(); err != nil { - return nil, err - } - return store, nil -} - -type InvitationStore struct { - mu sync.RWMutex - invitations map[uuid.UUID][]uuid.UUID - filename string -} - -func (i *InvitationStore) GetInvitationByID(ctx context.Context, inviteID uuid.UUID) (*model.Invitation, error) { - var span trace.Span - _, span = tracer.Start(ctx, "GetInvitationByID") - defer span.End() - - span.AddEvent("RLock") - i.mu.RLock() - defer span.AddEvent("RUnlock") - defer i.mu.RUnlock() - - guestIDs, ok := i.invitations[inviteID] - if !ok { - err := fmt.Errorf("could not find invite with id: %s", inviteID) - span.RecordError(err) - return nil, err - } - return &model.Invitation{ - ID: inviteID, - GuestIDs: guestIDs, - }, nil -} - -func (i *InvitationStore) CreateInvitation(ctx context.Context, guestIDs ...uuid.UUID) (*model.Invitation, error) { - var span trace.Span - ctx, span = tracer.Start(ctx, "CreateInvitation") - defer span.End() - - span.AddEvent("Lock") - i.mu.Lock() - defer span.AddEvent("Unlock") - defer i.mu.Unlock() - id := uuid.New() - if _, ok := i.invitations[id]; ok { - err := fmt.Errorf("cannot create invitation, uuid already exists") - span.RecordError(err) - return nil, err - } - i.invitations[id] = guestIDs - if err := i.saveToFile(ctx); err != nil { - return nil, err - } - return &model.Invitation{ - ID: id, - GuestIDs: guestIDs, - }, nil -} - -func (i *InvitationStore) UpdateInvitation(ctx context.Context, invite *model.Invitation) error { - var span trace.Span - ctx, span = tracer.Start(ctx, "UpdateInvitation") - defer span.End() - - span.AddEvent("Lock") - i.mu.Lock() - defer span.AddEvent("Unlock") - defer i.mu.Unlock() - - if _, ok := i.invitations[invite.ID]; !ok { - err := fmt.Errorf("could not find invite") - span.RecordError(err) - return err - } - i.invitations[invite.ID] = invite.GuestIDs - if err := i.saveToFile(ctx); err != nil { - return err - } - return nil -} - -func (i *InvitationStore) ListInvitations(ctx context.Context) ([]*model.Invitation, error) { - var span trace.Span - _, span = tracer.Start(ctx, "ListInvitations") - defer span.End() - - span.AddEvent("RLock") - i.mu.RLock() - defer span.AddEvent("RUnlock") - defer i.mu.RUnlock() - - var res []*model.Invitation - for inviteID, guestIDs := range i.invitations { - res = append(res, &model.Invitation{ - ID: inviteID, - GuestIDs: guestIDs, - }) - } - return res, nil -} - -// saveToFile saves the current invitation store to the JSON file. -func (i *InvitationStore) saveToFile(ctx context.Context) error { - var span trace.Span - _, span = tracer.Start(ctx, "SaveToFile") - defer span.End() - - fileData, err := json.MarshalIndent(i.invitations, "", " ") - if err != nil { - span.RecordError(err) - return err - } - - err = os.WriteFile(i.filename, fileData, 0644) - if err != nil { - span.RecordError(err) - return err - } - return nil -} - -// loadFromFile loads invitation data from the JSON file into the store. -func (i *InvitationStore) loadFromFile() error { - if _, err := os.Stat(i.filename); os.IsNotExist(err) { - // File does not exist, no invitations to load - return nil - } - - fileData, err := os.ReadFile(i.filename) - if err != nil { - return err - } - - i.mu.Lock() - defer i.mu.Unlock() - - return json.Unmarshal(fileData, &i.invitations) -} diff --git a/internal/db/jsondb/tracing.go b/internal/db/jsondb/tracing.go deleted file mode 100644 index 719f1d7..0000000 --- a/internal/db/jsondb/tracing.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (C) 2024 the lets-party maintainers -// See root-dir/LICENSE for more information - -package jsondb - -import "go.opentelemetry.io/otel" - -var tracer = otel.GetTracerProvider().Tracer("github.com/quixsi/core/internal/db/jsondb") diff --git a/internal/db/jsondb/translation_store.go b/internal/db/jsondb/translation_store.go deleted file mode 100644 index 5307099..0000000 --- a/internal/db/jsondb/translation_store.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (C) 2024 the lets-party maintainers -// See root-dir/LICENSE for more information - -package jsondb - -import ( - "context" - "encoding/json" - "errors" - "os" - "sort" - "sync" - - "go.opentelemetry.io/otel/trace" - - "github.com/quixsi/core/internal/model" -) - -func NewTranslationStore(filename string) (*TranslationStore, error) { - store := &TranslationStore{ - filename: filename, - byLanguage: make(map[string]model.Translation), - } - if err := store.loadFromFile(); err != nil { - return nil, err - } - return store, nil -} - -type TranslationStore struct { - mu sync.RWMutex - - filename string - byLanguage map[string]model.Translation -} - -func (t *TranslationStore) ListLanguages(ctx context.Context) ([]string, error) { - var span trace.Span - _, span = tracer.Start(ctx, "ListLanguages") - defer span.End() - - span.AddEvent("Lock") - t.mu.Lock() - defer span.AddEvent("RUlock") - defer t.mu.Unlock() - - res := make([]string, len(t.byLanguage)) - i := 0 - for lang := range t.byLanguage { - res[i] = lang - i++ - } - sort.Slice(res, func(i, j int) bool { return res[i] < res[j] }) - return res, nil -} - -func (t *TranslationStore) ByLanguage(ctx context.Context, l string) (*model.Translation, error) { - var span trace.Span - _, span = tracer.Start(ctx, "ByLanguage") - defer span.End() - - span.AddEvent("RLock") - t.mu.RLock() - defer span.AddEvent("RUnlock") - defer t.mu.RUnlock() - - lang, ok := t.byLanguage[l] - if !ok { - err := errors.New("missing translation") - span.RecordError(err) - return nil, err - } - return &lang, nil -} - -func (t *TranslationStore) loadFromFile() error { - if _, err := os.Stat(t.filename); os.IsNotExist(err) { - // File does not exist, no guests to load - return nil - } - - fileData, err := os.ReadFile(t.filename) - if err != nil { - return err - } - - t.mu.Lock() - defer t.mu.Unlock() - - return json.Unmarshal(fileData, &t.byLanguage) -} - -func (t *TranslationStore) CreateLanguage(context.Context, string, *model.Translation) error { - return errors.New("not implemented") -} - -func (t *TranslationStore) UpdateLanguages(context.Context, map[string]*model.Translation) error { - return errors.New("not implemented") -} diff --git a/testdata/event.json b/testdata/event.json deleted file mode 100644 index 6987c3d..0000000 --- a/testdata/event.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "id": "b0efa7fc-be99-4f5b-9fe8-1cd6cf6dd443", - "created_at": null, - "updated_at": null, - "created_at": null, - "name": "Party location", - "country": "Germany", - "city": "Somewhere", - "zipcode": "1337", - "street": "Milky Way", - "street_number": "42", - "longitude": 106.6333, - "latitude": 10.8167, - "date": "2023-12-24T00:00:00+01:00", - "hotels": [ - { - "id": "7df4cf65-abbf-4ff6-9b81-88250c5e992c", - "created_at": null, - "name": "Demo Hotel 1", - "country": "Germany", - "city": "Somewhere", - "zipcode": "1337", - "street": "Milky Way", - "street_number": "42", - "longitude": 106.6333, - "latitude": 10.8167, - "website": "https://booking.com" - } - ], - "airports": [ - { - "id": "5b95def0-2190-4533-ba27-15d5322eda32", - "created_at": null, - "name": "Demo Airport 1", - "country": "Germany", - "city": "Somewhere", - "zipcode": "1337", - "street": "Milky Way", - "street_number": "42", - "longitude": 106.6333, - "latitude": 10.8167 - } - ] -} diff --git a/testdata/guests.json b/testdata/guests.json deleted file mode 100644 index fe443ff..0000000 --- a/testdata/guests.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "39a502ac-ba10-430d-99ac-e0955eccb73b": { - "id": "39a502ac-ba10-430d-99ac-e0955eccb73b", - "deleteable": false, - "created_at": "2023-09-10T16:55:04.061919457+02:00", - "updated_at": "2024-01-10T21:47:42.218390865+01:00", - "firstname": "Mad", - "lastname": "Max", - "age_category": 3, - "dietary_category": 3, - "invitation_status": 1 - }, - "42a7b4d3-25c6-431f-8930-f611c16103e6": { - "id": "42a7b4d3-25c6-431f-8930-f611c16103e6", - "deleteable": false, - "created_at": "2023-09-10T16:55:04.061919457+02:00", - "updated_at": "2024-01-10T21:47:42.217509548+01:00", - "firstname": "Serious", - "lastname": "Sam", - "age_category": 2, - "dietary_category": 1, - "invitation_status": 1 - }, - "e2153062-d244-42b7-9d7e-4b0af64a672f": { - "id": "e2153062-d244-42b7-9d7e-4b0af64a672f", - "deleteable": true, - "created_at": "2024-01-10T21:47:25.837469879+01:00", - "updated_at": "2024-01-10T21:47:42.216605583+01:00", - "firstname": "Torben", - "lastname": "L", - "age_category": 0, - "dietary_category": 0, - "invitation_status": 0 - } -} diff --git a/testdata/invitations.json b/testdata/invitations.json deleted file mode 100644 index c1bb9cf..0000000 --- a/testdata/invitations.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "ba20785f-8c7b-442e-935a-1cb58c41b92a": [ - "42a7b4d3-25c6-431f-8930-f611c16103e6", - "39a502ac-ba10-430d-99ac-e0955eccb73b", - "e2153062-d244-42b7-9d7e-4b0af64a672f" - ] -} diff --git a/testdata/translations.json b/testdata/translations.json deleted file mode 100644 index 21539f0..0000000 --- a/testdata/translations.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "en": { - "title": "Party of Jamcan Pimpleworthy", - "flag_img_src": "data:image/png;base64,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", - "greeting": "Hello {{range $val := .}}{{$val.Firstname}} {{end}}!", - "welcome_message": "Welcome to our website.", - "error": { - "title": "Oh no, an error occurred!", - "process": "Unfortunately, we were unable to process your request. Please try again and let us know if the error still occurs.", - "deadline": "Unfortunately, we were unable to process your request as the deadline for adjustments has already expired." - }, - "success": { - "title": "🎉 Success 🎉" - }, - "guest_form": { - "label_input_firstname": "Firstname", - "label_input_lastname": "Lastname", - "label_select_diet": "Diet", - "label_select_age": "Age", - "label_select_inv_status": "State", - "label_button_add_guest": "Add Guest", - "label_button_submit": "Submit", - "select_options_diet": ["Unknown", "Vegan", "Vegetarian", "Omnivore"], - "select_options_inv_status": ["Unknown", "Accepted", "Rejected"], - "select_options_age": ["Unknown", "0 to 5", "6 to 17", "18+"], - "message_submit_success": "Thank you for your answer." - }, - "location": { - "title": "Map", - "openExternally": "View Larger Map" - }, - "hotels": { - "title": "Hotels", - "website": "Check website" - }, - "airports": { - "title": "Airports" - }, - "navigation": { - "guests": "Guests", - "map": "Map", - "hotels": "Hotels", - "airports": "Airports" - }, - "and": "and" - }, - "de": { - "close": "Schließen", - "title": "Party von Jamcan Pimpleworthy", - "flag_img_src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAK4AAACCCAMAAADovAORAAAAFVBMVEUAAAD/zgDdAAC4AADhAADmaAD/2QDBEdIQAAAAgElEQVR4nO3OOQ3AAAwAsfTlD7kUutwQyUbgGQAAAAAAAAD+u1aZe5U5V9Et6ZZ0S7ol3ZJuSbekW9It6ZZ0S7ol3ZJuSbekW9It6ZZ0S7qleVaZd5U5VtEt6ZZ0S7ol3ZJuSbekW9It6ZZ0S7ol3ZJuSbekW9It6ZZ0S7qlZd0PXPFghbx3mecAAAAASUVORK5CYII=", - "greeting": "Hallo {{range $val := .}}{{$val.Firstname}} {{end}}!", - "welcome_message": "Guten Tag!", - "error": { - "title": "Oh nein, ein Fehler ist aufgetreten!", - "process": "Leider konnten wir Deine Anfrage nicht bearbeiten. Bitte versuche es erneut und teile uns mit, wenn der Fehler weiterhin auftritt.", - "deadline": "Leider konnten wir Deine Anfrage nicht bearbeiten, da die Frist für Anpassungen bereits abgelaufen ist." - }, - "success": { - "title": "🎉 Geschafft 🎉" - }, - "guest_form": { - "label_input_firstname": "Vorname", - "label_input_lastname": "Nachname", - "label_select_diet": "Ernährung", - "label_select_age": "Altersgruppe", - "label_select_inv_status": "Status", - "label_button_add_guest": "Gast Hinzufügen", - "label_button_submit": "Abschicken", - "select_options_diet": ["Unknown", "Vegan", "Vegetarisch", "Omnivor"], - "select_options_inv_status": ["Unknown", "Angenommen", "Abgelehnt"], - "select_options_age": ["Unknown", "0 bis 5", "6 bis 17", "18+"], - "message_submit_success": "Vielen Dank für deine Antwort." - }, - "location": { - "title": "Karte", - "openExternally": "Größere Ansicht" - }, - "hotels": { - "title": "Hotels", - "website": "Zur Webseite gehen" - }, - "airports": { - "title": "Flughäfen" - }, - "navigation": { - "guests": "Gäste", - "map": "Karte", - "hotels": "Hotels", - "airports": "Flughäfen" - }, - "and": "und" - } -}