diff --git a/backend/internal/services/contexts.go b/backend/internal/services/contexts.go index 1ecc901..c85c50e 100644 --- a/backend/internal/services/contexts.go +++ b/backend/internal/services/contexts.go @@ -3,6 +3,7 @@ package services import ( "context" + "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/types" ) @@ -15,6 +16,31 @@ var ( ContextUserToken = &contextKeys{name: "UserToken"} ) +type ServiceContext struct { + context.Context + + // UID is a unique identifier for the acting user. + UID uuid.UUID + + // GID is a unique identifier for the acting users group. + GID uuid.UUID + + // User is the acting user. + User *types.UserOut +} + +// UseServiceCtx is a helper function that returns the service context from the context. +// This extracts the users from the context and embeds it into the ServiceContext struct +func NewServiceContext(ctx context.Context) ServiceContext { + user := UseUserCtx(ctx) + return ServiceContext{ + Context: ctx, + UID: user.ID, + GID: user.GroupID, + User: user, + } +} + // SetUserCtx is a helper function that sets the ContextUser and ContextUserToken // values within the context of a web request (or any context). func SetUserCtx(ctx context.Context, user *types.UserOut, token string) context.Context { diff --git a/backend/internal/services/service_items_attachments.go b/backend/internal/services/service_items_attachments.go index bc3ad75..ea8d034 100644 --- a/backend/internal/services/service_items_attachments.go +++ b/backend/internal/services/service_items_attachments.go @@ -40,12 +40,12 @@ func (at attachmentTokens) Delete(token string) { delete(at, token) } -func (svc *ItemService) AttachmentToken(ctx context.Context, gid, itemId, attachmentId uuid.UUID) (string, error) { +func (svc *ItemService) AttachmentToken(ctx ServiceContext, itemId, attachmentId uuid.UUID) (string, error) { item, err := svc.repo.Items.GetOne(ctx, itemId) if err != nil { return "", err } - if item.Edges.Group.ID != gid { + if item.Edges.Group.ID != ctx.GID { return "", ErrNotOwner } @@ -77,25 +77,55 @@ func (svc *ItemService) AttachmentPath(ctx context.Context, token string) (strin return attachment.Edges.Document.Path, nil } +func (svc *ItemService) AttachmentUpdate(ctx ServiceContext, itemId uuid.UUID, data *types.ItemAttachmentUpdate) (*types.ItemOut, error) { + // Update Properties + attachment, err := svc.repo.Attachments.Update(ctx, data.ID, attachment.Type(data.Type)) + if err != nil { + return nil, err + } + + attDoc := attachment.Edges.Document + + if data.Title != attachment.Edges.Document.Title { + newPath := pathlib.Safe(svc.attachmentPath(ctx.GID, itemId, data.Title)) + + // Move File + err = os.Rename(attachment.Edges.Document.Path, newPath) + if err != nil { + return nil, err + } + + _, err = svc.repo.Docs.Update(ctx, attDoc.ID, types.DocumentUpdate{ + Title: data.Title, + Path: newPath, + }) + if err != nil { + return nil, err + } + } + + return svc.GetOne(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 // Table and Items table. The file provided via the reader is stored on the file system based on the provided // relative path during construction of the service. -func (svc *ItemService) AttachmentAdd(ctx context.Context, gid, itemId uuid.UUID, filename string, attachmentType attachment.Type, file io.Reader) (*types.ItemOut, error) { +func (svc *ItemService) AttachmentAdd(ctx ServiceContext, itemId uuid.UUID, filename string, attachmentType attachment.Type, file io.Reader) (*types.ItemOut, error) { // Get the Item item, err := svc.repo.Items.GetOne(ctx, itemId) if err != nil { return nil, err } - if item.Edges.Group.ID != gid { + if item.Edges.Group.ID != ctx.GID { return nil, ErrNotOwner } - fp := svc.attachmentPath(gid, itemId, filename) + fp := svc.attachmentPath(ctx.GID, itemId, filename) filename = filepath.Base(fp) // Create the document - doc, err := svc.repo.Docs.Create(ctx, gid, types.DocumentCreate{ + doc, err := svc.repo.Docs.Create(ctx, ctx.GID, types.DocumentCreate{ Title: filename, Path: fp, }) @@ -126,7 +156,7 @@ func (svc *ItemService) AttachmentAdd(ctx context.Context, gid, itemId uuid.UUID return nil, err } - return svc.GetOne(ctx, gid, itemId) + return svc.GetOne(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_test.go b/backend/internal/services/service_items_test.go index 10114f4..c6235b1 100644 --- a/backend/internal/services/service_items_test.go +++ b/backend/internal/services/service_items_test.go @@ -125,7 +125,7 @@ func TestItemService_AddAttachment(t *testing.T) { reader := strings.NewReader(contents) // Setup - afterAttachment, err := svc.AttachmentAdd(context.Background(), tGroup.ID, itm.ID, "testfile.txt", "attachment", reader) + afterAttachment, err := svc.AttachmentAdd(ServiceContext{Context: context.Background(), GID: tGroup.ID}, itm.ID, "testfile.txt", "attachment", reader) assert.NoError(t, err) assert.NotNil(t, afterAttachment)