clean: Article to Post in domain and related use cases

Renamed the 'Article' domain to 'Post' in order to better reflect the purpose and utility of the object. The change involved renaming all related use cases, classes, and other references from 'Article' to 'Post' and updating all functions and data types to work with Posts instead of Articles.
This commit is contained in:
Florian Sylvain
2023-09-06 01:56:27 +02:00
parent 46491a688b
commit 554fdc1989
18 changed files with 274 additions and 271 deletions
@@ -1,62 +0,0 @@
package gateways
import (
entity "GohCMS2/adapters/secondary/gateways/models"
domain "GohCMS2/domain/article"
"GohCMS2/domain/gateways"
"gorm.io/gorm"
)
type ArticleRepository struct {
db *gorm.DB
}
func NewArticleRepository(db *gorm.DB) *ArticleRepository {
return &ArticleRepository{db}
}
func mapArticleToDomain(article entity.Article) domain.Article {
return domain.FromDb(article.ID, article.Title, article.Body, article.CreatedAt, article.UpdatedAt)
}
func (a *ArticleRepository) Get(id uint32) (domain.Article, error) {
var article entity.Article
err := a.db.Model(&entity.Article{}).First(&article, id).Error
if err != nil {
return domain.Article{}, err
}
return mapArticleToDomain(article), nil
}
func (a *ArticleRepository) Create(article domain.Article) (domain.Article, error) {
creationResult := a.db.Create(&entity.Article{
Title: article.Title,
Body: article.Body,
})
if creationResult.Error != nil {
return domain.Article{}, creationResult.Error
}
var createdArticle entity.Article
creationResult.Scan(&createdArticle)
return mapArticleToDomain(createdArticle), nil
}
func (a *ArticleRepository) GetAll() []domain.Article {
var articles []entity.Article
err := a.db.Model(&entity.Article{}).Find(&articles).Error
if err != nil {
return []domain.Article{}
}
var domainArticles = make([]domain.Article, 0)
for _, article := range articles {
domainArticles = append(domainArticles, mapArticleToDomain(article))
}
return domainArticles
}
var _ gateways.IArticleRepository = &ArticleRepository{}
@@ -5,7 +5,7 @@ import (
"time" "time"
) )
type Article struct { type Post struct {
gorm.Model gorm.Model
ID uint32 `gorm:"primary_key;auto_increment;not_null"` ID uint32 `gorm:"primary_key;auto_increment;not_null"`
Title string Title string
@@ -0,0 +1,62 @@
package gateways
import (
entity "GohCMS2/adapters/secondary/gateways/models"
"GohCMS2/domain/gateways"
domain "GohCMS2/domain/post"
"gorm.io/gorm"
)
type PostRepository struct {
db *gorm.DB
}
func NewPostRepository(db *gorm.DB) *PostRepository {
return &PostRepository{db}
}
func mapPostToDomain(post entity.Post) domain.Post {
return domain.FromDb(post.ID, post.Title, post.Body, post.CreatedAt, post.UpdatedAt)
}
func (a *PostRepository) Get(id uint32) (domain.Post, error) {
var article entity.Post
err := a.db.Model(&entity.Post{}).First(&article, id).Error
if err != nil {
return domain.Post{}, err
}
return mapPostToDomain(article), nil
}
func (a *PostRepository) Create(article domain.Post) (domain.Post, error) {
creationResult := a.db.Create(&entity.Post{
Title: article.Title,
Body: article.Body,
})
if creationResult.Error != nil {
return domain.Post{}, creationResult.Error
}
var createdArticle entity.Post
creationResult.Scan(&createdArticle)
return mapPostToDomain(createdArticle), nil
}
func (a *PostRepository) GetAll() []domain.Post {
var articles []entity.Post
err := a.db.Model(&entity.Post{}).Find(&articles).Error
if err != nil {
return []domain.Post{}
}
var domainArticles = make([]domain.Post, 0)
for _, article := range articles {
domainArticles = append(domainArticles, mapPostToDomain(article))
}
return domainArticles
}
var _ gateways.IArticleRepository = &PostRepository{}
@@ -16,6 +16,7 @@
<div class="container mt-3 text-black-50"> <div class="container mt-3 text-black-50">
<h1>Accueil</h1> <h1>Accueil</h1>
<p>Bienvenue sur GohCMS !</p> <p>Bienvenue sur GohCMS !</p>
<button class="btn btn-outline-primary">Posts &raquo;</button>
</div> </div>
</body> </body>
</html> </html>
+4 -4
View File
@@ -11,7 +11,7 @@ import (
) )
type LocalContainer struct { type LocalContainer struct {
CreateArticleUseCase *useCases.CreateArticleUseCase CreateArticleUseCase *useCases.CreatePostUseCase
GetArticleUseCase *useCases.GetArticleUseCase GetArticleUseCase *useCases.GetArticleUseCase
ListArticlesUseCase *useCases.ListArticlesUseCase ListArticlesUseCase *useCases.ListArticlesUseCase
GetUserUseCase *useCases.GetUserUseCase GetUserUseCase *useCases.GetUserUseCase
@@ -23,7 +23,7 @@ type LocalContainer struct {
var Container *LocalContainer var Container *LocalContainer
func setContainer( func setContainer(
createArticle *useCases.CreateArticleUseCase, createArticle *useCases.CreatePostUseCase,
getArticle *useCases.GetArticleUseCase, getArticle *useCases.GetArticleUseCase,
listArticle *useCases.ListArticlesUseCase, listArticle *useCases.ListArticlesUseCase,
getUser *useCases.GetUserUseCase, getUser *useCases.GetUserUseCase,
@@ -60,11 +60,11 @@ func InitContainer() {
panic("Unable to open the database: " + err.Error()) panic("Unable to open the database: " + err.Error())
} }
_ = db.AutoMigrate(&models.Article{}, &models.User{}) _ = db.AutoMigrate(&models.Post{}, &models.User{})
_ = digContainer.Provide(func() *gorm.DB { return db }) _ = digContainer.Provide(func() *gorm.DB { return db })
_ = digContainer.Provide(func(db *gorm.DB) *useCases.CreateArticleUseCase { return useCases.NewCreateArticleUseCase(db) }) _ = digContainer.Provide(func(db *gorm.DB) *useCases.CreatePostUseCase { return useCases.NewCreatePostUseCase(db) })
_ = digContainer.Provide(func(db *gorm.DB) *useCases.GetArticleUseCase { return useCases.NewGetArticleUseCase(db) }) _ = digContainer.Provide(func(db *gorm.DB) *useCases.GetArticleUseCase { return useCases.NewGetArticleUseCase(db) })
_ = digContainer.Provide(func(db *gorm.DB) *useCases.ListArticlesUseCase { return useCases.NewListArticlesUseCase(db) }) _ = digContainer.Provide(func(db *gorm.DB) *useCases.ListArticlesUseCase { return useCases.NewListArticlesUseCase(db) })
_ = digContainer.Provide(func(db *gorm.DB) *useCases.GetUserUseCase { return useCases.NewGetUserUseCase(db) }) _ = digContainer.Provide(func(db *gorm.DB) *useCases.GetUserUseCase { return useCases.NewGetUserUseCase(db) })
+1 -1
View File
@@ -44,7 +44,7 @@ func postArticle(w http.ResponseWriter, r *http.Request) {
return return
} }
createdArticle, err := Container.CreateArticleUseCase.CreateArticle(useCases.CreateArticleCommand{ createdArticle, err := Container.CreateArticleUseCase.CreatePost(useCases.CreatePostCommand{
Title: article.Title, Title: article.Title,
Body: article.Body, Body: article.Body,
}) })
-11
View File
@@ -1,11 +0,0 @@
package gateways
import (
"GohCMS2/domain/article"
)
type IArticleRepository interface {
Get(id uint32) (article.Article, error)
GetAll() []article.Article
Create(article article.Article) (article.Article, error)
}
+11
View File
@@ -0,0 +1,11 @@
package gateways
import (
"GohCMS2/domain/post"
)
type IArticleRepository interface {
Get(id uint32) (post.Post, error)
GetAll() []post.Post
Create(article post.Post) (post.Post, error)
}
@@ -1,8 +1,8 @@
package article package post
import "time" import "time"
type Article struct { type Post struct {
ID uint32 `json:"id"` ID uint32 `json:"id"`
Title string `json:"title"` Title string `json:"title"`
Body string `json:"body"` Body string `json:"body"`
@@ -13,8 +13,8 @@ type Article struct {
func FromApi( func FromApi(
title string, title string,
body string, body string,
) Article { ) Post {
return Article{ return Post{
Title: title, Title: title,
Body: body, Body: body,
} }
@@ -26,8 +26,8 @@ func FromDb(
body string, body string,
createdAt time.Time, createdAt time.Time,
updatedAt time.Time, updatedAt time.Time,
) Article { ) Post {
return Article{ return Post{
ID: id, ID: id,
Title: title, Title: title,
Body: body, Body: body,
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -46,7 +46,7 @@ func InitBackendRoutes() *chi.Mux {
r.Group(func(r chi.Router) { r.Group(func(r chi.Router) {
r.Use(jwtauth.Verifier(api.TokenAuth)) r.Use(jwtauth.Verifier(api.TokenAuth))
r.Use(jwtauth.Authenticator) r.Use(jwtauth.Authenticator)
r.Mount("/article", api.NewArticleRouter()) r.Mount("/post", api.NewArticleRouter())
}) })
r.Mount("/auth", api.NewAuthRouter()) r.Mount("/auth", api.NewAuthRouter())
-144
View File
@@ -1,144 +0,0 @@
package test
import (
"GohCMS2/domain/article"
"bytes"
"encoding/json"
"github.com/stretchr/testify/assert"
"io"
"net/http"
"strconv"
"testing"
)
var TestCreateArticleSuccess = func(t *testing.T) {
jsonBody, err := json.Marshal(map[string]string{
"title": "Test Title",
"body": "Test Body",
})
if err != nil {
t.Fatal(err)
}
r, _ := ApiRequest("POST", "/article", bytes.NewBuffer(jsonBody))
var response article.Article
bd, err := io.ReadAll(r.Body)
if err != nil {
t.Fatal(err)
}
err = json.Unmarshal(bd, &response)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, http.StatusOK, r.StatusCode)
assert.Equal(t, "Test Title", response.Title)
assert.Equal(t, "Test Body", response.Body)
}
var TestCreateArticleFailTitleMissing = func(t *testing.T) {
jsonBody, err := json.Marshal(map[string]string{
"body": "Test Body",
})
if err != nil {
t.Fatal(err)
}
r, _ := ApiRequest("POST", "/article", bytes.NewBuffer(jsonBody))
assert.Equal(t, http.StatusBadRequest, r.StatusCode)
}
var TestCreateArticleTitleTooShort = func(t *testing.T) {
jsonBody, err := json.Marshal(map[string]string{
"title": "Te",
"body": "Test Body",
})
if err != nil {
t.Fatal(err)
}
r, _ := ApiRequest("POST", "/article", bytes.NewBuffer(jsonBody))
assert.Equal(t, http.StatusBadRequest, r.StatusCode)
}
var TestGetArticleSuccess = func(t *testing.T) {
var createdArticle article.Article
var articleToCreate = article.Article{
Title: "Test Title",
Body: "Test Body",
}
db := GetDb()
db.Create(&articleToCreate).Scan(&createdArticle)
r, _ := ApiRequest("GET", "/article/"+strconv.Itoa(int(createdArticle.ID)), nil)
var response article.Article
bd, err := io.ReadAll(r.Body)
if err != nil {
t.Fatal(err)
}
err = json.Unmarshal(bd, &response)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, http.StatusOK, r.StatusCode)
assert.Equal(t, createdArticle.ID, response.ID)
assert.Equal(t, createdArticle.Title, response.Title)
assert.Equal(t, createdArticle.Body, response.Body)
}
var TestGetAllArticlesSuccess = func(t *testing.T) {
var createdArticle article.Article
var articleToCreate = article.Article{
Title: "Test Title",
Body: "Test Body",
}
db := GetDb()
db.Create(&articleToCreate).Scan(&createdArticle)
r, _ := ApiRequest("GET", "/article", nil)
var response []article.Article
bd, err := io.ReadAll(r.Body)
if err != nil {
t.Fatal(err)
}
err = json.Unmarshal(bd, &response)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, http.StatusOK, r.StatusCode)
assert.Equal(t, createdArticle.Title, response[0].Title)
assert.Equal(t, createdArticle.Body, response[0].Body)
}
var TestArticleCreate = func(t *testing.T) {
t.Run("Should return an article with the given title and body", TestCreateArticleSuccess)
t.Run("Should return an error if the title is missing", TestCreateArticleFailTitleMissing)
t.Run("Should return an error if the title is too short", TestCreateArticleTitleTooShort)
}
var TestArticleGet = func(t *testing.T) {
t.Run("Should return an article with the given id", TestGetArticleSuccess)
}
var TestArticleGetAll = func(t *testing.T) {
t.Run("Should return all articles", TestGetAllArticlesSuccess)
}
func TestArticle(t *testing.T) {
StartServerIfNotAlready()
WaitForServer()
t.Run("Create", TestArticleCreate)
t.Run("Get", TestArticleGet)
t.Run("GetAll", TestArticleGetAll)
}
+144
View File
@@ -0,0 +1,144 @@
package test
import (
"GohCMS2/domain/post"
"bytes"
"encoding/json"
"github.com/stretchr/testify/assert"
"io"
"net/http"
"strconv"
"testing"
)
var TestCreatePostSuccess = func(t *testing.T) {
jsonBody, err := json.Marshal(map[string]string{
"title": "Test Title",
"body": "Test Body",
})
if err != nil {
t.Fatal(err)
}
r, _ := ApiRequest("POST", "/post", bytes.NewBuffer(jsonBody))
var response post.Post
bd, err := io.ReadAll(r.Body)
if err != nil {
t.Fatal(err)
}
err = json.Unmarshal(bd, &response)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, http.StatusOK, r.StatusCode)
assert.Equal(t, "Test Title", response.Title)
assert.Equal(t, "Test Body", response.Body)
}
var TestCreatePostFailTitleMissing = func(t *testing.T) {
jsonBody, err := json.Marshal(map[string]string{
"body": "Test Body",
})
if err != nil {
t.Fatal(err)
}
r, _ := ApiRequest("POST", "/post", bytes.NewBuffer(jsonBody))
assert.Equal(t, http.StatusBadRequest, r.StatusCode)
}
var TestCreatePostTitleTooShort = func(t *testing.T) {
jsonBody, err := json.Marshal(map[string]string{
"title": "Te",
"body": "Test Body",
})
if err != nil {
t.Fatal(err)
}
r, _ := ApiRequest("POST", "/post", bytes.NewBuffer(jsonBody))
assert.Equal(t, http.StatusBadRequest, r.StatusCode)
}
var TestGetPostSuccess = func(t *testing.T) {
var createdPost post.Post
var articleToCreate = post.Post{
Title: "Test Title",
Body: "Test Body",
}
db := GetDb()
db.Create(&articleToCreate).Scan(&createdPost)
r, _ := ApiRequest("GET", "/post/"+strconv.Itoa(int(createdPost.ID)), nil)
var response post.Post
bd, err := io.ReadAll(r.Body)
if err != nil {
t.Fatal(err)
}
err = json.Unmarshal(bd, &response)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, http.StatusOK, r.StatusCode)
assert.Equal(t, createdPost.ID, response.ID)
assert.Equal(t, createdPost.Title, response.Title)
assert.Equal(t, createdPost.Body, response.Body)
}
var TestGetAllPostsSuccess = func(t *testing.T) {
var createdPost post.Post
var articleToCreate = post.Post{
Title: "Test Title",
Body: "Test Body",
}
db := GetDb()
db.Create(&articleToCreate).Scan(&createdPost)
r, _ := ApiRequest("GET", "/post", nil)
var response []post.Post
bd, err := io.ReadAll(r.Body)
if err != nil {
t.Fatal(err)
}
err = json.Unmarshal(bd, &response)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, http.StatusOK, r.StatusCode)
assert.Equal(t, createdPost.Title, response[0].Title)
assert.Equal(t, createdPost.Body, response[0].Body)
}
var TestPostCreate = func(t *testing.T) {
t.Run("Should return an post with the given title and body", TestCreatePostSuccess)
t.Run("Should return an error if the title is missing", TestCreatePostFailTitleMissing)
t.Run("Should return an error if the title is too short", TestCreatePostTitleTooShort)
}
var TestPostGet = func(t *testing.T) {
t.Run("Should return an post with the given id", TestGetPostSuccess)
}
var TestPostGetAll = func(t *testing.T) {
t.Run("Should return all articles", TestGetAllPostsSuccess)
}
func TestPost(t *testing.T) {
StartServerIfNotAlready()
WaitForServer()
t.Run("Create", TestPostCreate)
t.Run("Get", TestPostGet)
t.Run("GetAll", TestPostGetAll)
}
+6 -4
View File
@@ -12,16 +12,18 @@ import (
"time" "time"
) )
const testDbFile = "test.db"
var ApiUrl string var ApiUrl string
var AuthorizationCookie *http.Cookie var AuthorizationCookie *http.Cookie
var HttpClient = http.Client{} var HttpClient = http.Client{}
func GetDb() *gorm.DB { func GetDb() *gorm.DB {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{}) db, err := gorm.Open(sqlite.Open(testDbFile), &gorm.Config{})
if err != nil { if err != nil {
panic(err) panic(err)
} }
_ = db.AutoMigrate(&models.Article{}, &models.User{}) _ = db.AutoMigrate(&models.Post{}, &models.User{})
return db return db
} }
@@ -30,8 +32,8 @@ func StartServerIfNotAlready() {
if err == nil { if err == nil {
return return
} }
_ = os.Remove("test.db") _ = os.Remove(testDbFile)
_ = os.Setenv("DB_FILE", "test.db") _ = os.Setenv("DB_FILE", testDbFile)
go func(url *string) { go func(url *string) {
router := server.InitServer() router := server.InitServer()
*url = "http://localhost:" + os.Getenv("PORT") + "/v1" *url = "http://localhost:" + os.Getenv("PORT") + "/v1"
-29
View File
@@ -1,29 +0,0 @@
package useCases
import (
"GohCMS2/adapters/secondary/gateways"
"GohCMS2/domain/article"
"gorm.io/gorm"
)
type CreateArticleUseCase struct {
articleRepository gateways.ArticleRepository
}
type CreateArticleCommand struct {
Title string
Body string
}
func NewCreateArticleUseCase(db *gorm.DB) *CreateArticleUseCase {
return &CreateArticleUseCase{
articleRepository: *gateways.NewArticleRepository(db),
}
}
func (g *CreateArticleUseCase) CreateArticle(createArticle CreateArticleCommand) (article.Article, error) {
return g.articleRepository.Create(article.FromApi(
createArticle.Title,
createArticle.Body,
))
}
+29
View File
@@ -0,0 +1,29 @@
package useCases
import (
"GohCMS2/adapters/secondary/gateways"
"GohCMS2/domain/post"
"gorm.io/gorm"
)
type CreatePostUseCase struct {
postRepository gateways.PostRepository
}
type CreatePostCommand struct {
Title string
Body string
}
func NewCreatePostUseCase(db *gorm.DB) *CreatePostUseCase {
return &CreatePostUseCase{
postRepository: *gateways.NewPostRepository(db),
}
}
func (g *CreatePostUseCase) CreatePost(createPost CreatePostCommand) (post.Post, error) {
return g.postRepository.Create(post.FromApi(
createPost.Title,
createPost.Body,
))
}
@@ -2,20 +2,20 @@ package useCases
import ( import (
"GohCMS2/adapters/secondary/gateways" "GohCMS2/adapters/secondary/gateways"
"GohCMS2/domain/article" "GohCMS2/domain/post"
"gorm.io/gorm" "gorm.io/gorm"
) )
type GetArticleUseCase struct { type GetArticleUseCase struct {
articleRepository gateways.ArticleRepository articleRepository gateways.PostRepository
} }
func NewGetArticleUseCase(db *gorm.DB) *GetArticleUseCase { func NewGetArticleUseCase(db *gorm.DB) *GetArticleUseCase {
return &GetArticleUseCase{ return &GetArticleUseCase{
articleRepository: *gateways.NewArticleRepository(db), articleRepository: *gateways.NewPostRepository(db),
} }
} }
func (g *GetArticleUseCase) GetArticle(id uint32) (article.Article, error) { func (g *GetArticleUseCase) GetArticle(id uint32) (post.Post, error) {
return g.articleRepository.Get(id) return g.articleRepository.Get(id)
} }
@@ -2,20 +2,20 @@ package useCases
import ( import (
"GohCMS2/adapters/secondary/gateways" "GohCMS2/adapters/secondary/gateways"
"GohCMS2/domain/article" "GohCMS2/domain/post"
"gorm.io/gorm" "gorm.io/gorm"
) )
type ListArticlesUseCase struct { type ListArticlesUseCase struct {
articleRepository gateways.ArticleRepository articleRepository gateways.PostRepository
} }
func NewListArticlesUseCase(db *gorm.DB) *ListArticlesUseCase { func NewListArticlesUseCase(db *gorm.DB) *ListArticlesUseCase {
return &ListArticlesUseCase{ return &ListArticlesUseCase{
articleRepository: *gateways.NewArticleRepository(db), articleRepository: *gateways.NewPostRepository(db),
} }
} }
func (g *ListArticlesUseCase) ListArticles() []article.Article { func (g *ListArticlesUseCase) ListArticles() []post.Post {
return g.articleRepository.GetAll() return g.articleRepository.GetAll()
} }