diff --git a/internal/static/repository.go b/internal/static/repository.go index a6b3863..2a77983 100644 --- a/internal/static/repository.go +++ b/internal/static/repository.go @@ -6,19 +6,13 @@ import ( "source.toby3d.me/toby3d/home/internal/domain" ) -type ( - Repository interface { - // Get returns Static on path if exists - Get(ctx context.Context, path string) (*domain.Static, error) - } +type Repository interface { + // Create copy static into store to path. + Create(ctx context.Context, static domain.Static, path string) (bool, error) - dummyRepository struct{} -) + // Get returns static on path if exists. + Get(ctx context.Context, path string) (*domain.Static, error) -func NewDummyRepository() dummyRepository { - return dummyRepository{} -} - -func (dummyRepository) Get(ctx context.Context, path string) (*domain.Static, error) { - return nil, nil + // Delete remove static from store if exists. + Delete(ctx context.Context, path string) (bool, error) } diff --git a/internal/static/repository/dummy/dummy_static.go b/internal/static/repository/dummy/dummy_static.go new file mode 100644 index 0000000..3367ca1 --- /dev/null +++ b/internal/static/repository/dummy/dummy_static.go @@ -0,0 +1,27 @@ +package dummy + +import ( + "context" + + "source.toby3d.me/toby3d/home/internal/domain" +) + +type dummyStaticRepository struct{} + +// NewDummyRepository creates a new dummy static repository which will be used +// as argument to functions that you don’t care about. +func NewDummyStaticRepository() dummyStaticRepository { + return dummyStaticRepository{} +} + +func (dummyStaticRepository) Create(_ context.Context, _ domain.Static, _ string) (bool, error) { + return false, nil +} + +func (dummyStaticRepository) Get(_ context.Context, _ string) (*domain.Static, error) { + return nil, nil +} + +func (dummyStaticRepository) Delete(_ context.Context, _ string) (bool, error) { + return false, nil +} diff --git a/internal/static/repository/fs/fs_static.go b/internal/static/repository/fs/fs_static.go index f1ec7df..83c4a6e 100644 --- a/internal/static/repository/fs/fs_static.go +++ b/internal/static/repository/fs/fs_static.go @@ -3,12 +3,15 @@ package fs import ( "bytes" "context" + "errors" "fmt" _ "image/gif" _ "image/jpeg" _ "image/png" "io" "io/fs" + "os" + "path/filepath" _ "golang.org/x/image/bmp" _ "golang.org/x/image/webp" @@ -18,22 +21,30 @@ import ( ) type fileServerStaticRepository struct { - root fs.FS + store fs.FS } -func NewFileServerStaticRepository(root fs.FS) static.Repository { - return &fileServerStaticRepository{ - root: root, +func (repo *fileServerStaticRepository) Create(_ context.Context, s domain.Static, p string) (bool, error) { + f, err := os.OpenFile(filepath.Clean(p), os.O_WRONLY, os.ModePerm) + if err != nil { + return false, fmt.Errorf("cannot open static for writing: %w", err) } + defer f.Close() + + if _, err = io.Copy(f, &s); err != nil { + return false, fmt.Errorf("cannot copy static: %w", err) + } + + return true, nil } -func (repo *fileServerStaticRepository) Get(ctx context.Context, p string) (*domain.Static, error) { - info, err := fs.Stat(repo.root, p) +func (repo *fileServerStaticRepository) Get(_ context.Context, p string) (*domain.Static, error) { + info, err := fs.Stat(repo.store, p) if err != nil { return nil, fmt.Errorf("cannot stat static on path '%s': %w", p, err) } - f, err := repo.root.Open(p) + f, err := repo.store.Open(p) if err != nil { return nil, fmt.Errorf("cannot open static on path '%s': %w", p, err) } @@ -46,3 +57,30 @@ func (repo *fileServerStaticRepository) Get(ctx context.Context, p string) (*dom return domain.NewStatic(bytes.NewReader(content), info.ModTime(), info.Name()), nil } + +func (repo *fileServerStaticRepository) Delete(_ context.Context, p string) (bool, error) { + p = filepath.Clean(p) + + _, err := fs.Stat(repo.store, p) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + return false, nil + } + + return false, fmt.Errorf("cannot open static for writing: %w", err) + } + + if err = os.RemoveAll(p); err != nil { + return false, fmt.Errorf("cannot remove static: %w", err) + } + + return true, nil +} + +// NewFileServerStaticRepository creates a new FS repository for static files +// which must be uploaded and used as is. +func NewFileServerStaticRepository(store fs.FS) static.Repository { + return &fileServerStaticRepository{ + store: store, + } +} diff --git a/internal/static/repository/stub/stub_static.go b/internal/static/repository/stub/stub_static.go new file mode 100644 index 0000000..44f5d73 --- /dev/null +++ b/internal/static/repository/stub/stub_static.go @@ -0,0 +1,34 @@ +package stub + +import ( + "context" + + "source.toby3d.me/toby3d/home/internal/domain" + "source.toby3d.me/toby3d/home/internal/static" +) + +type stubStaticRepository struct { + static *domain.Static + error error + status bool +} + +func (repo *stubStaticRepository) Create(_ context.Context, _ domain.Static, _ string) (bool, error) { + return repo.status, repo.error +} + +func (repo *stubStaticRepository) Delete(_ context.Context, _ string) (bool, error) { + return repo.status, repo.error +} + +func (repo *stubStaticRepository) Get(_ context.Context, _ string) (*domain.Static, error) { + return repo.static, repo.error +} + +func NewStubStaticRepository(err error, s *domain.Static, ok bool) static.Repository { + return &stubStaticRepository{ + static: s, + error: err, + status: ok, + } +}