diff --git a/backend/app/api/handlers/v1/controller.go b/backend/app/api/handlers/v1/controller.go index 2c41bc1..442a34d 100644 --- a/backend/app/api/handlers/v1/controller.go +++ b/backend/app/api/handlers/v1/controller.go @@ -3,6 +3,7 @@ package v1 import ( "net/http" + "github.com/hay-kot/homebox/backend/internal/repo" "github.com/hay-kot/homebox/backend/internal/services" "github.com/hay-kot/homebox/backend/pkgs/server" ) @@ -26,6 +27,7 @@ func WithRegistration(allowRegistration bool) func(*V1Controller) { } type V1Controller struct { + repo *repo.AllRepos svc *services.AllServices maxUploadSize int64 isDemo bool @@ -57,8 +59,9 @@ func BaseUrlFunc(prefix string) func(s string) string { } } -func NewControllerV1(svc *services.AllServices, options ...func(*V1Controller)) *V1Controller { +func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, options ...func(*V1Controller)) *V1Controller { ctrl := &V1Controller{ + repo: repos, svc: svc, allowRegistration: true, } diff --git a/backend/app/api/handlers/v1/v1_ctrl_items.go b/backend/app/api/handlers/v1/v1_ctrl_items.go index 84591ca..42d20c1 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items.go @@ -61,7 +61,7 @@ func (ctrl *V1Controller) HandleItemsGetAll() server.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { ctx := services.NewContext(r.Context()) - items, err := ctrl.svc.Items.Query(ctx, extractQuery(r)) + items, err := ctrl.repo.Items.QueryByGroup(ctx, ctx.GID, extractQuery(r)) if err != nil { log.Err(err).Msg("failed to get items") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -87,7 +87,7 @@ func (ctrl *V1Controller) HandleItemsCreate() server.HandlerFunc { } user := services.UseUserCtx(r.Context()) - item, err := ctrl.svc.Items.Create(r.Context(), user.GroupID, createData) + item, err := ctrl.repo.Items.Create(r.Context(), user.GroupID, createData) if err != nil { log.Err(err).Msg("failed to create item") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -144,14 +144,14 @@ func (ctrl *V1Controller) handleItemsGeneral() server.HandlerFunc { switch r.Method { case http.MethodGet: - items, err := ctrl.svc.Items.GetOne(r.Context(), ctx.GID, ID) + items, err := ctrl.repo.Items.GetOneByGroup(r.Context(), ctx.GID, ID) if err != nil { log.Err(err).Msg("failed to get item") return validate.NewRequestError(err, http.StatusInternalServerError) } return server.Respond(w, http.StatusOK, items) case http.MethodDelete: - err = ctrl.svc.Items.Delete(r.Context(), ctx.GID, ID) + err = ctrl.repo.Items.DeleteByGroup(r.Context(), ctx.GID, ID) if err != nil { log.Err(err).Msg("failed to delete item") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -164,7 +164,7 @@ func (ctrl *V1Controller) handleItemsGeneral() server.HandlerFunc { return validate.NewRequestError(err, http.StatusInternalServerError) } body.ID = ID - result, err := ctrl.svc.Items.Update(r.Context(), ctx.GID, body) + result, err := ctrl.repo.Items.UpdateByGroup(r.Context(), ctx.GID, body) if err != nil { log.Err(err).Msg("failed to update item") return validate.NewRequestError(err, http.StatusInternalServerError) diff --git a/backend/app/api/handlers/v1/v1_ctrl_labels.go b/backend/app/api/handlers/v1/v1_ctrl_labels.go index f02a929..71edddd 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_labels.go +++ b/backend/app/api/handlers/v1/v1_ctrl_labels.go @@ -21,7 +21,7 @@ import ( func (ctrl *V1Controller) HandleLabelsGetAll() server.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { user := services.UseUserCtx(r.Context()) - labels, err := ctrl.svc.Labels.GetAll(r.Context(), user.GroupID) + labels, err := ctrl.repo.Labels.GetAll(r.Context(), user.GroupID) if err != nil { log.Err(err).Msg("error getting labels") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -47,7 +47,7 @@ func (ctrl *V1Controller) HandleLabelsCreate() server.HandlerFunc { } user := services.UseUserCtx(r.Context()) - label, err := ctrl.svc.Labels.Create(r.Context(), user.GroupID, createData) + label, err := ctrl.repo.Labels.Create(r.Context(), user.GroupID, createData) if err != nil { log.Err(err).Msg("error creating label") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -103,7 +103,7 @@ func (ctrl *V1Controller) handleLabelsGeneral() server.HandlerFunc { switch r.Method { case http.MethodGet: - labels, err := ctrl.svc.Labels.Get(r.Context(), ctx.GID, ID) + labels, err := ctrl.repo.Labels.GetOneByGroup(r.Context(), ctx.GID, ID) if err != nil { if ent.IsNotFound(err) { log.Err(err). @@ -117,7 +117,7 @@ func (ctrl *V1Controller) handleLabelsGeneral() server.HandlerFunc { return server.Respond(w, http.StatusOK, labels) case http.MethodDelete: - err = ctrl.svc.Labels.Delete(r.Context(), ctx.GID, ID) + err = ctrl.repo.Labels.DeleteByGroup(ctx, ctx.GID, ID) if err != nil { log.Err(err).Msg("error deleting label") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -127,14 +127,12 @@ func (ctrl *V1Controller) handleLabelsGeneral() server.HandlerFunc { case http.MethodPut: body := repo.LabelUpdate{} if err := server.Decode(r, &body); err != nil { - log.Err(err).Msg("error decoding label update data") return validate.NewRequestError(err, http.StatusInternalServerError) } body.ID = ID - result, err := ctrl.svc.Labels.Update(r.Context(), ctx.GID, body) + result, err := ctrl.repo.Labels.UpdateByGroup(ctx, ctx.GID, body) if err != nil { - log.Err(err).Msg("error updating label") return validate.NewRequestError(err, http.StatusInternalServerError) } return server.Respond(w, http.StatusOK, result) diff --git a/backend/app/api/handlers/v1/v1_ctrl_locations.go b/backend/app/api/handlers/v1/v1_ctrl_locations.go index 775cf76..07edd0b 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_locations.go +++ b/backend/app/api/handlers/v1/v1_ctrl_locations.go @@ -21,7 +21,7 @@ import ( func (ctrl *V1Controller) HandleLocationGetAll() server.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { user := services.UseUserCtx(r.Context()) - locations, err := ctrl.svc.Location.GetAll(r.Context(), user.GroupID) + locations, err := ctrl.repo.Locations.GetAll(r.Context(), user.GroupID) if err != nil { log.Err(err).Msg("failed to get locations") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -48,7 +48,7 @@ func (ctrl *V1Controller) HandleLocationCreate() server.HandlerFunc { } user := services.UseUserCtx(r.Context()) - location, err := ctrl.svc.Location.Create(r.Context(), user.GroupID, createData) + location, err := ctrl.repo.Locations.Create(r.Context(), user.GroupID, createData) if err != nil { log.Err(err).Msg("failed to create location") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -105,7 +105,7 @@ func (ctrl *V1Controller) handleLocationGeneral() server.HandlerFunc { switch r.Method { case http.MethodGet: - location, err := ctrl.svc.Location.GetOne(r.Context(), ctx.GID, ID) + location, err := ctrl.repo.Locations.GetOneByGroup(r.Context(), ctx.GID, ID) if err != nil { l := log.Err(err). Str("ID", ID.String()). @@ -129,14 +129,14 @@ func (ctrl *V1Controller) handleLocationGeneral() server.HandlerFunc { body.ID = ID - result, err := ctrl.svc.Location.Update(r.Context(), ctx.GID, body) + result, err := ctrl.repo.Locations.UpdateOneByGroup(r.Context(), ctx.GID, ID, body) if err != nil { log.Err(err).Msg("failed to update location") return validate.NewRequestError(err, http.StatusInternalServerError) } return server.Respond(w, http.StatusOK, result) case http.MethodDelete: - err = ctrl.svc.Location.Delete(r.Context(), ctx.GID, ID) + err = ctrl.repo.Locations.DeleteByGroup(r.Context(), ctx.GID, ID) if err != nil { log.Err(err).Msg("failed to delete location") return validate.NewRequestError(err, http.StatusInternalServerError) diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index 02a7f74..13c7aa6 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -49,6 +49,7 @@ func (a *app) mountRoutes(repos *repo.AllRepos) { v1Ctrl := v1.NewControllerV1( a.services, + a.repos, v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize), v1.WithRegistration(a.conf.AllowRegistration), v1.WithDemoStatus(a.conf.Demo), // Disable Password Change in Demo Mode diff --git a/backend/internal/repo/repo_labels.go b/backend/internal/repo/repo_labels.go index b899d68..165f12e 100644 --- a/backend/internal/repo/repo_labels.go +++ b/backend/internal/repo/repo_labels.go @@ -106,13 +106,30 @@ func (r *LabelRepository) Create(ctx context.Context, groupdId uuid.UUID, data L return mapLabelOut(label), err } -func (r *LabelRepository) Update(ctx context.Context, data LabelUpdate) (LabelOut, error) { - _, err := r.db.Label.UpdateOneID(data.ID). +func (r *LabelRepository) update(ctx context.Context, data LabelUpdate, where ...predicate.Label) (int, error) { + if len(where) == 0 { + panic("empty where not supported empty") + } + + return r.db.Label.Update(). + Where(where...). SetName(data.Name). SetDescription(data.Description). SetColor(data.Color). Save(ctx) +} +func (r *LabelRepository) Update(ctx context.Context, data LabelUpdate) (LabelOut, error) { + _, err := r.update(ctx, data, label.ID(data.ID)) + if err != nil { + return LabelOut{}, err + } + + return r.GetOne(ctx, data.ID) +} + +func (r *LabelRepository) UpdateByGroup(ctx context.Context, GID uuid.UUID, data LabelUpdate) (LabelOut, error) { + _, err := r.update(ctx, data, label.ID(data.ID), label.HasGroupWith(group.ID(GID))) if err != nil { return LabelOut{}, err } @@ -123,3 +140,13 @@ func (r *LabelRepository) Update(ctx context.Context, data LabelUpdate) (LabelOu func (r *LabelRepository) Delete(ctx context.Context, id uuid.UUID) error { return r.db.Label.DeleteOneID(id).Exec(ctx) } + +func (r *LabelRepository) DeleteByGroup(ctx context.Context, gid, id uuid.UUID) error { + _, err := r.db.Label.Delete(). + Where( + label.ID(id), + label.HasGroupWith(group.ID(gid)), + ).Exec(ctx) + + return err +} diff --git a/backend/internal/repo/repo_locations.go b/backend/internal/repo/repo_locations.go index f927431..8dbc93d 100644 --- a/backend/internal/repo/repo_locations.go +++ b/backend/internal/repo/repo_locations.go @@ -154,23 +154,24 @@ func (r *LocationRepository) GetOneByGroup(ctx context.Context, GID, ID uuid.UUI return r.getOne(ctx, location.ID(ID), location.HasGroupWith(group.ID(GID))) } -func (r *LocationRepository) Create(ctx context.Context, gid uuid.UUID, data LocationCreate) (LocationOut, error) { +func (r *LocationRepository) Create(ctx context.Context, GID uuid.UUID, data LocationCreate) (LocationOut, error) { location, err := r.db.Location.Create(). SetName(data.Name). SetDescription(data.Description). - SetGroupID(gid). + SetGroupID(GID). Save(ctx) if err != nil { return LocationOut{}, err } - location.Edges.Group = &ent.Group{ID: gid} // bootstrap group ID + location.Edges.Group = &ent.Group{ID: GID} // bootstrap group ID return mapLocationOut(location), nil } -func (r *LocationRepository) Update(ctx context.Context, data LocationUpdate) (LocationOut, error) { - q := r.db.Location.UpdateOneID(data.ID). +func (r *LocationRepository) update(ctx context.Context, data LocationUpdate, where ...predicate.Location) (LocationOut, error) { + q := r.db.Location.Update(). + Where(where...). SetName(data.Name). SetDescription(data.Description) @@ -181,7 +182,6 @@ func (r *LocationRepository) Update(ctx context.Context, data LocationUpdate) (L } _, err := q.Save(ctx) - if err != nil { return LocationOut{}, err } @@ -189,6 +189,19 @@ func (r *LocationRepository) Update(ctx context.Context, data LocationUpdate) (L return r.Get(ctx, data.ID) } -func (r *LocationRepository) Delete(ctx context.Context, id uuid.UUID) error { - return r.db.Location.DeleteOneID(id).Exec(ctx) +func (r *LocationRepository) Update(ctx context.Context, data LocationUpdate) (LocationOut, error) { + return r.update(ctx, data, location.ID(data.ID)) +} + +func (r *LocationRepository) UpdateOneByGroup(ctx context.Context, GID, ID uuid.UUID, data LocationUpdate) (LocationOut, error) { + return r.update(ctx, data, location.ID(ID), location.HasGroupWith(group.ID(GID))) +} + +func (r *LocationRepository) Delete(ctx context.Context, ID uuid.UUID) error { + return r.db.Location.DeleteOneID(ID).Exec(ctx) +} + +func (r *LocationRepository) DeleteByGroup(ctx context.Context, GID, ID uuid.UUID) error { + _, err := r.db.Location.Delete().Where(location.ID(ID), location.HasGroupWith(group.ID(GID))).Exec(ctx) + return err } diff --git a/backend/internal/services/all.go b/backend/internal/services/all.go index 20e377f..d87738a 100644 --- a/backend/internal/services/all.go +++ b/backend/internal/services/all.go @@ -3,11 +3,9 @@ package services import "github.com/hay-kot/homebox/backend/internal/repo" type AllServices struct { - User *UserService - Group *GroupService - Location *LocationService - Labels *LabelService - Items *ItemService + User *UserService + Group *GroupService + Items *ItemService } func New(repos *repo.AllRepos) *AllServices { @@ -16,10 +14,8 @@ func New(repos *repo.AllRepos) *AllServices { } return &AllServices{ - User: &UserService{repos}, - Group: &GroupService{repos}, - Location: &LocationService{repos}, - Labels: &LabelService{repos}, + User: &UserService{repos}, + Group: &GroupService{repos}, Items: &ItemService{ repo: repos, at: attachmentTokens{}, diff --git a/backend/internal/services/service_items.go b/backend/internal/services/service_items.go index 7650a97..df5fe0d 100644 --- a/backend/internal/services/service_items.go +++ b/backend/internal/services/service_items.go @@ -23,30 +23,6 @@ type ItemService struct { at attachmentTokens } -func (svc *ItemService) GetOne(ctx context.Context, gid uuid.UUID, id uuid.UUID) (repo.ItemOut, error) { - return svc.repo.Items.GetOneByGroup(ctx, gid, id) -} - -func (svc *ItemService) Query(ctx Context, q repo.ItemQuery) (repo.PaginationResult[repo.ItemSummary], error) { - return svc.repo.Items.QueryByGroup(ctx, ctx.GID, q) -} - -func (svc *ItemService) GetAll(ctx context.Context, gid uuid.UUID) ([]repo.ItemSummary, error) { - return svc.repo.Items.GetAll(ctx, gid) -} - -func (svc *ItemService) Create(ctx context.Context, gid uuid.UUID, data repo.ItemCreate) (repo.ItemOut, error) { - return svc.repo.Items.Create(ctx, gid, data) -} - -func (svc *ItemService) Delete(ctx context.Context, gid uuid.UUID, id uuid.UUID) error { - return svc.repo.Items.DeleteByGroup(ctx, gid, id) -} - -func (svc *ItemService) Update(ctx context.Context, gid uuid.UUID, data repo.ItemUpdate) (repo.ItemOut, error) { - return svc.repo.Items.UpdateByGroup(ctx, gid, data) -} - func (svc *ItemService) CsvImport(ctx context.Context, gid uuid.UUID, data [][]string) (int, error) { loaded := []csvRow{} diff --git a/backend/internal/services/service_items_attachments.go b/backend/internal/services/service_items_attachments.go index 0f2afde..5954d33 100644 --- a/backend/internal/services/service_items_attachments.go +++ b/backend/internal/services/service_items_attachments.go @@ -91,7 +91,7 @@ func (svc *ItemService) AttachmentUpdate(ctx Context, itemId uuid.UUID, data *re return repo.ItemOut{}, err } - return svc.GetOne(ctx, ctx.GID, itemId) + return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId) } // AttachmentAdd adds an attachment to an item by creating an entry in the Documents table and linking it to the Attachment @@ -118,7 +118,7 @@ func (svc *ItemService) AttachmentAdd(ctx Context, itemId uuid.UUID, filename st return repo.ItemOut{}, err } - return svc.GetOne(ctx, ctx.GID, itemId) + return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId) } func (svc *ItemService) AttachmentDelete(ctx context.Context, gid, itemId, attachmentId uuid.UUID) error { diff --git a/backend/internal/services/service_items_attachments_test.go b/backend/internal/services/service_items_attachments_test.go index c3ab032..c90c1df 100644 --- a/backend/internal/services/service_items_attachments_test.go +++ b/backend/internal/services/service_items_attachments_test.go @@ -19,7 +19,7 @@ func TestItemService_AddAttachment(t *testing.T) { filepath: temp, } - loc, err := tSvc.Location.Create(context.Background(), tGroup.ID, repo.LocationCreate{ + loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, repo.LocationCreate{ Description: "test", Name: "test", }) @@ -32,7 +32,7 @@ func TestItemService_AddAttachment(t *testing.T) { LocationID: loc.ID, } - itm, err := svc.Create(context.Background(), tGroup.ID, itmC) + itm, err := svc.repo.Items.Create(context.Background(), tGroup.ID, itmC) assert.NoError(t, err) assert.NotNil(t, itm) t.Cleanup(func() { diff --git a/backend/internal/services/service_items_test.go b/backend/internal/services/service_items_test.go index 018dbc1..1daa0b7 100644 --- a/backend/internal/services/service_items_test.go +++ b/backend/internal/services/service_items_test.go @@ -22,7 +22,7 @@ func TestItemService_CsvImport(t *testing.T) { assert.Equal(t, 0, count) assert.NoError(t, err) - items, err := svc.GetAll(context.Background(), tGroup.ID) + items, err := svc.repo.Items.GetAll(context.Background(), tGroup.ID) assert.NoError(t, err) t.Cleanup(func() { for _, item := range items { @@ -38,22 +38,14 @@ func TestItemService_CsvImport(t *testing.T) { dataCsv = append(dataCsv, newCsvRow(item)) } - locationService := &LocationService{ - repos: tRepos, - } - - LabelService := &LabelService{ - repos: tRepos, - } - - allLocation, err := locationService.GetAll(context.Background(), tGroup.ID) + allLocation, err := tRepos.Locations.GetAll(context.Background(), tGroup.ID) assert.NoError(t, err) locNames := []string{} for _, loc := range allLocation { locNames = append(locNames, loc.Name) } - allLabels, err := LabelService.GetAll(context.Background(), tGroup.ID) + allLabels, err := tRepos.Labels.GetAll(context.Background(), tGroup.ID) assert.NoError(t, err) labelNames := []string{} for _, label := range allLabels { diff --git a/backend/internal/services/service_labels.go b/backend/internal/services/service_labels.go deleted file mode 100644 index 34d67df..0000000 --- a/backend/internal/services/service_labels.go +++ /dev/null @@ -1,37 +0,0 @@ -package services - -import ( - "context" - - "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/repo" -) - -type LabelService struct { - repos *repo.AllRepos -} - -func (svc *LabelService) Create(ctx context.Context, groupId uuid.UUID, data repo.LabelCreate) (repo.LabelOut, error) { - return svc.repos.Labels.Create(ctx, groupId, data) -} - -func (svc *LabelService) Update(ctx context.Context, groupId uuid.UUID, data repo.LabelUpdate) (repo.LabelOut, error) { - return svc.repos.Labels.Update(ctx, data) -} - -func (svc *LabelService) Delete(ctx context.Context, gid uuid.UUID, id uuid.UUID) error { - _, err := svc.repos.Labels.GetOneByGroup(ctx, gid, id) - if err != nil { - return err - } - return svc.repos.Labels.Delete(ctx, id) -} - -func (svc *LabelService) Get(ctx context.Context, gid uuid.UUID, id uuid.UUID) (repo.LabelOut, error) { - return svc.repos.Labels.GetOneByGroup(ctx, gid, id) - -} - -func (svc *LabelService) GetAll(ctx context.Context, groupId uuid.UUID) ([]repo.LabelSummary, error) { - return svc.repos.Labels.GetAll(ctx, groupId) -} diff --git a/backend/internal/services/service_locations.go b/backend/internal/services/service_locations.go deleted file mode 100644 index 7152337..0000000 --- a/backend/internal/services/service_locations.go +++ /dev/null @@ -1,47 +0,0 @@ -package services - -import ( - "context" - "errors" - - "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/repo" -) - -var ( - ErrNotOwner = errors.New("not owner") -) - -type LocationService struct { - repos *repo.AllRepos -} - -func (svc *LocationService) GetOne(ctx context.Context, groupId uuid.UUID, id uuid.UUID) (repo.LocationOut, error) { - return svc.repos.Locations.GetOneByGroup(ctx, groupId, id) -} - -func (svc *LocationService) GetAll(ctx context.Context, groupId uuid.UUID) ([]repo.LocationOutCount, error) { - return svc.repos.Locations.GetAll(ctx, groupId) -} - -func (svc *LocationService) Create(ctx context.Context, groupId uuid.UUID, data repo.LocationCreate) (repo.LocationOut, error) { - return svc.repos.Locations.Create(ctx, groupId, data) -} - -func (svc *LocationService) Delete(ctx context.Context, groupId uuid.UUID, id uuid.UUID) error { - _, err := svc.repos.Locations.GetOneByGroup(ctx, groupId, id) - if err != nil { - return err - } - return svc.repos.Locations.Delete(ctx, id) -} - -func (svc *LocationService) Update(ctx context.Context, groupId uuid.UUID, data repo.LocationUpdate) (repo.LocationOut, error) { - location, err := svc.repos.Locations.GetOneByGroup(ctx, groupId, data.ID) - if err != nil { - return repo.LocationOut{}, err - } - - data.ID = location.ID - return svc.repos.Locations.Update(ctx, data) -}