mirror of
https://github.com/hay-kot/homebox.git
synced 2025-08-05 09:10:26 +00:00
add attachment API
This commit is contained in:
parent
3cae78a85e
commit
d19f0e2922
9 changed files with 286 additions and 129 deletions
|
@ -353,6 +353,38 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Items"
|
||||||
|
],
|
||||||
|
"summary": "retrieves an attachment for an item",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Item ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Attachment ID",
|
||||||
|
"name": "attachment_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/labels": {
|
"/v1/labels": {
|
||||||
|
|
|
@ -345,6 +345,38 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"Bearer": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Items"
|
||||||
|
],
|
||||||
|
"summary": "retrieves an attachment for an item",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Item ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Attachment ID",
|
||||||
|
"name": "attachment_id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"description": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/labels": {
|
"/v1/labels": {
|
||||||
|
|
|
@ -542,6 +542,26 @@ paths:
|
||||||
tags:
|
tags:
|
||||||
- Items
|
- Items
|
||||||
/v1/items/{id}/attachments/{attachment_id}:
|
/v1/items/{id}/attachments/{attachment_id}:
|
||||||
|
delete:
|
||||||
|
parameters:
|
||||||
|
- description: Item ID
|
||||||
|
in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: Attachment ID
|
||||||
|
in: path
|
||||||
|
name: attachment_id
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"204":
|
||||||
|
description: ""
|
||||||
|
security:
|
||||||
|
- Bearer: []
|
||||||
|
summary: retrieves an attachment for an item
|
||||||
|
tags:
|
||||||
|
- Items
|
||||||
get:
|
get:
|
||||||
parameters:
|
parameters:
|
||||||
- description: Item ID
|
- description: Item ID
|
||||||
|
|
|
@ -88,6 +88,7 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux {
|
||||||
|
|
||||||
r.Post(v1Base("/items/{id}/attachments"), v1Ctrl.HandleItemAttachmentCreate())
|
r.Post(v1Base("/items/{id}/attachments"), v1Ctrl.HandleItemAttachmentCreate())
|
||||||
r.Get(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentToken())
|
r.Get(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentToken())
|
||||||
|
r.Delete(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentDelete())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
item, err := ctrl.svc.Items.AddAttachment(
|
item, err := ctrl.svc.Items.AttachmentAdd(
|
||||||
r.Context(),
|
r.Context(),
|
||||||
user.GroupID,
|
user.GroupID,
|
||||||
uid,
|
uid,
|
||||||
|
@ -253,7 +253,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
server.Respond(w, http.StatusOK, item)
|
server.Respond(w, http.StatusCreated, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
token := server.GetParam(r, "token", "")
|
token := server.GetParam(r, "token", "")
|
||||||
|
|
||||||
path, err := ctrl.svc.Items.GetAttachment(r.Context(), token)
|
path, err := ctrl.svc.Items.AttachmentPath(r.Context(), token)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("failed to get attachment")
|
log.Err(err).Msg("failed to get attachment")
|
||||||
|
@ -288,8 +288,8 @@ func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc {
|
||||||
// @Summary retrieves an attachment for an item
|
// @Summary retrieves an attachment for an item
|
||||||
// @Tags Items
|
// @Tags Items
|
||||||
// @Produce application/octet-stream
|
// @Produce application/octet-stream
|
||||||
// @Param id path string true "Item ID"
|
// @Param id path string true "Item ID"
|
||||||
// @Param attachment_id path string true "Attachment ID"
|
// @Param attachment_id path string true "Attachment ID"
|
||||||
// @Success 200 {object} types.ItemAttachmentToken
|
// @Success 200 {object} types.ItemAttachmentToken
|
||||||
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
|
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
|
||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
|
@ -307,7 +307,7 @@ func (ctrl *V1Controller) HandleItemAttachmentToken() http.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := ctrl.svc.Items.NewAttachmentToken(r.Context(), user.GroupID, uid, attachmentId)
|
token, err := ctrl.svc.Items.AttachmentToken(r.Context(), user.GroupID, uid, attachmentId)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("failed to get attachment")
|
log.Err(err).Msg("failed to get attachment")
|
||||||
|
@ -321,3 +321,36 @@ func (ctrl *V1Controller) HandleItemAttachmentToken() http.HandlerFunc {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HandleItemAttachmentDelete godocs
|
||||||
|
// @Summary retrieves an attachment for an item
|
||||||
|
// @Tags Items
|
||||||
|
// @Param id path string true "Item ID"
|
||||||
|
// @Param attachment_id path string true "Attachment ID"
|
||||||
|
// @Success 204
|
||||||
|
// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE]
|
||||||
|
// @Security Bearer
|
||||||
|
func (ctrl *V1Controller) HandleItemAttachmentDelete() http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
uid, user, err := ctrl.partialParseIdAndUser(w, r)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
attachmentId, err := uuid.Parse(chi.URLParam(r, "attachment_id"))
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).Msg("failed to parse attachment_id param")
|
||||||
|
server.RespondError(w, http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ctrl.svc.Items.AttachmentDelete(r.Context(), user.GroupID, uid, attachmentId)
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).Msg("failed to delete attachment")
|
||||||
|
server.RespondServerError(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
server.Respond(w, http.StatusNoContent, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,18 +4,11 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/ent/attachment"
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/repo"
|
"github.com/hay-kot/homebox/backend/internal/repo"
|
||||||
"github.com/hay-kot/homebox/backend/internal/services/mappers"
|
"github.com/hay-kot/homebox/backend/internal/services/mappers"
|
||||||
"github.com/hay-kot/homebox/backend/internal/types"
|
"github.com/hay-kot/homebox/backend/internal/types"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/hasher"
|
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/pathlib"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,37 +16,10 @@ var (
|
||||||
ErrNotFound = errors.New("not found")
|
ErrNotFound = errors.New("not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: this isn't a scalable solution, tokens should be stored in the database
|
|
||||||
type attachmentTokens map[string]uuid.UUID
|
|
||||||
|
|
||||||
func (at attachmentTokens) Add(token string, id uuid.UUID) {
|
|
||||||
at[token] = id
|
|
||||||
|
|
||||||
log.Debug().Str("token", token).Str("uuid", id.String()).Msg("added token")
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
ch := time.After(1 * time.Minute)
|
|
||||||
<-ch
|
|
||||||
at.Delete(token)
|
|
||||||
log.Debug().Str("token", token).Msg("deleted token")
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at attachmentTokens) Get(token string) (uuid.UUID, bool) {
|
|
||||||
id, ok := at[token]
|
|
||||||
return id, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (at attachmentTokens) Delete(token string) {
|
|
||||||
delete(at, token)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ItemService struct {
|
type ItemService struct {
|
||||||
repo *repo.AllRepos
|
repo *repo.AllRepos
|
||||||
|
|
||||||
// filepath is the root of the storage location that will be used to store all files from.
|
|
||||||
filepath string
|
filepath string
|
||||||
|
|
||||||
// at is a map of tokens to attachment IDs. This is used to store the attachment ID
|
// at is a map of tokens to attachment IDs. This is used to store the attachment ID
|
||||||
// for issued URLs
|
// for issued URLs
|
||||||
at attachmentTokens
|
at attachmentTokens
|
||||||
|
@ -131,90 +97,6 @@ func (svc *ItemService) Update(ctx context.Context, gid uuid.UUID, data types.It
|
||||||
return mappers.ToItemOut(item), nil
|
return mappers.ToItemOut(item), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *ItemService) attachmentPath(gid, itemId uuid.UUID, filename string) string {
|
|
||||||
path := filepath.Join(svc.filepath, gid.String(), itemId.String(), filename)
|
|
||||||
return pathlib.Safe(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (svc *ItemService) NewAttachmentToken(ctx context.Context, gid, 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 {
|
|
||||||
return "", ErrNotOwner
|
|
||||||
}
|
|
||||||
|
|
||||||
token := hasher.GenerateToken()
|
|
||||||
|
|
||||||
svc.at.Add(token.Raw, attachmentId)
|
|
||||||
|
|
||||||
return token.Raw, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (svc *ItemService) GetAttachment(ctx context.Context, token string) (string, error) {
|
|
||||||
attachmentId, ok := svc.at.Get(token)
|
|
||||||
if !ok {
|
|
||||||
return "", ErrNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return attachment.Edges.Document.Path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddAttachment 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) AddAttachment(ctx context.Context, gid, 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 {
|
|
||||||
return nil, ErrNotOwner
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the document
|
|
||||||
doc, err := svc.repo.Docs.Create(ctx, gid, types.DocumentCreate{
|
|
||||||
Title: filename,
|
|
||||||
Path: svc.attachmentPath(gid, itemId, filename),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the attachment
|
|
||||||
_, err = svc.repo.Attachments.Create(ctx, itemId, doc.ID, attachmentType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the contents and write them to a file on the file system
|
|
||||||
err = os.MkdirAll(filepath.Dir(doc.Path), os.ModePerm)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Create(doc.Path)
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to create file")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = io.Copy(f, file)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return svc.GetOne(ctx, gid, itemId)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (svc *ItemService) CsvImport(ctx context.Context, gid uuid.UUID, data [][]string) error {
|
func (svc *ItemService) CsvImport(ctx context.Context, gid uuid.UUID, data [][]string) error {
|
||||||
loaded := []csvRow{}
|
loaded := []csvRow{}
|
||||||
|
|
||||||
|
|
158
backend/internal/services/service_items_attachments.go
Normal file
158
backend/internal/services/service_items_attachments.go
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/hay-kot/homebox/backend/ent/attachment"
|
||||||
|
"github.com/hay-kot/homebox/backend/internal/types"
|
||||||
|
"github.com/hay-kot/homebox/backend/pkgs/hasher"
|
||||||
|
"github.com/hay-kot/homebox/backend/pkgs/pathlib"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: this isn't a scalable solution, tokens should be stored in the database
|
||||||
|
type attachmentTokens map[string]uuid.UUID
|
||||||
|
|
||||||
|
func (at attachmentTokens) Add(token string, id uuid.UUID) {
|
||||||
|
at[token] = id
|
||||||
|
|
||||||
|
log.Debug().Str("token", token).Str("uuid", id.String()).Msg("added token")
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
ch := time.After(1 * time.Minute)
|
||||||
|
<-ch
|
||||||
|
at.Delete(token)
|
||||||
|
log.Debug().Str("token", token).Msg("deleted token")
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (at attachmentTokens) Get(token string) (uuid.UUID, bool) {
|
||||||
|
id, ok := at[token]
|
||||||
|
return id, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (at attachmentTokens) Delete(token string) {
|
||||||
|
delete(at, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *ItemService) AttachmentToken(ctx context.Context, gid, 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 {
|
||||||
|
return "", ErrNotOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
token := hasher.GenerateToken()
|
||||||
|
|
||||||
|
svc.at.Add(token.Raw, attachmentId)
|
||||||
|
|
||||||
|
return token.Raw, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *ItemService) attachmentPath(gid, itemId uuid.UUID, filename string) string {
|
||||||
|
path := filepath.Join(svc.filepath, gid.String(), itemId.String(), filename)
|
||||||
|
path = pathlib.Safe(path)
|
||||||
|
log.Debug().Str("path", path).Msg("attachment path")
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *ItemService) AttachmentPath(ctx context.Context, token string) (string, error) {
|
||||||
|
attachmentId, ok := svc.at.Get(token)
|
||||||
|
if !ok {
|
||||||
|
return "", ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachment.Edges.Document.Path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
// Get the Item
|
||||||
|
item, err := svc.repo.Items.GetOne(ctx, itemId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Edges.Group.ID != gid {
|
||||||
|
return nil, ErrNotOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
fp := svc.attachmentPath(gid, itemId, filename)
|
||||||
|
filename = filepath.Base(fp)
|
||||||
|
|
||||||
|
// Create the document
|
||||||
|
doc, err := svc.repo.Docs.Create(ctx, gid, types.DocumentCreate{
|
||||||
|
Title: filename,
|
||||||
|
Path: fp,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the attachment
|
||||||
|
_, err = svc.repo.Attachments.Create(ctx, itemId, doc.ID, attachmentType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the contents and write them to a file on the file system
|
||||||
|
err = os.MkdirAll(filepath.Dir(doc.Path), os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(doc.Path)
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).Msg("failed to create file")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(f, file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc.GetOne(ctx, gid, itemId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *ItemService) AttachmentDelete(ctx context.Context, gid, itemId, attachmentId uuid.UUID) error {
|
||||||
|
// Get the Item
|
||||||
|
item, err := svc.repo.Items.GetOne(ctx, itemId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.Edges.Group.ID != gid {
|
||||||
|
return ErrNotOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment, err := svc.repo.Attachments.Get(ctx, attachmentId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the attachment
|
||||||
|
err = svc.repo.Attachments.Delete(ctx, attachmentId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove File
|
||||||
|
err = os.Remove(attachment.Edges.Document.Path)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
|
@ -97,8 +97,7 @@ func TestItemService_AddAttachment(t *testing.T) {
|
||||||
temp := os.TempDir()
|
temp := os.TempDir()
|
||||||
|
|
||||||
svc := &ItemService{
|
svc := &ItemService{
|
||||||
repo: tRepos,
|
repo: tRepos,
|
||||||
filepath: temp,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loc, err := tSvc.Location.Create(context.Background(), tGroup.ID, types.LocationCreate{
|
loc, err := tSvc.Location.Create(context.Background(), tGroup.ID, types.LocationCreate{
|
||||||
|
@ -126,7 +125,7 @@ func TestItemService_AddAttachment(t *testing.T) {
|
||||||
reader := strings.NewReader(contents)
|
reader := strings.NewReader(contents)
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
afterAttachment, err := svc.AddAttachment(context.Background(), tGroup.ID, itm.ID, "testfile.txt", "attachment", reader)
|
afterAttachment, err := svc.AttachmentAdd(context.Background(), tGroup.ID, itm.ID, "testfile.txt", "attachment", reader)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, afterAttachment)
|
assert.NotNil(t, afterAttachment)
|
||||||
|
|
||||||
|
|
|
@ -24,10 +24,10 @@ var dirReader dirReaderFunc = func(directory string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasConflict(path string, neighbors []string) bool {
|
func hasConflict(path string, neighbors []string) bool {
|
||||||
path = strings.ToLower(path)
|
filename := strings.ToLower(filepath.Base(path))
|
||||||
|
|
||||||
for _, n := range neighbors {
|
for _, n := range neighbors {
|
||||||
if strings.ToLower(n) == path {
|
if strings.ToLower(n) == filename {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue