Skip to content

Commit

Permalink
Merge pull request #375 from synyx/golang-http
Browse files Browse the repository at this point in the history
Modernize go API server
  • Loading branch information
fheft authored Oct 1, 2024
2 parents 1dbf40a + 94f6765 commit 2773fca
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 194 deletions.
5 changes: 0 additions & 5 deletions .golangci.yml

This file was deleted.

1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ module synyx.de/tales
go 1.22

require (
github.com/gorilla/mux v1.8.1
github.com/mozillazg/go-slugify v0.2.0
github.com/stretchr/testify v1.9.0
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/mozillazg/go-slugify v0.2.0 h1:SIhqDlnJWZH8OdiTmQgeXR28AOnypmAXPeOTcG7b9lk=
github.com/mozillazg/go-slugify v0.2.0/go.mod h1:z7dPH74PZf2ZPFkyxx+zjPD8CNzRJNa1CGacv0gg8Ns=
github.com/mozillazg/go-unidecode v0.2.0 h1:vFGEzAH9KSwyWmXCOblazEWDh7fOkpmy/Z4ArmamSUc=
Expand Down
1 change: 1 addition & 0 deletions pkg/buildinfo/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ func FormattedGitSHA() string {
if GitTreeState != "clean" {
return fmt.Sprintf("%s-%s", GitSHA, GitTreeState)
}

return GitSHA
}
23 changes: 23 additions & 0 deletions pkg/buildinfo/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package buildinfo

import "testing"

func TestCleanState(t *testing.T) {
Version = "1.0"
GitSHA = "2547ce676b1f899d08c61c5367c635c76505b443"
GitTreeState = "clean"

if sha := FormattedGitSHA(); sha != GitSHA {
t.Errorf("git sha should be %s, got %s", GitSHA, sha)
}
}

func TestDirtyState(t *testing.T) {
Version = "1.0"
GitSHA = "2547ce676b1f899d08c61c5367c635c76505b443"
GitTreeState = "dirty"

if sha := FormattedGitSHA(); sha != GitSHA+"-dirty" {
t.Errorf("git sha should be %s, got %s", GitSHA, sha)
}
}
52 changes: 39 additions & 13 deletions pkg/project/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,31 @@ func (fr *FilesystemRepository) imageFile(slug, filename string) string {
}

// Exists implements the Repository.Exists method.
func (fr *FilesystemRepository) Exists(slug string) bool {
func (fr *FilesystemRepository) Exists(slug string) (bool, error) {
dir, err := os.Stat(fr.ProjectDir)
if err != nil {
return false, fmt.Errorf("project directory %s not accessible: %w", fr.ProjectDir, err)
}
if !dir.IsDir() {
return false, fmt.Errorf("project directory %s is not a directory", fr.ProjectDir)
}

filename := fr.configFile(slug)
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
return false, nil
}
if info.IsDir() {
return false, fmt.Errorf("%s is a directory", slug)
}
return !info.IsDir()

return true, nil
}

// LoadProjects implements the Repository.LoadProjects method.
func (fr *FilesystemRepository) LoadProjects() ([]Project, error) {
projects := make([]Project, 0)

files, err := os.ReadDir(fr.ProjectDir)
if err != nil {
return projects, err
Expand All @@ -45,6 +58,7 @@ func (fr *FilesystemRepository) LoadProjects() ([]Project, error) {
if !f.IsDir() {
continue
}

slug := f.Name()
project, err := fr.LoadProject(slug)
if err != nil {
Expand All @@ -59,18 +73,20 @@ func (fr *FilesystemRepository) LoadProjects() ([]Project, error) {

// LoadProject implements the Repository.LoadProject method.
func (fr *FilesystemRepository) LoadProject(slug string) (Project, error) {
if !fr.Exists(slug) {
if exists, err := fr.Exists(slug); err != nil {
return Project{}, err
} else if !exists {
return Project{}, ErrNotExist
}

jsonFile := fr.configFile(slug)
data, err := os.ReadFile(jsonFile)
if err != nil {
return Project{}, err
}

var project Project
err = json.Unmarshal(data, &project)
if err != nil {
if err := json.Unmarshal(data, &project); err != nil {
return Project{}, err
}

Expand Down Expand Up @@ -99,42 +115,52 @@ func (fr *FilesystemRepository) SaveProject(slug string, project Project) (Proje

// DeleteProject implements the Repository.DeleteProject method.
func (fr *FilesystemRepository) DeleteProject(slug string) error {
if !fr.Exists(slug) {
if exists, err := fr.Exists(slug); err != nil {
return err
} else if !exists {
return ErrNotExist
}

jsonFile := fr.configFile(slug)

return os.RemoveAll(filepath.Dir(jsonFile))
}

// SaveImage implements the Repository.SaveImage method.
func (fr *FilesystemRepository) SaveImage(slug, contentType string, data []byte) (Project, error) {
if !fr.Exists(slug) {
if exists, err := fr.Exists(slug); err != nil {
return Project{}, err
} else if !exists {
return Project{}, ErrNotExist
}

extension := imageType(contentType)
filename := slug + "." + extension
if extension == "" {
return Project{}, fmt.Errorf("unsupported content-type: %v", contentType)
}

filename := slug + "." + extension
imageFile := fr.imageFile(slug, filename)
err := os.MkdirAll(filepath.Dir(imageFile), os.ModePerm)
if err != nil {
if err := os.MkdirAll(filepath.Dir(imageFile), os.ModePerm); err != nil {
return Project{}, err
}
err = os.WriteFile(imageFile, data, 0644)
if err != nil {

if err := os.WriteFile(imageFile, data, 0644); err != nil {
return Project{}, err
}

project, err := fr.LoadProject(slug)
if err != nil {
return Project{}, err
}

project.FilePath = filename
project.FileType = contentType
project, err = fr.SaveProject(slug, project)
if err != nil {
return Project{}, err
}

return project, nil
}

Expand Down
29 changes: 18 additions & 11 deletions pkg/project/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ func TestFilesystemRepository_Exists(t *testing.T) {
defer os.RemoveAll(repo.ProjectDir)

t.Run("checks existence", func(t *testing.T) {
assert.False(t, repo.Exists("project-1"))
repo.SaveProject("project-1", Project{Name: "Project 1"})
assert.True(t, repo.Exists("project-1"))
exists, _ := repo.Exists("project-1")
assert.False(t, exists)

_, _ = repo.SaveProject("project-1", Project{Name: "Project 1"})

exists, _ = repo.Exists("project-1")
assert.True(t, exists)
})
}

Expand All @@ -27,11 +31,11 @@ func TestFilesystemRepository_LoadProjects(t *testing.T) {
defer os.RemoveAll(repo.ProjectDir)

project1 := Project{Name: "Project 1"}
repo.SaveProject("project-1", project1)
_, _ = repo.SaveProject("project-1", project1)
project2 := Project{Name: "Project 2"}
repo.SaveProject("project-2", project2)
_, _ = repo.SaveProject("project-2", project2)
project3 := Project{Name: "Project 3"}
repo.SaveProject("project-3", project3)
_, _ = repo.SaveProject("project-3", project3)

projects, err := repo.LoadProjects()
assert.Nil(t, err)
Expand All @@ -42,7 +46,9 @@ func TestFilesystemRepository_LoadProjects(t *testing.T) {
})
t.Run("non-existing repo directory", func(t *testing.T) {
repo := testRepo(t)
os.RemoveAll(repo.ProjectDir)
if err := os.RemoveAll(repo.ProjectDir); err != nil {
t.Fatal("could not delete project dir for testing", err)
}

projects, err := repo.LoadProjects()
assert.NotNil(t, err)
Expand Down Expand Up @@ -114,7 +120,7 @@ func TestFilesystemRepository_LoadProject(t *testing.T) {
})
t.Run("load existing project", func(t *testing.T) {
project1 := Project{Name: "Project 1"}
repo.SaveProject("project-1", project1)
_, _ = repo.SaveProject("project-1", project1)
project, err := repo.LoadProject("project-1")
assert.Nil(t, err)
assert.Equal(t, project1, project)
Expand Down Expand Up @@ -149,7 +155,7 @@ func TestFilesystemRepository_DeleteProject(t *testing.T) {
})
t.Run("delete valid project", func(t *testing.T) {
project := Project{Name: "Foo"}
repo.SaveProject("foo", project)
_, _ = repo.SaveProject("foo", project)
_, err := repo.LoadProject("foo")
assert.Nil(t, err)
err = repo.DeleteProject("foo")
Expand All @@ -173,13 +179,13 @@ func TestFilesystemRepository_SaveImage(t *testing.T) {
})
t.Run("save image with invalid content-type", func(t *testing.T) {
project := Project{}
repo.SaveProject("project", project)
_, _ = repo.SaveProject("project", project)
_, err := repo.SaveImage("project", "foo/bar", []byte{})
assert.EqualError(t, err, "unsupported content-type: foo/bar")
})
t.Run("save image for valid project", func(t *testing.T) {
project := Project{}
repo.SaveProject("project", project)
_, _ = repo.SaveProject("project", project)
savedProject, err := repo.SaveImage("project", "image/jpeg", []byte{'f', 'o', 'o'})
assert.NoError(t, err)
assert.Equal(t, "project.jpg", savedProject.FilePath)
Expand All @@ -196,5 +202,6 @@ func TestFilesystemRepository_SaveImage(t *testing.T) {
func testRepo(t *testing.T) FilesystemRepository {
dir, err := os.MkdirTemp("", "tales-test")
assert.Nil(t, err)

return FilesystemRepository{dir}
}
2 changes: 1 addition & 1 deletion pkg/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type Project struct {

// A Repository manages projects.
type Repository interface {
Exists(string) bool
Exists(string) (bool, error)
LoadProjects() ([]Project, error)
LoadProject(string) (Project, error)
SaveProject(string, Project) (Project, error)
Expand Down
Loading

0 comments on commit 2773fca

Please sign in to comment.