diff --git a/.air.toml b/.air.toml
index a770bbd..cc88d09 100644
--- a/.air.toml
+++ b/.air.toml
@@ -7,7 +7,7 @@ tmp_dir = "tmp"
bin = "tmp\\main.exe"
cmd = "go build -o ./tmp/main.exe ./main"
delay = 1000
- exclude_dir = ["assets", "tmp", "vendor", "testdata", "api\\static\\tinymce", "api\\static\\bootstrap-icons"]
+ exclude_dir = ["assets", "tmp", "vendor", "testdata", "api\\static\\tinymce", "api\\static\\bootstrap-icons", "api\\static\\uploadedImages"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
diff --git a/README.md b/README.md
index cc4c7fc..dc46fe3 100644
--- a/README.md
+++ b/README.md
@@ -46,7 +46,7 @@ of course required, but not necessarily via the `.env` file.
| PORT | int | port the API will use | required |
| JWT_SECRET | string | secret for the jwt auth | required |
| CORS_ALLOWED_ORIGINS | string | allowed origins for CORS | required, semicolon separated list |
-| DB_FILE | string | path to the sqlite db file | required, can be at the root but name still required (e.g. `./gocms.db`) ; have to end up with `.db` |
+| DB_FILE | string | path to the sqlite db file | required, can be at the root but name still required (e.g. `./gocms.db`) ; have to end up with `.db` |
| DOCKER_DB_FOLDER | string | path to the sqlite db file's folder | required with docker, this will basically be the host machine folder (e.g. `./data`) that contains the sqlite db file |
| SMTP_EMAIL | string | sender email | required |
| SMTP_PASSWORD | string | smtp account password | required |
diff --git a/adapters/secondary/gateways/imageRepository.go b/adapters/secondary/gateways/imageRepository.go
new file mode 100644
index 0000000..be625ce
--- /dev/null
+++ b/adapters/secondary/gateways/imageRepository.go
@@ -0,0 +1,85 @@
+package gateways
+
+import (
+ entity "GoCMS/adapters/secondary/gateways/models"
+ "GoCMS/domain/gateways"
+ domain "GoCMS/domain/image"
+ "errors"
+ "github.com/google/uuid"
+ "gorm.io/gorm"
+ "mime/multipart"
+ "os"
+)
+
+type ImageRepository struct {
+ db *gorm.DB
+}
+
+func NewImageRepository(db *gorm.DB) *ImageRepository {
+ return &ImageRepository{db}
+}
+
+var contentTypeExtensions = map[string]string{
+ "image/png": ".png",
+ "image/jpeg": ".jpeg",
+ "image/webp": ".webp",
+ "image/svg+xml": ".svg",
+}
+
+func mapImageToDomain(image entity.Image) domain.Image {
+ return domain.FromDB(
+ image.ID,
+ image.Path,
+ image.PostID,
+ image.CreatedAt,
+ image.UpdatedAt,
+ )
+}
+
+func (i ImageRepository) Create(file multipart.File, fileHeader multipart.FileHeader) (domain.Image, error) {
+ fileBytes := make([]byte, fileHeader.Size)
+ _, err := file.Read(fileBytes)
+ if err != nil {
+ return domain.Image{}, err
+ }
+
+ err = os.MkdirAll("api/static/uploadedImages/", 0666)
+ if err != nil {
+ return domain.Image{}, err
+ }
+
+ contentType := fileHeader.Header.Get("Content-Type")
+ extension := contentTypeExtensions[contentType]
+ if extension == "" {
+ return domain.Image{}, errors.New("the file must be a PNG, JPEG, WEBP, or SVG image")
+ }
+
+ newName := uuid.NewString() + extension
+ err = os.WriteFile("api/static/uploadedImages/"+newName, fileBytes, 0666)
+ if err != nil {
+ return domain.Image{}, err
+ }
+
+ newImage := i.db.Create(&domain.Image{Path: "/static/uploadedImages/" + newName})
+ var createdImage entity.Image
+ newImage.Scan(&createdImage)
+
+ return mapImageToDomain(createdImage), nil
+}
+
+func (i ImageRepository) Delete(id uint32) error {
+ var image entity.Image
+ err := i.db.Model(&entity.Image{}).First(&image, id).Error
+ if err != nil {
+ return err
+ }
+
+ err = os.Remove("api" + image.Path)
+ if err != nil {
+ return err
+ }
+
+ return i.db.Delete(&entity.Image{}, id).Error
+}
+
+var _ gateways.IImageRepository = &ImageRepository{}
diff --git a/adapters/secondary/gateways/models/image.go b/adapters/secondary/gateways/models/image.go
new file mode 100644
index 0000000..6430f07
--- /dev/null
+++ b/adapters/secondary/gateways/models/image.go
@@ -0,0 +1,15 @@
+package models
+
+import (
+ "gorm.io/gorm"
+ "time"
+)
+
+type Image struct {
+ gorm.Model
+ ID uint32 `gorm:"primary_key;auto_increment;not_null"`
+ Path string
+ PostID uint32
+ CreatedAt time.Time `gorm:"autoCreateTime"`
+ UpdatedAt time.Time `gorm:"autoUpdateTime"`
+}
diff --git a/adapters/secondary/gateways/models/post.go b/adapters/secondary/gateways/models/post.go
index f0bd730..497afda 100644
--- a/adapters/secondary/gateways/models/post.go
+++ b/adapters/secondary/gateways/models/post.go
@@ -10,6 +10,7 @@ type Post struct {
ID uint32 `gorm:"primary_key;auto_increment;not_null"`
Title string
Body string
+ Images []*Image `gorm:"many2many:post_images;"`
CreatedAt time.Time `gorm:"autoCreateTime"`
UpdatedAt time.Time `gorm:"autoUpdateTime"`
}
diff --git a/adapters/secondary/gateways/postRepository.go b/adapters/secondary/gateways/postRepository.go
index a3ec04c..068d1e3 100644
--- a/adapters/secondary/gateways/postRepository.go
+++ b/adapters/secondary/gateways/postRepository.go
@@ -16,12 +16,12 @@ func NewPostRepository(db *gorm.DB) *PostRepository {
}
func mapPostToDomain(post entity.Post) domain.Post {
- return domain.FromDb(post.ID, post.Title, post.Body, post.CreatedAt, post.UpdatedAt)
+ return domain.FromDb(post.ID, post.Title, post.Body, post.Images, post.CreatedAt, post.UpdatedAt)
}
func (a *PostRepository) Get(id uint32) (domain.Post, error) {
var post entity.Post
- err := a.db.Model(&entity.Post{}).First(&post, id).Error
+ err := a.db.Model(&entity.Post{}).Preload("Images").First(&post, id).Error
if err != nil {
return domain.Post{}, err
}
@@ -69,15 +69,49 @@ func (a *PostRepository) GetAll() []domain.Post {
return domainPosts
}
-func (a *PostRepository) UpdateBody(id uint32, body string) error {
+func (a *PostRepository) UpdateBody(id uint32, body string) (domain.Post, error) {
var localPost entity.Post
err := a.db.Model(&entity.Post{}).First(&localPost, id).Error
if err != nil {
- return err
+ return domain.Post{}, err
}
localPost.Body = body
err = a.db.Save(&localPost).Error
+ if err != nil {
+ return domain.Post{}, err
+ }
+
+ newPost := domain.FromDb(
+ localPost.ID,
+ localPost.Title,
+ localPost.Body,
+ localPost.Images,
+ localPost.CreatedAt,
+ localPost.UpdatedAt,
+ )
+
+ return newPost, nil
+}
+
+func (a *PostRepository) Delete(id uint32) error {
+ return a.db.Delete(&entity.Post{}, id).Error
+}
+
+func (a *PostRepository) AddImage(postId uint32, imageId uint32) error {
+ var localPost entity.Post
+ err := a.db.Model(&entity.Post{}).First(&localPost, postId).Error
+ if err != nil {
+ return err
+ }
+
+ var localImage entity.Image
+ err = a.db.Model(&entity.Image{}).First(&localImage, imageId).Error
+ if err != nil {
+ return err
+ }
+
+ err = a.db.Model(&localPost).Association("Images").Append(&localImage)
if err != nil {
return err
}
@@ -85,8 +119,4 @@ func (a *PostRepository) UpdateBody(id uint32, body string) error {
return nil
}
-func (a *PostRepository) Delete(id uint32) error {
- return a.db.Delete(&entity.Post{}, id).Error
-}
-
var _ gateways.IPostRepository = &PostRepository{}
diff --git a/adapters/secondary/gateways/web/templates/postEdit.html b/adapters/secondary/gateways/web/templates/postEdit.html
index 2ce750e..7d50d86 100644
--- a/adapters/secondary/gateways/web/templates/postEdit.html
+++ b/adapters/secondary/gateways/web/templates/postEdit.html
@@ -30,7 +30,7 @@
-
+
@@ -49,43 +49,43 @@
},
license_key: 'gpl',
images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
- // const xhr = new XMLHttpRequest();
- // xhr.withCredentials = false;
- // xhr.open('POST', 'postAcceptor.php');
- //
- // xhr.upload.onprogress = (e) => {
- // progress(e.loaded / e.total * 100);
- // };
- //
- // xhr.onload = () => {
- // if (xhr.status === 403) {
- // reject({message: 'HTTP Error: ' + xhr.status, remove: true});
- // return;
- // }
- //
- // if (xhr.status < 200 || xhr.status >= 300) {
- // reject('HTTP Error: ' + xhr.status);
- // return;
- // }
- //
- // const json = JSON.parse(xhr.responseText);
- //
- // if (!json || typeof json.location != 'string') {
- // reject('Invalid JSON: ' + xhr.responseText);
- // return;
- // }
- //
- // resolve(json.location);
- // };
- //
- // xhr.onerror = () => {
- // reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
- // };
- //
- // const formData = new FormData();
- // formData.append('file', blobInfo.blob(), blobInfo.filename());
- //
- // xhr.send(formData);
+ const xhr = new XMLHttpRequest();
+ xhr.withCredentials = false;
+ xhr.open('POST', `/post/{{.Post.ID}}/image/create`);
+
+ xhr.upload.onprogress = (e) => {
+ progress(e.loaded / e.total * 100);
+ };
+
+ xhr.onload = () => {
+ if (xhr.status === 403) {
+ reject({message: 'HTTP Error: ' + xhr.status, remove: true});
+ return;
+ }
+
+ if (xhr.status < 200 || xhr.status >= 300) {
+ reject('HTTP Error: ' + xhr.status);
+ return;
+ }
+
+ const json = JSON.parse(xhr.responseText);
+
+ if (!json || typeof json.location != 'string') {
+ reject('Invalid JSON: ' + xhr.responseText);
+ return;
+ }
+
+ resolve(`http{{ if .Secured }}s{{ end }}://${window.location.host}${json.location}`);
+ };
+
+ xhr.onerror = () => {
+ reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
+ };
+
+ const formData = new FormData();
+ formData.append('file', blobInfo.blob(), blobInfo.filename());
+
+ xhr.send(formData);
}),
})
diff --git a/api/dependecyInjection.go b/api/dependecyInjection.go
index 21d83e2..557616a 100644
--- a/api/dependecyInjection.go
+++ b/api/dependecyInjection.go
@@ -11,18 +11,20 @@ import (
)
type UseCases struct {
- CreatePostUseCase *useCases.CreatePostUseCase
- GetPostUseCase *useCases.GetPostUseCase
- ListPostsUseCase *useCases.ListPostsUseCase
- UpdatePostUseCase *useCases.UpdatePostUseCase
- DeletePostUseCase *useCases.DeletePostUseCase
- GetUserUseCase *useCases.GetUserUseCase
- CreateUserUseCase *useCases.CreateUserUseCase
- UpdateUserUseCase *useCases.UpdateUserUseCase
- DeleteUserUseCase *useCases.DeleteUserUseCase
- ListUsersUseCase *useCases.ListUsersUseCase
- GetPageUseCase *useCases.GetPageUseCase
- SendMailUseCase *useCases.SendMailUseCase
+ CreatePostUseCase *useCases.CreatePostUseCase
+ GetPostUseCase *useCases.GetPostUseCase
+ ListPostsUseCase *useCases.ListPostsUseCase
+ UpdatePostUseCase *useCases.UpdatePostUseCase
+ DeletePostUseCase *useCases.DeletePostUseCase
+ GetUserUseCase *useCases.GetUserUseCase
+ CreateUserUseCase *useCases.CreateUserUseCase
+ UpdateUserUseCase *useCases.UpdateUserUseCase
+ DeleteUserUseCase *useCases.DeleteUserUseCase
+ ListUsersUseCase *useCases.ListUsersUseCase
+ GetPageUseCase *useCases.GetPageUseCase
+ SendMailUseCase *useCases.SendMailUseCase
+ CreateImageUseCase *useCases.CreateImageUseCase
+ DeleteImageUseCase *useCases.DeleteImageUseCase
}
var Container *UseCases
@@ -48,18 +50,20 @@ func InitContainer() {
_ = digContainer.Provide(func(db *gorm.DB) *UseCases {
return &UseCases{
- CreatePostUseCase: useCases.NewCreatePostUseCase(db),
- GetPostUseCase: useCases.NewGetPostUseCase(db),
- ListPostsUseCase: useCases.NewListPostsUseCase(db),
- UpdatePostUseCase: useCases.NewUpdatePostUseCase(db),
- DeletePostUseCase: useCases.NewDeletePostUseCase(db),
- GetUserUseCase: useCases.NewGetUserUseCase(db),
- CreateUserUseCase: useCases.NewCreateUserUseCase(db),
- UpdateUserUseCase: useCases.NewUpdateUserUseCase(db),
- DeleteUserUseCase: useCases.NewDeleteUserUseCase(db),
- ListUsersUseCase: useCases.NewListUsersUseCase(db),
- GetPageUseCase: useCases.NewGetPageUseCase(),
- SendMailUseCase: useCases.NewSendMailUseCase(),
+ CreatePostUseCase: useCases.NewCreatePostUseCase(db),
+ GetPostUseCase: useCases.NewGetPostUseCase(db),
+ ListPostsUseCase: useCases.NewListPostsUseCase(db),
+ UpdatePostUseCase: useCases.NewUpdatePostUseCase(db),
+ DeletePostUseCase: useCases.NewDeletePostUseCase(db),
+ GetUserUseCase: useCases.NewGetUserUseCase(db),
+ CreateUserUseCase: useCases.NewCreateUserUseCase(db),
+ UpdateUserUseCase: useCases.NewUpdateUserUseCase(db),
+ DeleteUserUseCase: useCases.NewDeleteUserUseCase(db),
+ ListUsersUseCase: useCases.NewListUsersUseCase(db),
+ GetPageUseCase: useCases.NewGetPageUseCase(),
+ SendMailUseCase: useCases.NewSendMailUseCase(),
+ CreateImageUseCase: useCases.NewCreateImageUseCase(db),
+ DeleteImageUseCase: useCases.NewDeleteImageUseCase(db),
}
})
err := digContainer.Invoke(func(useCases *UseCases) { Container = useCases })
diff --git a/api/image.go b/api/image.go
new file mode 100644
index 0000000..53e48c7
--- /dev/null
+++ b/api/image.go
@@ -0,0 +1,38 @@
+package api
+
+import (
+ "encoding/json"
+ "github.com/go-chi/chi/v5"
+ "net/http"
+ "strconv"
+)
+
+func postImage(w http.ResponseWriter, r *http.Request) {
+ _ = r.ParseForm()
+
+ id := chi.URLParam(r, "id")
+ idInt, _ := strconv.Atoi(id)
+
+ file, fileHeader, err := r.FormFile("file")
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+
+ newImage, err := Container.CreateImageUseCase.CreateImage(file, *fileHeader)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ err = Container.UpdatePostUseCase.AddImage(uint32(idInt), newImage.ID)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ newJson := map[string]interface{}{"location": newImage.Path}
+ newJsonBytes, _ := json.Marshal(newJson)
+
+ _, _ = w.Write(newJsonBytes)
+}
diff --git a/api/page.go b/api/page.go
index acf667f..0cd8885 100644
--- a/api/page.go
+++ b/api/page.go
@@ -1,18 +1,13 @@
package api
import (
- "embed"
"github.com/go-chi/chi/v5"
"html/template"
- "io/fs"
"net/http"
"path/filepath"
"strings"
)
-//go:embed static
-var staticFolder embed.FS
-
var headTmpl template.HTML
var contentTypes = map[string]string{
@@ -97,11 +92,10 @@ func InitHeadTmpl() {
func NewPageRouter() http.Handler {
r := chi.NewRouter()
- contentStatic := fs.FS(staticFolder)
-
InitHeadTmpl()
- r.Handle("/static/*", StaticFileServerWithContentType(http.FS(contentStatic)))
+ fileServer := StaticFileServerWithContentType(http.Dir("api/static"))
+ r.Handle("/static/*", http.StripPrefix("/static/", fileServer))
r.Get("/", GetLogin)
r.Get(LoginRoute, GetLoginPageHandler(EmptyLoginPage))
@@ -128,6 +122,7 @@ func NewPageRouter() http.Handler {
r.Get("/post/{id}/delete", GetPostDeletePage)
r.Get("/post/create", GetPostCreatePage)
r.Post("/post/create", PostPostCreatePage)
+ r.Post("/post/{id}/image/create", postImage)
})
return r
diff --git a/api/pagePostDelete.go b/api/pagePostDelete.go
index 2d4ea3a..ccc0784 100644
--- a/api/pagePostDelete.go
+++ b/api/pagePostDelete.go
@@ -1,6 +1,7 @@
package api
import (
+ "fmt"
"github.com/go-chi/chi/v5"
"net/http"
"strconv"
@@ -13,6 +14,21 @@ func GetPostDeletePage(w http.ResponseWriter, r *http.Request) {
return
}
+ localPost, err := Container.GetPostUseCase.GetPost(uint32(id))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusNotFound)
+ return
+ }
+
+ fmt.Println(localPost.Images)
+ for _, image := range localPost.Images {
+ err = Container.DeleteImageUseCase.DeleteImage(image.ID)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusNotFound)
+ return
+ }
+ }
+
err = Container.DeletePostUseCase.DeletePost(uint32(id))
if err != nil {
http.Error(w, http.StatusText(400), http.StatusBadRequest)
diff --git a/api/pagePostEdit.go b/api/pagePostEdit.go
index a706756..7f1e544 100644
--- a/api/pagePostEdit.go
+++ b/api/pagePostEdit.go
@@ -1,9 +1,11 @@
package api
import (
+ "GoCMS/domain/post"
"github.com/go-chi/chi/v5"
"html/template"
"net/http"
+ "os"
"strconv"
)
@@ -12,13 +14,14 @@ type PostEditPageAlert struct {
Message string
}
-func getPostEditPageTemplate(body string, alert PostEditPageAlert) []byte {
+func getPostEditPageTemplate(post post.Post, alert PostEditPageAlert) []byte {
navbarTmpl, _ := Container.GetPageUseCase.GetPage("componentNavbar", nil)
postTmpl, _ := Container.GetPageUseCase.GetPage("postEdit", map[string]interface{}{
- "Navbar": template.HTML(navbarTmpl),
- "Head": headTmpl,
- "Body": body,
- "Alert": alert,
+ "Navbar": template.HTML(navbarTmpl),
+ "Head": headTmpl,
+ "Post": post,
+ "Alert": alert,
+ "Secured": os.Getenv("ENVIRONMENT") == "production",
})
return postTmpl
}
@@ -27,7 +30,7 @@ func PostPostEditPage(w http.ResponseWriter, r *http.Request) {
postID := chi.URLParam(r, "id")
postIDint, err := strconv.Atoi(postID)
if err != nil {
- _, _ = w.Write(getPostEditPageTemplate("", PostEditPageAlert{
+ _, _ = w.Write(getPostEditPageTemplate(post.Post{}, PostEditPageAlert{
IsError: true,
Message: "Could not find the requested post.",
}))
@@ -37,17 +40,17 @@ func PostPostEditPage(w http.ResponseWriter, r *http.Request) {
_ = r.ParseForm()
postBody := r.FormValue("postBody")
- post, _ := Container.GetPostUseCase.GetPost(uint32(postIDint))
- err = Container.UpdatePostUseCase.UpdateBody(post.ID, postBody)
+ getPost, _ := Container.GetPostUseCase.GetPost(uint32(postIDint))
+ updatedPost, err := Container.UpdatePostUseCase.UpdateBody(getPost.ID, postBody)
if err != nil {
- _, _ = w.Write(getPostEditPageTemplate(postBody, PostEditPageAlert{
+ _, _ = w.Write(getPostEditPageTemplate(post.Post{Body: postBody}, PostEditPageAlert{
IsError: true,
Message: "Could not save the post: " + err.Error(),
}))
return
}
- _, _ = w.Write(getPostEditPageTemplate(postBody, PostEditPageAlert{
+ _, _ = w.Write(getPostEditPageTemplate(updatedPost, PostEditPageAlert{
IsError: false,
Message: "Post successfully edited!",
}))
@@ -61,9 +64,9 @@ func GetPostEditPage(w http.ResponseWriter, r *http.Request) {
return
}
- post, _ := Container.GetPostUseCase.GetPost(uint32(postIDint))
+ getPost, _ := Container.GetPostUseCase.GetPost(uint32(postIDint))
- _, _ = w.Write(getPostEditPageTemplate(post.Body, PostEditPageAlert{
+ _, _ = w.Write(getPostEditPageTemplate(getPost, PostEditPageAlert{
IsError: false,
Message: "",
}))
diff --git a/domain/gateways/IImageRepository.go b/domain/gateways/IImageRepository.go
new file mode 100644
index 0000000..0443ddb
--- /dev/null
+++ b/domain/gateways/IImageRepository.go
@@ -0,0 +1,11 @@
+package gateways
+
+import (
+ "GoCMS/domain/image"
+ "mime/multipart"
+)
+
+type IImageRepository interface {
+ Create(file multipart.File, fileHeader multipart.FileHeader) (image.Image, error)
+ Delete(id uint32) error
+}
diff --git a/domain/gateways/IPostRepository.go b/domain/gateways/IPostRepository.go
index 66fe876..857ecbe 100644
--- a/domain/gateways/IPostRepository.go
+++ b/domain/gateways/IPostRepository.go
@@ -9,6 +9,7 @@ type IPostRepository interface {
GetByName(name string) (post.Post, error)
GetAll() []post.Post
Create(post post.Post) (post.Post, error)
- UpdateBody(id uint32, body string) error
+ UpdateBody(id uint32, body string) (post.Post, error)
Delete(id uint32) error
+ AddImage(postId uint32, imageId uint32) error
}
diff --git a/domain/image/image.go b/domain/image/image.go
new file mode 100644
index 0000000..2f83483
--- /dev/null
+++ b/domain/image/image.go
@@ -0,0 +1,23 @@
+package image
+
+import (
+ "time"
+)
+
+type Image struct {
+ ID uint32
+ Path string
+ PostID uint32
+ CreatedAt time.Time
+ UpdatedAt time.Time
+}
+
+func FromDB(id uint32, path string, postId uint32, createdAt time.Time, updatedAt time.Time) Image {
+ return Image{
+ ID: id,
+ Path: path,
+ PostID: postId,
+ CreatedAt: createdAt,
+ UpdatedAt: updatedAt,
+ }
+}
diff --git a/domain/post/post.go b/domain/post/post.go
index 2a42e0f..40e16c3 100644
--- a/domain/post/post.go
+++ b/domain/post/post.go
@@ -1,13 +1,18 @@
package post
-import "time"
+import (
+ entity "GoCMS/adapters/secondary/gateways/models"
+ domain "GoCMS/domain/image"
+ "time"
+)
type Post struct {
- ID uint32 `json:"id"`
- Title string `json:"title"`
- Body string `json:"body"`
- CreatedAt time.Time `json:"created_at"`
- UpdatedAt time.Time `json:"updated_at"`
+ ID uint32 `json:"id"`
+ Title string `json:"title"`
+ Body string `json:"body"`
+ Images []*domain.Image `json:"images"`
+ CreatedAt time.Time `json:"created_at"`
+ UpdatedAt time.Time `json:"updated_at"`
}
func FromApi(
@@ -24,13 +29,26 @@ func FromDb(
id uint32,
title string,
body string,
+ images []*entity.Image,
createdAt time.Time,
updatedAt time.Time,
) Post {
+ domainImages := make([]*domain.Image, len(images))
+ for i, img := range images {
+ domainImage := domain.FromDB(
+ img.ID,
+ img.Path,
+ img.PostID,
+ img.CreatedAt,
+ img.UpdatedAt,
+ )
+ domainImages[i] = &domainImage
+ }
return Post{
ID: id,
Title: title,
Body: body,
+ Images: domainImages,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
}
diff --git a/useCases/CreateImageUseCase.go b/useCases/CreateImageUseCase.go
new file mode 100644
index 0000000..c598a5f
--- /dev/null
+++ b/useCases/CreateImageUseCase.go
@@ -0,0 +1,22 @@
+package useCases
+
+import (
+ "GoCMS/adapters/secondary/gateways"
+ "GoCMS/domain/image"
+ "gorm.io/gorm"
+ "mime/multipart"
+)
+
+type CreateImageUseCase struct {
+ imageRepository gateways.ImageRepository
+}
+
+func NewCreateImageUseCase(db *gorm.DB) *CreateImageUseCase {
+ return &CreateImageUseCase{
+ imageRepository: *gateways.NewImageRepository(db),
+ }
+}
+
+func (g *CreateImageUseCase) CreateImage(file multipart.File, fileHeader multipart.FileHeader) (image.Image, error) {
+ return g.imageRepository.Create(file, fileHeader)
+}
diff --git a/useCases/DeleteImageUseCase.go b/useCases/DeleteImageUseCase.go
new file mode 100644
index 0000000..c1e63e9
--- /dev/null
+++ b/useCases/DeleteImageUseCase.go
@@ -0,0 +1,20 @@
+package useCases
+
+import (
+ "GoCMS/adapters/secondary/gateways"
+ "gorm.io/gorm"
+)
+
+type DeleteImageUseCase struct {
+ imageRepository gateways.ImageRepository
+}
+
+func NewDeleteImageUseCase(db *gorm.DB) *DeleteImageUseCase {
+ return &DeleteImageUseCase{
+ imageRepository: *gateways.NewImageRepository(db),
+ }
+}
+
+func (g *DeleteImageUseCase) DeleteImage(imageId uint32) error {
+ return g.imageRepository.Delete(imageId)
+}
diff --git a/useCases/UpdatePostUseCase.go b/useCases/UpdatePostUseCase.go
index 60b9b0f..2674830 100644
--- a/useCases/UpdatePostUseCase.go
+++ b/useCases/UpdatePostUseCase.go
@@ -2,6 +2,7 @@ package useCases
import (
"GoCMS/adapters/secondary/gateways"
+ "GoCMS/domain/post"
"gorm.io/gorm"
)
@@ -15,6 +16,10 @@ func NewUpdatePostUseCase(db *gorm.DB) *UpdatePostUseCase {
}
}
-func (g *UpdatePostUseCase) UpdateBody(id uint32, body string) error {
+func (g *UpdatePostUseCase) UpdateBody(id uint32, body string) (post.Post, error) {
return g.postRepository.UpdateBody(id, body)
}
+
+func (g *UpdatePostUseCase) AddImage(postId uint32, imageId uint32) error {
+ return g.postRepository.AddImage(postId, imageId)
+}