From 259c3c8dcebf69d12e999a1ba186e91dc860bf7f Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Sun, 22 Oct 2023 22:11:10 +0900 Subject: [PATCH 01/12] add: get articles by tag --- backend/application/usecase/article.go | 10 ++++ backend/domain/repository/article.go | 2 + backend/infrastructure/persistence/article.go | 54 +++++++++++++++++++ backend/interfaces/api/handler/article.go | 50 +++++++++++++---- backend/interfaces/api/handler/index.go | 5 -- .../api/handler/lastest_articles.go | 2 +- backend/interfaces/api/user_api/api.go | 2 + 7 files changed, 108 insertions(+), 17 deletions(-) diff --git a/backend/application/usecase/article.go b/backend/application/usecase/article.go index 43e23b18..6f6ee2e0 100644 --- a/backend/application/usecase/article.go +++ b/backend/application/usecase/article.go @@ -10,6 +10,8 @@ type ArticleUseCase interface { Create(title, content string, userId, categoryId int) (*model.Article, error) FindByID(id int) (*model.Article, error) GetArticles(articles *[]model.Article, limit, offset int) error + GetArticlesByCategory(articles *[]model.Article, slug string) error + GetArticlesByTag(articles *[]model.Article, slug string) error GetPager(currentPage, offset int) (*pager.Pager, error) Update(id int, title, content string) (*model.Article, error) Delete(id int) error @@ -52,6 +54,14 @@ func (au *articleUseCase) GetArticles(articles *[]model.Article, limit, offset i return au.articleRepo.GetArticles(articles, limit, offset) } +func (au *articleUseCase) GetArticlesByCategory(articles *[]model.Article, slug string) error { + return au.articleRepo.GetArticlesByCategory(articles, slug) +} + +func (au *articleUseCase) GetArticlesByTag(articles *[]model.Article, slug string) error { + return au.articleRepo.GetArticlesByTag(articles, slug) +} + func (au *articleUseCase) GetPager(currentPage, offset int) (*pager.Pager, error) { var a model.Article diff --git a/backend/domain/repository/article.go b/backend/domain/repository/article.go index b665c82b..31b7fca8 100644 --- a/backend/domain/repository/article.go +++ b/backend/domain/repository/article.go @@ -6,6 +6,8 @@ type ArticleRepository interface { Create(article *model.Article) (*model.Article, error) FindByID(article *model.Article) error GetArticles(articles *[]model.Article, limit, offset int) error + GetArticlesByCategory(articles *[]model.Article, slug string) error + GetArticlesByTag(articles *[]model.Article, slug string) error GetPager(article *model.Article) (int, error) Update(article *model.Article) (*model.Article, error) Delete(article *model.Article) error diff --git a/backend/infrastructure/persistence/article.go b/backend/infrastructure/persistence/article.go index f6f41f15..c44ca9f7 100644 --- a/backend/infrastructure/persistence/article.go +++ b/backend/infrastructure/persistence/article.go @@ -52,6 +52,60 @@ func (ap *articlePersistence) GetPager(article *model.Article) (int, error) { return int(count), nil } +func (ap *articlePersistence) GetArticlesByCategory(articles *[]model.Article, slug string) error { + // return ap.Reprica(). + // Joins("User"). + // Joins("Category"). + // Preload("Tags"). + // Order("created_at ASC"). + // Where("category.slug = ?", slug). + // Find(articles). + // Error + return nil +} + +// GetArticlesByTag retrieves articles based on a given tag slug. +// +// articles: a pointer to a slice of model.Article to store the retrieved articles. +// slug: the slug of the tag to filter the articles by. +// error: an error indicating if there was any issue retrieving the articles. +func (ap *articlePersistence) GetArticlesByTag(articles *[]model.Article, slug string) error { + query := ` + SELECT + article.id, + article.title, + article.thumbnail_url, + article.updated_at, + category.id AS category_id, + category.name AS category_name, + category.slug AS category_slug, + tag.id AS tag_id, + tag.name AS tag_name, + tag.slug AS tag_slug, + article_tag.article_id AS article_tag_article_id, + article_tag.tag_id AS article_tag_tag_id + FROM + articles AS article + LEFT JOIN + categories AS category + ON + category.id = article.category_id + LEFT JOIN + article_tags AS article_tag + ON + article_tag.article_id = article.id + LEFT JOIN + tags AS tag + ON + tag.id = article_tag.tag_id + WHERE + tag.slug = ? + AND + article.status = 2; + ` + return ap.Reprica().Raw(query, slug).Scan(articles).Error +} + func (ap *articlePersistence) Update(article *model.Article) (*model.Article, error) { return &model.Article{}, nil } diff --git a/backend/interfaces/api/handler/article.go b/backend/interfaces/api/handler/article.go index cb328b78..726ef793 100644 --- a/backend/interfaces/api/handler/article.go +++ b/backend/interfaces/api/handler/article.go @@ -6,15 +6,15 @@ import ( "github.com/gorilla/mux" "github.com/yoshihiro-shu/draft-backend/backend/application/usecase" + "github.com/yoshihiro-shu/draft-backend/backend/domain/model" "github.com/yoshihiro-shu/draft-backend/backend/interfaces/api/request" "gorm.io/gorm" ) type ArticleHandler interface { - Post(w http.ResponseWriter, r *http.Request) error Get(w http.ResponseWriter, r *http.Request) error - Put(w http.ResponseWriter, r *http.Request) error - Delete(w http.ResponseWriter, r *http.Request) error + GetArticlesByCategory(w http.ResponseWriter, r *http.Request) error + GetArticlesByTag(w http.ResponseWriter, r *http.Request) error } type articleHandler struct { @@ -29,10 +29,6 @@ func NewArticleHandler(articleUseCase usecase.ArticleUseCase, c *request.Context } } -func (ah *articleHandler) Post(w http.ResponseWriter, r *http.Request) error { - return nil -} - func (ah *articleHandler) Get(w http.ResponseWriter, r *http.Request) error { vars := mux.Vars(r) strId := vars["id"] @@ -52,10 +48,42 @@ func (ah *articleHandler) Get(w http.ResponseWriter, r *http.Request) error { return ah.C.JSON(w, http.StatusOK, article) } -func (ah *articleHandler) Put(w http.ResponseWriter, r *http.Request) error { - return nil +type responseGetArticlesByCategory struct { + Articles []model.Article `json:"articles"` +} + +func (ah *articleHandler) GetArticlesByCategory(w http.ResponseWriter, r *http.Request) error { + var res responseGetArticlesByCategory + vars := mux.Vars(r) + slug := vars["slug"] + + err := ah.articleUseCase.GetArticlesByCategory(&res.Articles, slug) + if err != nil { + if err == gorm.ErrRecordNotFound { + ah.C.Logger.Warn("err no articles at latest Articles Handler") + return ah.C.JSON(w, http.StatusNotFound, err) + } + } + + return ah.C.JSON(w, http.StatusOK, res) +} + +type responseGetArticlesByTag struct { + Articles []model.Article `json:"articles"` } -func (ah *articleHandler) Delete(w http.ResponseWriter, r *http.Request) error { - return nil +func (ah *articleHandler) GetArticlesByTag(w http.ResponseWriter, r *http.Request) error { + var res responseGetArticlesByTag + vars := mux.Vars(r) + slug := vars["slug"] + + err := ah.articleUseCase.GetArticlesByTag(&res.Articles, slug) + if err != nil { + if err == gorm.ErrRecordNotFound { + ah.C.Logger.Warn("err no articles at latest Articles Handler") + return ah.C.JSON(w, http.StatusNotFound, err) + } + } + + return ah.C.JSON(w, http.StatusOK, res) } diff --git a/backend/interfaces/api/handler/index.go b/backend/interfaces/api/handler/index.go index a15aa700..df8f6213 100644 --- a/backend/interfaces/api/handler/index.go +++ b/backend/interfaces/api/handler/index.go @@ -18,11 +18,6 @@ type TestRedis struct { func (h indexHandler) Index(w http.ResponseWriter, r *http.Request) error { return h.JSON(w, http.StatusOK, "HELLO WORLD") } -func (h indexHandler) AuthIndex(w http.ResponseWriter, r *http.Request) error { - id := h.GetAuthUserID(r.Context()) - return h.JSON(w, http.StatusOK, id) -} - func NewIndexHandler(c *request.Context) *indexHandler { return &indexHandler{c} } diff --git a/backend/interfaces/api/handler/lastest_articles.go b/backend/interfaces/api/handler/lastest_articles.go index 1d0dd1c3..687bd63b 100644 --- a/backend/interfaces/api/handler/lastest_articles.go +++ b/backend/interfaces/api/handler/lastest_articles.go @@ -61,7 +61,7 @@ func (h latestArticlesHandler) Get(w http.ResponseWriter, r *http.Request) error h.logger.Warn("err no articles at latest Articles Handler") return h.JSON(w, http.StatusNotFound, err) } - h.logger.Warn("failed at get articles at latest articles.", zap.Error(err)) + h.logger.Error("failed at get articles at latest articles.", zap.Error(err)) return h.Error(w, http.StatusInternalServerError, err) } diff --git a/backend/interfaces/api/user_api/api.go b/backend/interfaces/api/user_api/api.go index 50d41d7c..f67f06db 100644 --- a/backend/interfaces/api/user_api/api.go +++ b/backend/interfaces/api/user_api/api.go @@ -65,6 +65,8 @@ func Apply(r router.Router, conf config.Configs, logger logger.Logger, db model. ) article := r.Group("/articles") article.GET("/{id:[0-9]+}", articleHandler.Get) + article.GET("/category/{slug}", articleHandler.GetArticlesByCategory) + article.GET("/tag/{slug}", articleHandler.GetArticlesByTag) } // { // a := r.Group("/auth") From 872727c84b0ce944718ac042518529edde44ac50 Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Sun, 22 Oct 2023 22:50:03 +0900 Subject: [PATCH 02/12] update: get aritlces by tag --- backend/application/usecase/article.go | 10 ---- backend/application/usecase/articles.go | 32 ++++++++++++ backend/infrastructure/persistence/article.go | 3 +- backend/interfaces/api/handler/article.go | 52 +++++++++++++++---- backend/registory/article_registory.go | 3 +- 5 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 backend/application/usecase/articles.go diff --git a/backend/application/usecase/article.go b/backend/application/usecase/article.go index 6f6ee2e0..43e23b18 100644 --- a/backend/application/usecase/article.go +++ b/backend/application/usecase/article.go @@ -10,8 +10,6 @@ type ArticleUseCase interface { Create(title, content string, userId, categoryId int) (*model.Article, error) FindByID(id int) (*model.Article, error) GetArticles(articles *[]model.Article, limit, offset int) error - GetArticlesByCategory(articles *[]model.Article, slug string) error - GetArticlesByTag(articles *[]model.Article, slug string) error GetPager(currentPage, offset int) (*pager.Pager, error) Update(id int, title, content string) (*model.Article, error) Delete(id int) error @@ -54,14 +52,6 @@ func (au *articleUseCase) GetArticles(articles *[]model.Article, limit, offset i return au.articleRepo.GetArticles(articles, limit, offset) } -func (au *articleUseCase) GetArticlesByCategory(articles *[]model.Article, slug string) error { - return au.articleRepo.GetArticlesByCategory(articles, slug) -} - -func (au *articleUseCase) GetArticlesByTag(articles *[]model.Article, slug string) error { - return au.articleRepo.GetArticlesByTag(articles, slug) -} - func (au *articleUseCase) GetPager(currentPage, offset int) (*pager.Pager, error) { var a model.Article diff --git a/backend/application/usecase/articles.go b/backend/application/usecase/articles.go new file mode 100644 index 00000000..33e86f02 --- /dev/null +++ b/backend/application/usecase/articles.go @@ -0,0 +1,32 @@ +package usecase + +import ( + "github.com/yoshihiro-shu/draft-backend/backend/domain/model" + "github.com/yoshihiro-shu/draft-backend/backend/domain/repository" +) + +type ArticlesUseCase interface { + GetArticlesByCategory(articles *[]model.Article, slug string) error + GetArticlesByTag(articles *[]model.Article, slug string) error +} + +type articlesUseCase struct { + articleRepo repository.ArticleRepository +} + +func NewArticlesUseCase(articleRepo repository.ArticleRepository) ArticlesUseCase { + return &articlesUseCase{articleRepo: articleRepo} +} + +func (au *articlesUseCase) GetArticlesByCategory(articles *[]model.Article, slug string) error { + err := au.articleRepo.GetArticlesByCategory(articles, slug) + if err != nil { + return err + } + + return nil +} + +func (au *articlesUseCase) GetArticlesByTag(articles *[]model.Article, slug string) error { + return au.articleRepo.GetArticlesByTag(articles, slug) +} diff --git a/backend/infrastructure/persistence/article.go b/backend/infrastructure/persistence/article.go index c44ca9f7..8ca042fd 100644 --- a/backend/infrastructure/persistence/article.go +++ b/backend/infrastructure/persistence/article.go @@ -75,12 +75,13 @@ func (ap *articlePersistence) GetArticlesByTag(articles *[]model.Article, slug s article.id, article.title, article.thumbnail_url, + article.created_at, article.updated_at, category.id AS category_id, category.name AS category_name, category.slug AS category_slug, tag.id AS tag_id, - tag.name AS tag_name, + -- tag.name AS tag_name, tag.slug AS tag_slug, article_tag.article_id AS article_tag_article_id, article_tag.tag_id AS article_tag_tag_id diff --git a/backend/interfaces/api/handler/article.go b/backend/interfaces/api/handler/article.go index 726ef793..d37e9fa9 100644 --- a/backend/interfaces/api/handler/article.go +++ b/backend/interfaces/api/handler/article.go @@ -3,11 +3,13 @@ package handler import ( "net/http" "strconv" + "time" "github.com/gorilla/mux" "github.com/yoshihiro-shu/draft-backend/backend/application/usecase" "github.com/yoshihiro-shu/draft-backend/backend/domain/model" "github.com/yoshihiro-shu/draft-backend/backend/interfaces/api/request" + "go.uber.org/zap" "gorm.io/gorm" ) @@ -18,15 +20,19 @@ type ArticleHandler interface { } type articleHandler struct { - articleUseCase usecase.ArticleUseCase - C *request.Context + articleUseCase usecase.ArticleUseCase + articlesUseCase usecase.ArticlesUseCase + C *request.Context } -func NewArticleHandler(articleUseCase usecase.ArticleUseCase, c *request.Context) ArticleHandler { - return &articleHandler{ - articleUseCase: articleUseCase, - C: c, - } +type ListAritcleBox struct { + Id int `json:"id"` + Title string `json:"title"` + ThumbnailUrl string `json:"thumbnail_url"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + // CategoryName string `json:"category_name"` + // CategorySlug string `json:"category_slug"` } func (ah *articleHandler) Get(w http.ResponseWriter, r *http.Request) error { @@ -57,7 +63,7 @@ func (ah *articleHandler) GetArticlesByCategory(w http.ResponseWriter, r *http.R vars := mux.Vars(r) slug := vars["slug"] - err := ah.articleUseCase.GetArticlesByCategory(&res.Articles, slug) + err := ah.articlesUseCase.GetArticlesByCategory(&res.Articles, slug) if err != nil { if err == gorm.ErrRecordNotFound { ah.C.Logger.Warn("err no articles at latest Articles Handler") @@ -69,21 +75,45 @@ func (ah *articleHandler) GetArticlesByCategory(w http.ResponseWriter, r *http.R } type responseGetArticlesByTag struct { - Articles []model.Article `json:"articles"` + Articles []ListAritcleBox `json:"articles"` } func (ah *articleHandler) GetArticlesByTag(w http.ResponseWriter, r *http.Request) error { - var res responseGetArticlesByTag vars := mux.Vars(r) slug := vars["slug"] - err := ah.articleUseCase.GetArticlesByTag(&res.Articles, slug) + var a []model.Article + err := ah.articlesUseCase.GetArticlesByTag(&a, slug) if err != nil { if err == gorm.ErrRecordNotFound { ah.C.Logger.Warn("err no articles at latest Articles Handler") return ah.C.JSON(w, http.StatusNotFound, err) } } + ah.C.Logger.Info("articles at latest Articles Handler", zap.Any("articles", a)) + + var res responseGetArticlesByTag + res.Articles = make([]ListAritcleBox, 0) + for _, v := range a { + res.Articles = append(res.Articles, ListAritcleBox{ + Id: v.Id, + Title: v.Title, + ThumbnailUrl: v.ThumbnailUrl, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + // TODO 記事にカテゴリを付与した後に戻す + // CategoryName: v.Category.Name, + // CategorySlug: v.Category.Slug, + }) + } return ah.C.JSON(w, http.StatusOK, res) } + +func NewArticleHandler(articleUseCase usecase.ArticleUseCase, articlesUseCase usecase.ArticlesUseCase, c *request.Context) ArticleHandler { + return &articleHandler{ + articleUseCase: articleUseCase, + articlesUseCase: articlesUseCase, + C: c, + } +} diff --git a/backend/registory/article_registory.go b/backend/registory/article_registory.go index 6be90c49..f10b8b7a 100644 --- a/backend/registory/article_registory.go +++ b/backend/registory/article_registory.go @@ -11,5 +11,6 @@ import ( func NewArticleRegistory(ctx *request.Context, master, reprica func() *gorm.DB) handler.ArticleHandler { articleRepository := persistence.NewArticlePersistence(master, reprica) articleUseCase := usecase.NewArticleUseCase(articleRepository) - return handler.NewArticleHandler(articleUseCase, ctx) + articlesUseCase := usecase.NewArticlesUseCase(articleRepository) + return handler.NewArticleHandler(articleUseCase, articlesUseCase, ctx) } From 9dc94bf4dc8096b43fa62282966c30bb65f92074 Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Sun, 22 Oct 2023 23:03:52 +0900 Subject: [PATCH 03/12] add: get aritlces by tag slug --- backend/infrastructure/persistence/article.go | 43 ++++--------------- backend/interfaces/api/handler/article.go | 23 ++-------- 2 files changed, 11 insertions(+), 55 deletions(-) diff --git a/backend/infrastructure/persistence/article.go b/backend/infrastructure/persistence/article.go index 8ca042fd..80139d24 100644 --- a/backend/infrastructure/persistence/article.go +++ b/backend/infrastructure/persistence/article.go @@ -70,41 +70,14 @@ func (ap *articlePersistence) GetArticlesByCategory(articles *[]model.Article, s // slug: the slug of the tag to filter the articles by. // error: an error indicating if there was any issue retrieving the articles. func (ap *articlePersistence) GetArticlesByTag(articles *[]model.Article, slug string) error { - query := ` - SELECT - article.id, - article.title, - article.thumbnail_url, - article.created_at, - article.updated_at, - category.id AS category_id, - category.name AS category_name, - category.slug AS category_slug, - tag.id AS tag_id, - -- tag.name AS tag_name, - tag.slug AS tag_slug, - article_tag.article_id AS article_tag_article_id, - article_tag.tag_id AS article_tag_tag_id - FROM - articles AS article - LEFT JOIN - categories AS category - ON - category.id = article.category_id - LEFT JOIN - article_tags AS article_tag - ON - article_tag.article_id = article.id - LEFT JOIN - tags AS tag - ON - tag.id = article_tag.tag_id - WHERE - tag.slug = ? - AND - article.status = 2; - ` - return ap.Reprica().Raw(query, slug).Scan(articles).Error + return ap.Reprica(). + // Preload("User"). + Preload("Category"). + Preload("Tags"). + Joins("JOIN article_tags ON articles.id = article_tags.article_id"). + Joins("JOIN tags ON tags.id = article_tags.tag_id"). + Where("tags.slug = ?", slug). + Find(&articles).Error } func (ap *articlePersistence) Update(article *model.Article) (*model.Article, error) { diff --git a/backend/interfaces/api/handler/article.go b/backend/interfaces/api/handler/article.go index d37e9fa9..5635ffaa 100644 --- a/backend/interfaces/api/handler/article.go +++ b/backend/interfaces/api/handler/article.go @@ -9,7 +9,6 @@ import ( "github.com/yoshihiro-shu/draft-backend/backend/application/usecase" "github.com/yoshihiro-shu/draft-backend/backend/domain/model" "github.com/yoshihiro-shu/draft-backend/backend/interfaces/api/request" - "go.uber.org/zap" "gorm.io/gorm" ) @@ -75,37 +74,21 @@ func (ah *articleHandler) GetArticlesByCategory(w http.ResponseWriter, r *http.R } type responseGetArticlesByTag struct { - Articles []ListAritcleBox `json:"articles"` + Articles []model.Article `json:"articles"` } func (ah *articleHandler) GetArticlesByTag(w http.ResponseWriter, r *http.Request) error { + var res responseGetArticlesByTag vars := mux.Vars(r) slug := vars["slug"] - var a []model.Article - err := ah.articlesUseCase.GetArticlesByTag(&a, slug) + err := ah.articlesUseCase.GetArticlesByTag(&res.Articles, slug) if err != nil { if err == gorm.ErrRecordNotFound { ah.C.Logger.Warn("err no articles at latest Articles Handler") return ah.C.JSON(w, http.StatusNotFound, err) } } - ah.C.Logger.Info("articles at latest Articles Handler", zap.Any("articles", a)) - - var res responseGetArticlesByTag - res.Articles = make([]ListAritcleBox, 0) - for _, v := range a { - res.Articles = append(res.Articles, ListAritcleBox{ - Id: v.Id, - Title: v.Title, - ThumbnailUrl: v.ThumbnailUrl, - CreatedAt: v.CreatedAt, - UpdatedAt: v.UpdatedAt, - // TODO 記事にカテゴリを付与した後に戻す - // CategoryName: v.Category.Name, - // CategorySlug: v.Category.Slug, - }) - } return ah.C.JSON(w, http.StatusOK, res) } From 5fed734791c742943a80457d18335dbd33515aa6 Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Sun, 22 Oct 2023 23:08:12 +0900 Subject: [PATCH 04/12] add: get article by category --- backend/application/usecase/articles.go | 7 +------ backend/infrastructure/persistence/article.go | 15 ++++++--------- backend/interfaces/api/handler/article.go | 11 ----------- 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/backend/application/usecase/articles.go b/backend/application/usecase/articles.go index 33e86f02..9b762e16 100644 --- a/backend/application/usecase/articles.go +++ b/backend/application/usecase/articles.go @@ -19,12 +19,7 @@ func NewArticlesUseCase(articleRepo repository.ArticleRepository) ArticlesUseCas } func (au *articlesUseCase) GetArticlesByCategory(articles *[]model.Article, slug string) error { - err := au.articleRepo.GetArticlesByCategory(articles, slug) - if err != nil { - return err - } - - return nil + return au.articleRepo.GetArticlesByCategory(articles, slug) } func (au *articlesUseCase) GetArticlesByTag(articles *[]model.Article, slug string) error { diff --git a/backend/infrastructure/persistence/article.go b/backend/infrastructure/persistence/article.go index 80139d24..c405c740 100644 --- a/backend/infrastructure/persistence/article.go +++ b/backend/infrastructure/persistence/article.go @@ -53,15 +53,12 @@ func (ap *articlePersistence) GetPager(article *model.Article) (int, error) { } func (ap *articlePersistence) GetArticlesByCategory(articles *[]model.Article, slug string) error { - // return ap.Reprica(). - // Joins("User"). - // Joins("Category"). - // Preload("Tags"). - // Order("created_at ASC"). - // Where("category.slug = ?", slug). - // Find(articles). - // Error - return nil + return ap.Reprica(). + // Preload("User"). + Preload("Tags"). + Preload("Category"). + Where("category.slug = ?", slug). + Find(&articles).Error } // GetArticlesByTag retrieves articles based on a given tag slug. diff --git a/backend/interfaces/api/handler/article.go b/backend/interfaces/api/handler/article.go index 5635ffaa..47fd1e63 100644 --- a/backend/interfaces/api/handler/article.go +++ b/backend/interfaces/api/handler/article.go @@ -3,7 +3,6 @@ package handler import ( "net/http" "strconv" - "time" "github.com/gorilla/mux" "github.com/yoshihiro-shu/draft-backend/backend/application/usecase" @@ -24,16 +23,6 @@ type articleHandler struct { C *request.Context } -type ListAritcleBox struct { - Id int `json:"id"` - Title string `json:"title"` - ThumbnailUrl string `json:"thumbnail_url"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - // CategoryName string `json:"category_name"` - // CategorySlug string `json:"category_slug"` -} - func (ah *articleHandler) Get(w http.ResponseWriter, r *http.Request) error { vars := mux.Vars(r) strId := vars["id"] From 33fb918d6cbf10d87a5f6081d2b0f243cfef8365 Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Sun, 22 Oct 2023 23:43:33 +0900 Subject: [PATCH 05/12] add: insert new tag --- batch/qiita/src/main.rs | 26 +++++++++++++++++ batch/qiita/src/tag_map.rs | 58 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 batch/qiita/src/tag_map.rs diff --git a/batch/qiita/src/main.rs b/batch/qiita/src/main.rs index 3c76bce3..415f26b2 100644 --- a/batch/qiita/src/main.rs +++ b/batch/qiita/src/main.rs @@ -4,6 +4,7 @@ use tokio; // tokioは非同期ランタイムです use tokio_postgres::{NoTls}; mod qiita_response; +mod tag_map; #[derive(Debug)] struct Tag { @@ -81,6 +82,31 @@ async fn main() -> Result<(), Box> { }); }; + // Insert New Tags + let tag_map = tag_map::create_map(); + for r in &res { + for t in &r.tags { + // insert tag if not exists + let check = db_client.query("SELECT * FROM tags WHERE name = $1", &[&t.name]).await?; + if check.len() == 0 { + let slug = tag_map.get(&t.name.as_str()); + let mut tag_id: i32 = 0; + if slug.is_none() { + let inserted_tag = db_client.query("INSERT INTO tags (name, slug) VALUES ($1, $2) RETURNING id", &[&t.name, &t.name]).await?; + tag_id = inserted_tag[0].get("id"); + } else { + let inserted_tag = db_client.query("INSERT INTO tags (name, slug) VALUES ($1, $2) RETURNING id", &[&t.name, &slug]).await?; + tag_id = inserted_tag[0].get("id"); + } + tags.push(Tag{ + id: tag_id, + name: t.name.clone(), + }); + println!("inserted tag: {}", t.name); + } + } + } + // Insert articles from Qiita for r in res { let check = db_client.query("SELECT * FROM articles WHERE title = $1", &[&r.title]).await?; diff --git a/batch/qiita/src/tag_map.rs b/batch/qiita/src/tag_map.rs new file mode 100644 index 00000000..8eacc2da --- /dev/null +++ b/batch/qiita/src/tag_map.rs @@ -0,0 +1,58 @@ +use std::collections::HashMap; + +pub fn create_map() -> HashMap<&'static str, &'static str> { + let mut name_to_slug: HashMap<&str, &str> = HashMap::new(); + + name_to_slug.insert("Docker", "docker"); + name_to_slug.insert("Kubernetes", "kubernetes"); + name_to_slug.insert("Golang", "golang"); + name_to_slug.insert("Agile", "agile"); + name_to_slug.insert("Requirement definition", "requirement-definition"); + name_to_slug.insert("Nuxt", "nuxt"); + name_to_slug.insert("Network", "network"); + name_to_slug.insert("dns", "dns"); + // 日本語の部分を英語に変換 + name_to_slug.insert("インフラ", "infrastructure"); + name_to_slug.insert("アジャイル", "agile-methodology"); + name_to_slug.insert("プロジェクト管理", "project-management"); + name_to_slug.insert("チームビルディング", "team-building"); + name_to_slug.insert("ふりかえり", "reflection"); + name_to_slug.insert("プロジェクトマネジメント", "project-management-advanced"); + name_to_slug.insert("AI", "ai"); + name_to_slug.insert("ビジネス", "business"); + name_to_slug.insert("生産性向上", "productivity-improvement"); + name_to_slug.insert("Google", "google"); + name_to_slug.insert("マーケティング", "marketing"); + name_to_slug.insert("SEO対策", "seo-strategies"); + name_to_slug.insert("解決", "problem-solving"); + name_to_slug.insert("論理的思考", "logical-thinking"); + name_to_slug.insert("リーダー", "leader"); + name_to_slug.insert("kubernetes", "kubernetes"); + name_to_slug.insert("kubectl", "kubectl"); + name_to_slug.insert("ckad", "ckad"); + name_to_slug.insert("CKA", "cka"); + name_to_slug.insert("プレゼンテーション", "presentation"); + name_to_slug.insert("ロジカルシンキング", "logical-thinking-advanced"); + name_to_slug.insert("Go", "go"); + name_to_slug.insert("dockerfile", "dockerfile"); + name_to_slug.insert("DockerHub", "docker-hub"); + name_to_slug.insert("沼", "quagmire"); + name_to_slug.insert("個人開発", "personal-development"); + name_to_slug.insert("GitHubActions", "github-actions"); + name_to_slug.insert("要件定義", "requirement-definition-advanced"); + name_to_slug.insert("ユースケース", "use-case"); + name_to_slug.insert("ワイヤーフレーム", "wireframe"); + name_to_slug.insert("デザイン設計", "design-planning"); + name_to_slug.insert("Cloud", "cloud"); + name_to_slug.insert("docker-compose", "docker-compose"); + name_to_slug.insert("googlecloud", "googlecloud"); + name_to_slug.insert("cookie", "cookie"); + name_to_slug.insert("Vue.js", "vue-js"); + name_to_slug.insert("Vuex", "vuex"); + name_to_slug.insert("ssr", "ssr"); + name_to_slug.insert("開発環境", "development-environment"); + name_to_slug.insert("TypeScript", "typescript"); + name_to_slug.insert("Nuxt3", "nuxt3"); + + name_to_slug +} From 9aa044a8b82874d23f06a9ba7194674e41d2e549 Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Sun, 22 Oct 2023 23:52:27 +0900 Subject: [PATCH 06/12] fix: category --- .../db/20221013202627_add_test_category_data.sql | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/migrations/db/20221013202627_add_test_category_data.sql b/migrations/db/20221013202627_add_test_category_data.sql index 8d1a65ba..f127df3d 100644 --- a/migrations/db/20221013202627_add_test_category_data.sql +++ b/migrations/db/20221013202627_add_test_category_data.sql @@ -3,12 +3,12 @@ SELECT 'up SQL query'; -- +goose StatementEnd -INSERT INTO categories (name, slug) VALUES ('Docker', 'docker'); -INSERT INTO categories (name, slug) VALUES ('Kubernetes', 'kubernetes'); -INSERT INTO categories (name, slug) VALUES ('Golang', 'golang'); INSERT INTO categories (name, slug) VALUES ('Agile', 'agile'); -INSERT INTO categories (name, slug) VALUES ('Requirement definition', 'requirement-definition'); -INSERT INTO categories (name, slug) VALUES ('Nuxt', 'nuxt'); +INSERT INTO categories (name, slug) VALUES ('Bussiness', 'bussiness'); +INSERT INTO categories (name, slug) VALUES ('Backend', 'backend'); +INSERT INTO categories (name, slug) VALUES ('Frontend', 'frontend'); +INSERT INTO categories (name, slug) VALUES ('Infrastructure', 'infrastructure'); +INSERT INTO categories (name, slug) VALUES ('Marketing', 'marketing'); UPDATE articles SET category_id = 1 WHERE id = 1; UPDATE articles SET category_id = 2 WHERE id = 2; From d3e74c82461ffb7c1a5dfb82ed8b925af969885e Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Sun, 22 Oct 2023 23:54:12 +0900 Subject: [PATCH 07/12] refactor: batch --- batch/qiita/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/batch/qiita/src/main.rs b/batch/qiita/src/main.rs index 415f26b2..7b6c07a4 100644 --- a/batch/qiita/src/main.rs +++ b/batch/qiita/src/main.rs @@ -128,7 +128,6 @@ async fn main() -> Result<(), Box> { name: t.name.clone(), }) } - // insert article_tags for tt in &tags { if t.name == tt.name { @@ -136,6 +135,7 @@ async fn main() -> Result<(), Box> { } } } + println!("inserted article: {}", r.title); } Ok(()) From 92e6b6ef6c7296c19eb5597a41bd6dce09e5e89b Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Mon, 23 Oct 2023 20:22:26 +0900 Subject: [PATCH 08/12] fix: map name --- batch/qiita/src/tag_map.rs | 102 ++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/batch/qiita/src/tag_map.rs b/batch/qiita/src/tag_map.rs index 8eacc2da..852a1eca 100644 --- a/batch/qiita/src/tag_map.rs +++ b/batch/qiita/src/tag_map.rs @@ -1,58 +1,58 @@ use std::collections::HashMap; pub fn create_map() -> HashMap<&'static str, &'static str> { - let mut name_to_slug: HashMap<&str, &str> = HashMap::new(); + let mut tag_map: HashMap<&str, &str> = HashMap::new(); - name_to_slug.insert("Docker", "docker"); - name_to_slug.insert("Kubernetes", "kubernetes"); - name_to_slug.insert("Golang", "golang"); - name_to_slug.insert("Agile", "agile"); - name_to_slug.insert("Requirement definition", "requirement-definition"); - name_to_slug.insert("Nuxt", "nuxt"); - name_to_slug.insert("Network", "network"); - name_to_slug.insert("dns", "dns"); + tag_map.insert("Docker", "docker"); + tag_map.insert("Kubernetes", "kubernetes"); + tag_map.insert("Golang", "golang"); + tag_map.insert("Agile", "agile"); + tag_map.insert("Requirement definition", "requirement-definition"); + tag_map.insert("Nuxt", "nuxt"); + tag_map.insert("Network", "network"); + tag_map.insert("dns", "dns"); // 日本語の部分を英語に変換 - name_to_slug.insert("インフラ", "infrastructure"); - name_to_slug.insert("アジャイル", "agile-methodology"); - name_to_slug.insert("プロジェクト管理", "project-management"); - name_to_slug.insert("チームビルディング", "team-building"); - name_to_slug.insert("ふりかえり", "reflection"); - name_to_slug.insert("プロジェクトマネジメント", "project-management-advanced"); - name_to_slug.insert("AI", "ai"); - name_to_slug.insert("ビジネス", "business"); - name_to_slug.insert("生産性向上", "productivity-improvement"); - name_to_slug.insert("Google", "google"); - name_to_slug.insert("マーケティング", "marketing"); - name_to_slug.insert("SEO対策", "seo-strategies"); - name_to_slug.insert("解決", "problem-solving"); - name_to_slug.insert("論理的思考", "logical-thinking"); - name_to_slug.insert("リーダー", "leader"); - name_to_slug.insert("kubernetes", "kubernetes"); - name_to_slug.insert("kubectl", "kubectl"); - name_to_slug.insert("ckad", "ckad"); - name_to_slug.insert("CKA", "cka"); - name_to_slug.insert("プレゼンテーション", "presentation"); - name_to_slug.insert("ロジカルシンキング", "logical-thinking-advanced"); - name_to_slug.insert("Go", "go"); - name_to_slug.insert("dockerfile", "dockerfile"); - name_to_slug.insert("DockerHub", "docker-hub"); - name_to_slug.insert("沼", "quagmire"); - name_to_slug.insert("個人開発", "personal-development"); - name_to_slug.insert("GitHubActions", "github-actions"); - name_to_slug.insert("要件定義", "requirement-definition-advanced"); - name_to_slug.insert("ユースケース", "use-case"); - name_to_slug.insert("ワイヤーフレーム", "wireframe"); - name_to_slug.insert("デザイン設計", "design-planning"); - name_to_slug.insert("Cloud", "cloud"); - name_to_slug.insert("docker-compose", "docker-compose"); - name_to_slug.insert("googlecloud", "googlecloud"); - name_to_slug.insert("cookie", "cookie"); - name_to_slug.insert("Vue.js", "vue-js"); - name_to_slug.insert("Vuex", "vuex"); - name_to_slug.insert("ssr", "ssr"); - name_to_slug.insert("開発環境", "development-environment"); - name_to_slug.insert("TypeScript", "typescript"); - name_to_slug.insert("Nuxt3", "nuxt3"); + tag_map.insert("インフラ", "infrastructure"); + tag_map.insert("アジャイル", "agile-methodology"); + tag_map.insert("プロジェクト管理", "project-management"); + tag_map.insert("チームビルディング", "team-building"); + tag_map.insert("ふりかえり", "reflection"); + tag_map.insert("プロジェクトマネジメント", "project-management-advanced"); + tag_map.insert("AI", "ai"); + tag_map.insert("ビジネス", "business"); + tag_map.insert("生産性向上", "productivity-improvement"); + tag_map.insert("Google", "google"); + tag_map.insert("マーケティング", "marketing"); + tag_map.insert("SEO対策", "seo-strategies"); + tag_map.insert("解決", "problem-solving"); + tag_map.insert("論理的思考", "logical-thinking"); + tag_map.insert("リーダー", "leader"); + tag_map.insert("kubernetes", "kubernetes"); + tag_map.insert("kubectl", "kubectl"); + tag_map.insert("ckad", "ckad"); + tag_map.insert("CKA", "cka"); + tag_map.insert("プレゼンテーション", "presentation"); + tag_map.insert("ロジカルシンキング", "logical-thinking-advanced"); + tag_map.insert("Go", "go"); + tag_map.insert("dockerfile", "dockerfile"); + tag_map.insert("DockerHub", "docker-hub"); + tag_map.insert("沼", "quagmire"); + tag_map.insert("個人開発", "personal-development"); + tag_map.insert("GitHubActions", "github-actions"); + tag_map.insert("要件定義", "requirement-definition-advanced"); + tag_map.insert("ユースケース", "use-case"); + tag_map.insert("ワイヤーフレーム", "wireframe"); + tag_map.insert("デザイン設計", "design-planning"); + tag_map.insert("Cloud", "cloud"); + tag_map.insert("docker-compose", "docker-compose"); + tag_map.insert("googlecloud", "googlecloud"); + tag_map.insert("cookie", "cookie"); + tag_map.insert("Vue.js", "vue-js"); + tag_map.insert("Vuex", "vuex"); + tag_map.insert("ssr", "ssr"); + tag_map.insert("開発環境", "development-environment"); + tag_map.insert("TypeScript", "typescript"); + tag_map.insert("Nuxt3", "nuxt3"); - name_to_slug + tag_map } From ff1b98d6563d6568b1546ccd4c9429ef71bcab1e Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Mon, 23 Oct 2023 20:33:39 +0900 Subject: [PATCH 09/12] add: category map --- batch/qiita/src/tag_category_map.rs | 18 ++++++++++++++++++ .../20221013202627_add_test_category_data.sql | 15 ++++++++++----- 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 batch/qiita/src/tag_category_map.rs diff --git a/batch/qiita/src/tag_category_map.rs b/batch/qiita/src/tag_category_map.rs new file mode 100644 index 00000000..d8063104 --- /dev/null +++ b/batch/qiita/src/tag_category_map.rs @@ -0,0 +1,18 @@ +use std::collections::HashMap; + +pub fn create_map() -> HashMap<&'static str, &'static str> { + let mut tag_category: HashMap<&str, &str> = HashMap::new(); + + tag_category.insert("インフラ", "Infrastructure"); + tag_category.insert("アジャイル", "agile"); + tag_category.insert("ビジネス", "Bussiness"); + tag_category.insert("マーケティング", "Marketing"); + tag_category.insert("kubernetes", "kubernetes"); + tag_category.insert("Docker", "Infrastructure"); + tag_category.insert("要件定義", "System Design"); + tag_category.insert("ワイヤーフレーム", "System Design"); + tag_category.insert("googlecloud", "Infrastructure"); + tag_category.insert("Nuxt", "Frontend"); + + tag_category +} diff --git a/migrations/db/20221013202627_add_test_category_data.sql b/migrations/db/20221013202627_add_test_category_data.sql index f127df3d..a2e373c7 100644 --- a/migrations/db/20221013202627_add_test_category_data.sql +++ b/migrations/db/20221013202627_add_test_category_data.sql @@ -5,10 +5,11 @@ SELECT 'up SQL query'; INSERT INTO categories (name, slug) VALUES ('Agile', 'agile'); INSERT INTO categories (name, slug) VALUES ('Bussiness', 'bussiness'); -INSERT INTO categories (name, slug) VALUES ('Backend', 'backend'); +INSERT INTO categories (name, slug) VALUES ('Marketing', 'marketing'); INSERT INTO categories (name, slug) VALUES ('Frontend', 'frontend'); +INSERT INTO categories (name, slug) VALUES ('Backend', 'backend'); INSERT INTO categories (name, slug) VALUES ('Infrastructure', 'infrastructure'); -INSERT INTO categories (name, slug) VALUES ('Marketing', 'marketing'); +INSERT INTO categories (name, slug) VALUES ('System Design', 'system-design'); UPDATE articles SET category_id = 1 WHERE id = 1; UPDATE articles SET category_id = 2 WHERE id = 2; @@ -18,7 +19,11 @@ UPDATE articles SET category_id = 3 WHERE id = 3; -- +goose StatementBegin SELECT 'down SQL query'; -DELETE FROM categories WHERE 'name' = 'category-1'; -DELETE FROM categories WHERE 'name' = 'category-2'; -DELETE FROM categories WHERE 'name' = 'category-3'; +DELETE FROM categories WHERE 'name' = 'Agile'; +DELETE FROM categories WHERE 'name' = 'Bussiness'; +DELETE FROM categories WHERE 'name' = 'Backend'; +DELETE FROM categories WHERE 'name' = 'Frontend'; +DELETE FROM categories WHERE 'name' = 'Infrastructure'; +DELETE FROM categories WHERE 'name' = 'Marketing'; +DELETE FROM categories WHERE 'name' = 'System Design'; -- +goose StatementEnd From 1c47c662482be7712131aaaef526fbf2f70df97e Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Mon, 23 Oct 2023 20:59:01 +0900 Subject: [PATCH 10/12] add: batch category --- backend/domain/model/category.go | 1 - batch/qiita/src/main.rs | 14 +++++++++++++- batch/qiita/src/tag_category_map.rs | 4 ++-- migrations/db/20221013200749_create_categories.sql | 1 - 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/backend/domain/model/category.go b/backend/domain/model/category.go index 5b420256..cc85ba95 100644 --- a/backend/domain/model/category.go +++ b/backend/domain/model/category.go @@ -7,6 +7,5 @@ type Category struct { Name string `json:"name"` Slug string `json:"slug"` Description string `json:"description"` - ParentId int `json:"parentId"` CreatedAt time.Time `json:"createdAt"` } diff --git a/batch/qiita/src/main.rs b/batch/qiita/src/main.rs index 7b6c07a4..c314bbee 100644 --- a/batch/qiita/src/main.rs +++ b/batch/qiita/src/main.rs @@ -5,6 +5,7 @@ use tokio_postgres::{NoTls}; mod qiita_response; mod tag_map; +mod tag_category_map; #[derive(Debug)] struct Tag { @@ -108,6 +109,7 @@ async fn main() -> Result<(), Box> { } // Insert articles from Qiita + let tag_category_map = tag_category_map::create_map(); for r in res { let check = db_client.query("SELECT * FROM articles WHERE title = $1", &[&r.title]).await?; if check.len() != 0 { @@ -115,7 +117,17 @@ async fn main() -> Result<(), Box> { continue; } - let inserted_data = db_client.query("INSERT INTO articles (user_id, thumbnail_url, title, content, status) VALUES ($1, $2, $3, $4, $5) RETURNING id", &[&1, &"",&r.title, &r.body, &2]).await?; + let mut category_id : i32 = Default::default(); + for t in &r.tags { + if !tag_category_map.get(&t.name.as_str()).is_none() { + println!("{}: {}", t.name, tag_category_map.get(&t.name.as_str()).unwrap()); + let categpory_name = tag_category_map.get(&t.name.as_str()).unwrap().to_string(); + let query_get_cagterogry = db_client.query("SELECT id FROM categories WHERE name = $1", &[&categpory_name]).await?; + category_id = query_get_cagterogry[0].get("id"); + } + } + + let inserted_data = db_client.query("INSERT INTO articles (user_id, thumbnail_url, title, content, status, category_id) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id", &[&1, &"",&r.title, &r.body, &2, &category_id]).await?; let inserted_id: i32 = inserted_data[0].get("id"); for t in r.tags { // insert tag if not exists diff --git a/batch/qiita/src/tag_category_map.rs b/batch/qiita/src/tag_category_map.rs index d8063104..596dcfdc 100644 --- a/batch/qiita/src/tag_category_map.rs +++ b/batch/qiita/src/tag_category_map.rs @@ -4,10 +4,10 @@ pub fn create_map() -> HashMap<&'static str, &'static str> { let mut tag_category: HashMap<&str, &str> = HashMap::new(); tag_category.insert("インフラ", "Infrastructure"); - tag_category.insert("アジャイル", "agile"); + tag_category.insert("アジャイル", "Agile"); tag_category.insert("ビジネス", "Bussiness"); tag_category.insert("マーケティング", "Marketing"); - tag_category.insert("kubernetes", "kubernetes"); + tag_category.insert("kubernetes", "Infrastructure"); tag_category.insert("Docker", "Infrastructure"); tag_category.insert("要件定義", "System Design"); tag_category.insert("ワイヤーフレーム", "System Design"); diff --git a/migrations/db/20221013200749_create_categories.sql b/migrations/db/20221013200749_create_categories.sql index 67ae2482..a1da7463 100644 --- a/migrations/db/20221013200749_create_categories.sql +++ b/migrations/db/20221013200749_create_categories.sql @@ -8,7 +8,6 @@ CREATE TABLE categories ( name varchar(255) NOT NULL, slug varchar(255) NOT NULL, description varchar(255), - parent_id INTEGER, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (parent_id) REFERENCES categories(id) ); From e898fdd675c2e9f6226147c13b11c693c9c49ef1 Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Mon, 23 Oct 2023 21:36:10 +0900 Subject: [PATCH 11/12] add: get article by category api --- backend/infrastructure/persistence/article.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/infrastructure/persistence/article.go b/backend/infrastructure/persistence/article.go index c405c740..662292c5 100644 --- a/backend/infrastructure/persistence/article.go +++ b/backend/infrastructure/persistence/article.go @@ -55,8 +55,9 @@ func (ap *articlePersistence) GetPager(article *model.Article) (int, error) { func (ap *articlePersistence) GetArticlesByCategory(articles *[]model.Article, slug string) error { return ap.Reprica(). // Preload("User"). - Preload("Tags"). Preload("Category"). + Preload("Tags"). + Joins("LEFT JOIN categories AS category ON articles.category_id = category.id"). Where("category.slug = ?", slug). Find(&articles).Error } From 3530ebaf2785f806b3bf39f95a7a282d7da21c2e Mon Sep 17 00:00:00 2001 From: yoshihiro-shu Date: Mon, 23 Oct 2023 21:40:22 +0900 Subject: [PATCH 12/12] add: omitempty --- backend/domain/model/article.go | 24 ++++++++++++------------ backend/domain/model/category.go | 10 +++++----- backend/domain/model/refresh_token.go | 14 +++++++------- backend/domain/model/tag.go | 10 +++++----- backend/domain/model/user.go | 10 +++++----- 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/backend/domain/model/article.go b/backend/domain/model/article.go index 11fa9726..b67906f6 100644 --- a/backend/domain/model/article.go +++ b/backend/domain/model/article.go @@ -5,18 +5,18 @@ import ( ) type Article struct { - Id int `gorm:"primaryKey;" json:"id"` - UserId int `json:"userId"` - ThumbnailUrl string `json:"thumbnailUrl"` - Title string `json:"title"` - Content string `json:"content"` - Status int `json:"status"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - CategoryId int `json:"categoryId"` - User *User `gorm:"foreignKey:UserId;" json:"user"` - Category *Category `gorm:"foreignKey:CategoryId;" json:"category"` - Tags []Tag `gorm:"many2many:article_tags;" json:"tags"` + Id int `gorm:"primaryKey;" json:"id,omitempty"` + UserId int `json:"userId,omitempty"` + ThumbnailUrl string `json:"thumbnailUrl,omitempty"` + Title string `json:"title,omitempty"` + Content string `json:"content,omitempty"` + Status int `json:"status,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty"` + UpdatedAt time.Time `json:"updatedAt,omitempty"` + CategoryId int `json:"categoryId,omitempty"` + User *User `gorm:"foreignKey:UserId;" json:"user,omitempty"` + Category *Category `gorm:"foreignKey:CategoryId;" json:"category,omitempty"` + Tags []Tag `gorm:"many2many:article_tags;" json:"tags,omitempty"` } func NewArticle(Id int) *Article { diff --git a/backend/domain/model/category.go b/backend/domain/model/category.go index cc85ba95..e778a604 100644 --- a/backend/domain/model/category.go +++ b/backend/domain/model/category.go @@ -3,9 +3,9 @@ package model import "time" type Category struct { - Id int `gorm:"primaryKey;" json:"id"` - Name string `json:"name"` - Slug string `json:"slug"` - Description string `json:"description"` - CreatedAt time.Time `json:"createdAt"` + Id int `gorm:"primaryKey;" json:"id,omitempty"` + Name string `json:"name,omitempty"` + Slug string `json:"slug,omitempty"` + Description string `json:"description,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty"` } diff --git a/backend/domain/model/refresh_token.go b/backend/domain/model/refresh_token.go index 457df0b6..0026a0e0 100644 --- a/backend/domain/model/refresh_token.go +++ b/backend/domain/model/refresh_token.go @@ -5,11 +5,11 @@ import ( ) type RefreshToken struct { - Id int `json:"id"` - UserId int `json:"user_id"` - JwtId string `json:"jwt_id"` - ExpiredAt time.Time `json:"expired_at"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - User *User `gorm:"foreignKey:user_id;" json:"user"` + Id int `json:"id,omitempty"` + UserId int `json:"user_id,omitempty"` + JwtId string `json:"jwt_id,omitempty"` + ExpiredAt time.Time `json:"expired_at,omitempty"` + CreatedAt time.Time `json:"created_at,omitempty"` + UpdatedAt time.Time `json:"updated_at,omitempty"` + User *User `gorm:"foreignKey:user_id;" json:"user,omitempty"` } diff --git a/backend/domain/model/tag.go b/backend/domain/model/tag.go index c132bf45..280b66ea 100644 --- a/backend/domain/model/tag.go +++ b/backend/domain/model/tag.go @@ -3,11 +3,11 @@ package model import "time" type Tag struct { - Id int `gorm:"primaryKey;" json:"id"` - Name string `json:"name"` - Slug string `json:"slug"` - Description string `json:"description"` - CreatedAt time.Time `json:"createdAt"` + Id int `gorm:"primaryKey;" json:"id,omitempty"` + Name string `json:"name,omitempty"` + Slug string `json:"slug,omitempty"` + Description string `json:"description,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty"` } type ArticleTags struct { diff --git a/backend/domain/model/user.go b/backend/domain/model/user.go index 1ed10347..de986dfe 100644 --- a/backend/domain/model/user.go +++ b/backend/domain/model/user.go @@ -3,11 +3,11 @@ package model import "time" type User struct { - Id int `gorm:"primaryKey;" json:"id"` - Name string `json:"name"` - Password string `json:"password"` - Email string `json:"email"` - CreatedAt time.Time `json:"createdAt"` + Id int `gorm:"primaryKey;" json:"id,omitempty"` + Name string `json:"name,omitempty"` + Password string `json:"password,omitempty"` + Email string `json:"email,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty"` } func NewUser(name, password, email string) *User {