feat: images

This commit is contained in:
Florian Sylvain
2024-06-13 13:34:10 +02:00
parent eb98a1003e
commit c25fb1b0a3
19 changed files with 387 additions and 100 deletions
@@ -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"`
Title string
Body string
Images []*Image `gorm:"many2many:post_images;"`
CreatedAt time.Time `gorm:"autoCreateTime"`
UpdatedAt time.Time `gorm:"autoUpdateTime"`
}
+38 -8
View File
@@ -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{}
@@ -30,7 +30,7 @@
</div>
</div>
<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>
</form>
@@ -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);
}),
})
</script>