mirror of
https://github.com/Floriansylvain/RenewCMS.git
synced 2026-08-19 11:43:22 +02:00
feat: images
This commit is contained in:
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user