mirror of
https://github.com/Floriansylvain/RenewCMS.git
synced 2026-08-19 11:43:22 +02:00
feat: images
This commit is contained in:
@@ -7,7 +7,7 @@ tmp_dir = "tmp"
|
|||||||
bin = "tmp\\main.exe"
|
bin = "tmp\\main.exe"
|
||||||
cmd = "go build -o ./tmp/main.exe ./main"
|
cmd = "go build -o ./tmp/main.exe ./main"
|
||||||
delay = 1000
|
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_file = []
|
||||||
exclude_regex = ["_test.go"]
|
exclude_regex = ["_test.go"]
|
||||||
exclude_unchanged = false
|
exclude_unchanged = false
|
||||||
|
|||||||
@@ -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{}
|
||||||
@@ -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"`
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ type Post struct {
|
|||||||
ID uint32 `gorm:"primary_key;auto_increment;not_null"`
|
ID uint32 `gorm:"primary_key;auto_increment;not_null"`
|
||||||
Title string
|
Title string
|
||||||
Body string
|
Body string
|
||||||
|
Images []*Image `gorm:"many2many:post_images;"`
|
||||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ func NewPostRepository(db *gorm.DB) *PostRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mapPostToDomain(post entity.Post) domain.Post {
|
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) {
|
func (a *PostRepository) Get(id uint32) (domain.Post, error) {
|
||||||
var post entity.Post
|
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 {
|
if err != nil {
|
||||||
return domain.Post{}, err
|
return domain.Post{}, err
|
||||||
}
|
}
|
||||||
@@ -69,15 +69,49 @@ func (a *PostRepository) GetAll() []domain.Post {
|
|||||||
return domainPosts
|
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
|
var localPost entity.Post
|
||||||
err := a.db.Model(&entity.Post{}).First(&localPost, id).Error
|
err := a.db.Model(&entity.Post{}).First(&localPost, id).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return domain.Post{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
localPost.Body = body
|
localPost.Body = body
|
||||||
err = a.db.Save(&localPost).Error
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -85,8 +119,4 @@ func (a *PostRepository) UpdateBody(id uint32, body string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *PostRepository) Delete(id uint32) error {
|
|
||||||
return a.db.Delete(&entity.Post{}, id).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ gateways.IPostRepository = &PostRepository{}
|
var _ gateways.IPostRepository = &PostRepository{}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-black-50 d-flex align-items-center justify-content-center h-100 py-3">
|
<div class="text-black-50 d-flex align-items-center justify-content-center h-100 py-3">
|
||||||
<textarea id="postBody" name="postBody">{{.Body}}</textarea>
|
<textarea id="postBody" name="postBody">{{.Post.Body}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@@ -49,43 +49,43 @@
|
|||||||
},
|
},
|
||||||
license_key: 'gpl',
|
license_key: 'gpl',
|
||||||
images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
|
images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
|
||||||
// const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
// xhr.withCredentials = false;
|
xhr.withCredentials = false;
|
||||||
// xhr.open('POST', 'postAcceptor.php');
|
xhr.open('POST', `/post/{{.Post.ID}}/image/create`);
|
||||||
//
|
|
||||||
// xhr.upload.onprogress = (e) => {
|
xhr.upload.onprogress = (e) => {
|
||||||
// progress(e.loaded / e.total * 100);
|
progress(e.loaded / e.total * 100);
|
||||||
// };
|
};
|
||||||
//
|
|
||||||
// xhr.onload = () => {
|
xhr.onload = () => {
|
||||||
// if (xhr.status === 403) {
|
if (xhr.status === 403) {
|
||||||
// reject({message: 'HTTP Error: ' + xhr.status, remove: true});
|
reject({message: 'HTTP Error: ' + xhr.status, remove: true});
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// if (xhr.status < 200 || xhr.status >= 300) {
|
if (xhr.status < 200 || xhr.status >= 300) {
|
||||||
// reject('HTTP Error: ' + xhr.status);
|
reject('HTTP Error: ' + xhr.status);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// const json = JSON.parse(xhr.responseText);
|
const json = JSON.parse(xhr.responseText);
|
||||||
//
|
|
||||||
// if (!json || typeof json.location != 'string') {
|
if (!json || typeof json.location != 'string') {
|
||||||
// reject('Invalid JSON: ' + xhr.responseText);
|
reject('Invalid JSON: ' + xhr.responseText);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// resolve(json.location);
|
resolve(`http{{ if .Secured }}s{{ end }}://${window.location.host}${json.location}`);
|
||||||
// };
|
};
|
||||||
//
|
|
||||||
// xhr.onerror = () => {
|
xhr.onerror = () => {
|
||||||
// reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
|
reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
|
||||||
// };
|
};
|
||||||
//
|
|
||||||
// const formData = new FormData();
|
const formData = new FormData();
|
||||||
// formData.append('file', blobInfo.blob(), blobInfo.filename());
|
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
||||||
//
|
|
||||||
// xhr.send(formData);
|
xhr.send(formData);
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ type UseCases struct {
|
|||||||
ListUsersUseCase *useCases.ListUsersUseCase
|
ListUsersUseCase *useCases.ListUsersUseCase
|
||||||
GetPageUseCase *useCases.GetPageUseCase
|
GetPageUseCase *useCases.GetPageUseCase
|
||||||
SendMailUseCase *useCases.SendMailUseCase
|
SendMailUseCase *useCases.SendMailUseCase
|
||||||
|
CreateImageUseCase *useCases.CreateImageUseCase
|
||||||
|
DeleteImageUseCase *useCases.DeleteImageUseCase
|
||||||
}
|
}
|
||||||
|
|
||||||
var Container *UseCases
|
var Container *UseCases
|
||||||
@@ -60,6 +62,8 @@ func InitContainer() {
|
|||||||
ListUsersUseCase: useCases.NewListUsersUseCase(db),
|
ListUsersUseCase: useCases.NewListUsersUseCase(db),
|
||||||
GetPageUseCase: useCases.NewGetPageUseCase(),
|
GetPageUseCase: useCases.NewGetPageUseCase(),
|
||||||
SendMailUseCase: useCases.NewSendMailUseCase(),
|
SendMailUseCase: useCases.NewSendMailUseCase(),
|
||||||
|
CreateImageUseCase: useCases.NewCreateImageUseCase(db),
|
||||||
|
DeleteImageUseCase: useCases.NewDeleteImageUseCase(db),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
err := digContainer.Invoke(func(useCases *UseCases) { Container = useCases })
|
err := digContainer.Invoke(func(useCases *UseCases) { Container = useCases })
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
+3
-8
@@ -1,18 +1,13 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io/fs"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed static
|
|
||||||
var staticFolder embed.FS
|
|
||||||
|
|
||||||
var headTmpl template.HTML
|
var headTmpl template.HTML
|
||||||
|
|
||||||
var contentTypes = map[string]string{
|
var contentTypes = map[string]string{
|
||||||
@@ -97,11 +92,10 @@ func InitHeadTmpl() {
|
|||||||
func NewPageRouter() http.Handler {
|
func NewPageRouter() http.Handler {
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
|
|
||||||
contentStatic := fs.FS(staticFolder)
|
|
||||||
|
|
||||||
InitHeadTmpl()
|
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("/", GetLogin)
|
||||||
r.Get(LoginRoute, GetLoginPageHandler(EmptyLoginPage))
|
r.Get(LoginRoute, GetLoginPageHandler(EmptyLoginPage))
|
||||||
@@ -128,6 +122,7 @@ func NewPageRouter() http.Handler {
|
|||||||
r.Get("/post/{id}/delete", GetPostDeletePage)
|
r.Get("/post/{id}/delete", GetPostDeletePage)
|
||||||
r.Get("/post/create", GetPostCreatePage)
|
r.Get("/post/create", GetPostCreatePage)
|
||||||
r.Post("/post/create", PostPostCreatePage)
|
r.Post("/post/create", PostPostCreatePage)
|
||||||
|
r.Post("/post/{id}/image/create", postImage)
|
||||||
})
|
})
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -13,6 +14,21 @@ func GetPostDeletePage(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
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))
|
err = Container.DeletePostUseCase.DeletePost(uint32(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, http.StatusText(400), http.StatusBadRequest)
|
http.Error(w, http.StatusText(400), http.StatusBadRequest)
|
||||||
|
|||||||
+12
-9
@@ -1,9 +1,11 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"GoCMS/domain/post"
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -12,13 +14,14 @@ type PostEditPageAlert struct {
|
|||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPostEditPageTemplate(body string, alert PostEditPageAlert) []byte {
|
func getPostEditPageTemplate(post post.Post, alert PostEditPageAlert) []byte {
|
||||||
navbarTmpl, _ := Container.GetPageUseCase.GetPage("componentNavbar", nil)
|
navbarTmpl, _ := Container.GetPageUseCase.GetPage("componentNavbar", nil)
|
||||||
postTmpl, _ := Container.GetPageUseCase.GetPage("postEdit", map[string]interface{}{
|
postTmpl, _ := Container.GetPageUseCase.GetPage("postEdit", map[string]interface{}{
|
||||||
"Navbar": template.HTML(navbarTmpl),
|
"Navbar": template.HTML(navbarTmpl),
|
||||||
"Head": headTmpl,
|
"Head": headTmpl,
|
||||||
"Body": body,
|
"Post": post,
|
||||||
"Alert": alert,
|
"Alert": alert,
|
||||||
|
"Secured": os.Getenv("ENVIRONMENT") == "production",
|
||||||
})
|
})
|
||||||
return postTmpl
|
return postTmpl
|
||||||
}
|
}
|
||||||
@@ -27,7 +30,7 @@ func PostPostEditPage(w http.ResponseWriter, r *http.Request) {
|
|||||||
postID := chi.URLParam(r, "id")
|
postID := chi.URLParam(r, "id")
|
||||||
postIDint, err := strconv.Atoi(postID)
|
postIDint, err := strconv.Atoi(postID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, _ = w.Write(getPostEditPageTemplate("", PostEditPageAlert{
|
_, _ = w.Write(getPostEditPageTemplate(post.Post{}, PostEditPageAlert{
|
||||||
IsError: true,
|
IsError: true,
|
||||||
Message: "Could not find the requested post.",
|
Message: "Could not find the requested post.",
|
||||||
}))
|
}))
|
||||||
@@ -37,17 +40,17 @@ func PostPostEditPage(w http.ResponseWriter, r *http.Request) {
|
|||||||
_ = r.ParseForm()
|
_ = r.ParseForm()
|
||||||
postBody := r.FormValue("postBody")
|
postBody := r.FormValue("postBody")
|
||||||
|
|
||||||
post, _ := Container.GetPostUseCase.GetPost(uint32(postIDint))
|
getPost, _ := Container.GetPostUseCase.GetPost(uint32(postIDint))
|
||||||
err = Container.UpdatePostUseCase.UpdateBody(post.ID, postBody)
|
updatedPost, err := Container.UpdatePostUseCase.UpdateBody(getPost.ID, postBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, _ = w.Write(getPostEditPageTemplate(postBody, PostEditPageAlert{
|
_, _ = w.Write(getPostEditPageTemplate(post.Post{Body: postBody}, PostEditPageAlert{
|
||||||
IsError: true,
|
IsError: true,
|
||||||
Message: "Could not save the post: " + err.Error(),
|
Message: "Could not save the post: " + err.Error(),
|
||||||
}))
|
}))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = w.Write(getPostEditPageTemplate(postBody, PostEditPageAlert{
|
_, _ = w.Write(getPostEditPageTemplate(updatedPost, PostEditPageAlert{
|
||||||
IsError: false,
|
IsError: false,
|
||||||
Message: "Post successfully edited!",
|
Message: "Post successfully edited!",
|
||||||
}))
|
}))
|
||||||
@@ -61,9 +64,9 @@ func GetPostEditPage(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
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,
|
IsError: false,
|
||||||
Message: "",
|
Message: "",
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ type IPostRepository interface {
|
|||||||
GetByName(name string) (post.Post, error)
|
GetByName(name string) (post.Post, error)
|
||||||
GetAll() []post.Post
|
GetAll() []post.Post
|
||||||
Create(post post.Post) (post.Post, error)
|
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
|
Delete(id uint32) error
|
||||||
|
AddImage(postId uint32, imageId uint32) error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
-1
@@ -1,11 +1,16 @@
|
|||||||
package post
|
package post
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
entity "GoCMS/adapters/secondary/gateways/models"
|
||||||
|
domain "GoCMS/domain/image"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type Post 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"`
|
||||||
|
Images []*domain.Image `json:"images"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
}
|
}
|
||||||
@@ -24,13 +29,26 @@ func FromDb(
|
|||||||
id uint32,
|
id uint32,
|
||||||
title string,
|
title string,
|
||||||
body string,
|
body string,
|
||||||
|
images []*entity.Image,
|
||||||
createdAt time.Time,
|
createdAt time.Time,
|
||||||
updatedAt time.Time,
|
updatedAt time.Time,
|
||||||
) Post {
|
) 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{
|
return Post{
|
||||||
ID: id,
|
ID: id,
|
||||||
Title: title,
|
Title: title,
|
||||||
Body: body,
|
Body: body,
|
||||||
|
Images: domainImages,
|
||||||
CreatedAt: createdAt,
|
CreatedAt: createdAt,
|
||||||
UpdatedAt: updatedAt,
|
UpdatedAt: updatedAt,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package useCases
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"GoCMS/adapters/secondary/gateways"
|
"GoCMS/adapters/secondary/gateways"
|
||||||
|
"GoCMS/domain/post"
|
||||||
"gorm.io/gorm"
|
"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)
|
return g.postRepository.UpdateBody(id, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *UpdatePostUseCase) AddImage(postId uint32, imageId uint32) error {
|
||||||
|
return g.postRepository.AddImage(postId, imageId)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user