mirror of
https://github.com/Floriansylvain/RenewCMS.git
synced 2026-08-19 11:43:22 +02:00
Compare commits
12
Commits
v1.0.0-beta
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6796ce63cb | ||
|
|
99812ddba4 | ||
|
|
0238c7511d | ||
|
|
d7ee0a488c | ||
|
|
c57394d4fd | ||
|
|
f47f145b6c | ||
|
|
83a1dec8ae | ||
|
|
b470bfcc67 | ||
|
|
cb9a431488 | ||
|
|
2292a8ef34 | ||
|
|
a77a5ad314 | ||
|
|
d895477b8c |
@@ -4,7 +4,7 @@ tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
args_bin = []
|
||||
bin = "tmp\\main.exe"
|
||||
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", "api\\static\\uploadedImages"]
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ HOST=example.com
|
||||
PORT=8080
|
||||
JWT_SECRET=abc123
|
||||
CORS_ALLOWED_ORIGINS=*
|
||||
DB_FILE=./gocms.db
|
||||
DB_FILE=./renewcms.db
|
||||
DOCKER_DB_FOLDER=./data
|
||||
SMTP_EMAIL=a@b.c
|
||||
SMTP_PASSWORD=12341234
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# GoCMS
|
||||
# RenewCMS
|
||||
|
||||
## 🚧 This project is under development !
|
||||
|
||||
@@ -42,11 +42,11 @@ of course required, but not necessarily via the `.env` file.
|
||||
| Name | Type | Description | Comment |
|
||||
|----------------------|--------|:----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------|
|
||||
| ENVIRONMENT | string | environment the API is running in | required, `development` or `production` |
|
||||
| HOST | string | the host domain name for emails and callbacks | required |
|
||||
| HOST | string | the host domain name for emails and callbacks | required, if `localhost`: add the port (e.g. `localhost:8080`) |
|
||||
| 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. `./RenewCMS.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 |
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
package gateways
|
||||
|
||||
import (
|
||||
entity "RenewCMS/adapters/secondary/gateways/models"
|
||||
domain "RenewCMS/domain/article"
|
||||
"RenewCMS/domain/gateways"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ArticleRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewArticleRepository(db *gorm.DB) *ArticleRepository {
|
||||
return &ArticleRepository{db}
|
||||
}
|
||||
|
||||
func mapArticleToDomain(article entity.Article) domain.Article {
|
||||
return domain.FromDb(article.ID, article.Title, article.Body, article.Images, article.IsOnline, article.CreatedAt, article.UpdatedAt)
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) Get(id uint32) (domain.Article, error) {
|
||||
var article entity.Article
|
||||
err := a.db.Model(&entity.Article{}).Preload("Images").First(&article, id).Error
|
||||
if err != nil {
|
||||
return domain.Article{}, err
|
||||
}
|
||||
|
||||
return mapArticleToDomain(article), nil
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) GetByName(name string) (domain.Article, error) {
|
||||
var article entity.Article
|
||||
err := a.db.Model(&entity.Article{}).Where("title = ?", name).First(&article).Error
|
||||
if err != nil {
|
||||
return domain.Article{}, err
|
||||
}
|
||||
|
||||
return mapArticleToDomain(article), nil
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) Create(article domain.Article) (domain.Article, error) {
|
||||
creationResult := a.db.Create(&entity.Article{
|
||||
Title: article.Title,
|
||||
Body: article.Body,
|
||||
})
|
||||
if creationResult.Error != nil {
|
||||
return domain.Article{}, creationResult.Error
|
||||
}
|
||||
|
||||
var createdArticle entity.Article
|
||||
creationResult.Scan(&createdArticle)
|
||||
|
||||
return mapArticleToDomain(createdArticle), nil
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) GetAll() []domain.Article {
|
||||
var articles []entity.Article
|
||||
err := a.db.Model(&entity.Article{}).Find(&articles).Error
|
||||
if err != nil {
|
||||
return []domain.Article{}
|
||||
}
|
||||
|
||||
var domainArticles = make([]domain.Article, 0)
|
||||
for _, article := range articles {
|
||||
domainArticles = append(domainArticles, mapArticleToDomain(article))
|
||||
}
|
||||
|
||||
return domainArticles
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) UpdateBody(id uint32, body string) (domain.Article, error) {
|
||||
var localArticle entity.Article
|
||||
err := a.db.Model(&entity.Article{}).First(&localArticle, id).Error
|
||||
if err != nil {
|
||||
return domain.Article{}, err
|
||||
}
|
||||
|
||||
localArticle.Body = body
|
||||
err = a.db.Save(&localArticle).Error
|
||||
if err != nil {
|
||||
return domain.Article{}, err
|
||||
}
|
||||
|
||||
newArticle := domain.FromDb(
|
||||
localArticle.ID,
|
||||
localArticle.Title,
|
||||
localArticle.Body,
|
||||
localArticle.Images,
|
||||
localArticle.IsOnline,
|
||||
localArticle.CreatedAt,
|
||||
localArticle.UpdatedAt,
|
||||
)
|
||||
|
||||
return newArticle, nil
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) UpdateIsOnline(id uint32, isOnline bool) (domain.Article, error) {
|
||||
var localArticle entity.Article
|
||||
err := a.db.Model(&entity.Article{}).First(&localArticle, id).Error
|
||||
if err != nil {
|
||||
return domain.Article{}, err
|
||||
}
|
||||
|
||||
localArticle.IsOnline = isOnline
|
||||
err = a.db.Save(&localArticle).Error
|
||||
if err != nil {
|
||||
return domain.Article{}, err
|
||||
}
|
||||
|
||||
return mapArticleToDomain(localArticle), nil
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) Delete(id uint32) error {
|
||||
return a.db.Delete(&entity.Article{}, id).Error
|
||||
}
|
||||
|
||||
func (a *ArticleRepository) AddImage(articleId uint32, imageId uint32) error {
|
||||
var localArticle entity.Article
|
||||
err := a.db.Model(&entity.Article{}).First(&localArticle, articleId).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(&localArticle).Association("Images").Append(&localImage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ gateways.IArticleRepository = &ArticleRepository{}
|
||||
@@ -1,9 +1,9 @@
|
||||
package gateways
|
||||
|
||||
import (
|
||||
entity "GoCMS/adapters/secondary/gateways/models"
|
||||
"GoCMS/domain/gateways"
|
||||
domain "GoCMS/domain/image"
|
||||
entity "RenewCMS/adapters/secondary/gateways/models"
|
||||
"RenewCMS/domain/gateways"
|
||||
domain "RenewCMS/domain/image"
|
||||
"errors"
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
@@ -30,7 +30,7 @@ func mapImageToDomain(image entity.Image) domain.Image {
|
||||
return domain.FromDB(
|
||||
image.ID,
|
||||
image.Path,
|
||||
image.PostID,
|
||||
image.ArticleID,
|
||||
image.CreatedAt,
|
||||
image.UpdatedAt,
|
||||
)
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<html lang="en">
|
||||
<body>
|
||||
<h1>
|
||||
<img src="{{.Host}}/static/gocms-favicon-128.png" alt="G" style="width: 2.5rem"/>
|
||||
GoCMS
|
||||
<img src="{{.Host}}/static/renewcms-favicon-64.png" alt="G" style="width: 2.5rem"/>
|
||||
RenewCMS
|
||||
</h1>
|
||||
<main>
|
||||
<p>You or someone tried to create a GoCMS admin account with this e-mail address. If you are not responsible for
|
||||
<p>You or someone tried to create a RenewCMS admin account with this e-mail address. If you are not responsible for
|
||||
this, please do not validate the account creation.</p>
|
||||
<p><b>If you want to validate the account creation, please <a
|
||||
href="{{.Host}}/register/validate?c={{.VerificationCode}}" target="_blank">click HERE</a>.</b>
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
<html lang="en">
|
||||
<body>
|
||||
<h1>
|
||||
<img src="{{.Host}}/static/gocms-favicon-128.png" alt="G" style="width: 2.5rem"/>
|
||||
GoCMS
|
||||
<img src="{{.Host}}/static/renewcms-favicon-64.png" alt="G" style="width: 2.5rem"/>
|
||||
RenewCMS
|
||||
</h1>
|
||||
<main>
|
||||
<p>You or someone tried to create reset your GoCMS account with this e-mail address. If you are not responsible for
|
||||
<p>You or someone tried to create reset your RenewCMS account with this e-mail address. If you are not responsible for
|
||||
this, please do not validate the password reset.</p>
|
||||
<p><b>If you want to reset your password, please <a
|
||||
href="{{.Host}}/register/reset/validate?c={{.VerificationCode}}&email={{.Email}}" target="_blank">click HERE</a>.</b>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package gateways
|
||||
|
||||
import (
|
||||
"GoCMS/domain/gateways"
|
||||
"RenewCMS/domain/gateways"
|
||||
"bytes"
|
||||
"embed"
|
||||
"gopkg.in/gomail.v2"
|
||||
"html/template"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/gomail.v2"
|
||||
)
|
||||
|
||||
type MailRepository struct{}
|
||||
@@ -16,7 +17,11 @@ type MailRepository struct{}
|
||||
//go:embed mail/templates/*
|
||||
var mailTemplateFiles embed.FS
|
||||
|
||||
func (m MailRepository) Send(receiverAddress string, templateName string, data interface{}) error {
|
||||
func NewMailRepository() *MailRepository {
|
||||
return &MailRepository{}
|
||||
}
|
||||
|
||||
func (m MailRepository) Send(receiverAddress string, templateName string, data any) error {
|
||||
from := os.Getenv("SMTP_EMAIL")
|
||||
password := os.Getenv("SMTP_PASSWORD")
|
||||
smtpHost := os.Getenv("SMTP_HOST")
|
||||
@@ -39,12 +44,12 @@ func (m MailRepository) Send(receiverAddress string, templateName string, data i
|
||||
|
||||
msg := gomail.NewMessage()
|
||||
msg.SetHeaders(map[string][]string{
|
||||
"From": {"GoCMS <" + from + ">"},
|
||||
"From": {"RenewCMS <" + from + ">"},
|
||||
"To": {receiverAddress},
|
||||
"MIME-version": {"1.0"},
|
||||
"Content-Type": {"text/html"},
|
||||
"charset": {"UTF-8"},
|
||||
"Subject": {"GoCMS | Action required"},
|
||||
"Subject": {"RenewCMS | Action required"},
|
||||
})
|
||||
msg.SetBody("text/html", body.String())
|
||||
|
||||
|
||||
+4
-3
@@ -1,16 +1,17 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Post struct {
|
||||
type Article struct {
|
||||
gorm.Model
|
||||
ID uint32 `gorm:"primary_key;auto_increment;not_null"`
|
||||
Title string
|
||||
Body string
|
||||
Images []*Image `gorm:"many2many:post_images;"`
|
||||
Images []*Image `gorm:"many2many:article_images;"`
|
||||
IsOnline bool `gorm:"not_null;default:false"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||
@@ -1,15 +1,16 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Image struct {
|
||||
gorm.Model
|
||||
ID uint32 `gorm:"primary_key;auto_increment;not_null"`
|
||||
Path string
|
||||
PostID uint32
|
||||
ArticleID uint32
|
||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime"`
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package gateways
|
||||
|
||||
import (
|
||||
"GoCMS/domain/gateways"
|
||||
"RenewCMS/domain/gateways"
|
||||
"bytes"
|
||||
"embed"
|
||||
"html/template"
|
||||
@@ -16,7 +16,7 @@ func NewPageRepository() *PageRepository {
|
||||
return &PageRepository{}
|
||||
}
|
||||
|
||||
func (p *PageRepository) Get(name string, data interface{}) ([]byte, error) {
|
||||
func (p *PageRepository) Get(name string, data any) ([]byte, error) {
|
||||
var processedHTML bytes.Buffer
|
||||
tmpl, err := template.ParseFS(webTemplateFiles, "web/templates/"+name+".html")
|
||||
if err != nil {
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
package gateways
|
||||
|
||||
import (
|
||||
entity "GoCMS/adapters/secondary/gateways/models"
|
||||
"GoCMS/domain/gateways"
|
||||
domain "GoCMS/domain/post"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type PostRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewPostRepository(db *gorm.DB) *PostRepository {
|
||||
return &PostRepository{db}
|
||||
}
|
||||
|
||||
func mapPostToDomain(post entity.Post) domain.Post {
|
||||
return domain.FromDb(post.ID, post.Title, post.Body, post.Images, post.IsOnline, post.CreatedAt, post.UpdatedAt)
|
||||
}
|
||||
|
||||
func (a *PostRepository) Get(id uint32) (domain.Post, error) {
|
||||
var post entity.Post
|
||||
err := a.db.Model(&entity.Post{}).Preload("Images").First(&post, id).Error
|
||||
if err != nil {
|
||||
return domain.Post{}, err
|
||||
}
|
||||
|
||||
return mapPostToDomain(post), nil
|
||||
}
|
||||
|
||||
func (a *PostRepository) GetByName(name string) (domain.Post, error) {
|
||||
var post entity.Post
|
||||
err := a.db.Model(&entity.Post{}).Where("title = ?", name).First(&post).Error
|
||||
if err != nil {
|
||||
return domain.Post{}, err
|
||||
}
|
||||
|
||||
return mapPostToDomain(post), nil
|
||||
}
|
||||
|
||||
func (a *PostRepository) Create(post domain.Post) (domain.Post, error) {
|
||||
creationResult := a.db.Create(&entity.Post{
|
||||
Title: post.Title,
|
||||
Body: post.Body,
|
||||
})
|
||||
if creationResult.Error != nil {
|
||||
return domain.Post{}, creationResult.Error
|
||||
}
|
||||
|
||||
var createdPost entity.Post
|
||||
creationResult.Scan(&createdPost)
|
||||
|
||||
return mapPostToDomain(createdPost), nil
|
||||
}
|
||||
|
||||
func (a *PostRepository) GetAll() []domain.Post {
|
||||
var posts []entity.Post
|
||||
err := a.db.Model(&entity.Post{}).Find(&posts).Error
|
||||
if err != nil {
|
||||
return []domain.Post{}
|
||||
}
|
||||
|
||||
var domainPosts = make([]domain.Post, 0)
|
||||
for _, post := range posts {
|
||||
domainPosts = append(domainPosts, mapPostToDomain(post))
|
||||
}
|
||||
|
||||
return domainPosts
|
||||
}
|
||||
|
||||
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 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.IsOnline,
|
||||
localPost.CreatedAt,
|
||||
localPost.UpdatedAt,
|
||||
)
|
||||
|
||||
return newPost, nil
|
||||
}
|
||||
|
||||
func (a *PostRepository) UpdateIsOnline(id uint32, isOnline bool) (domain.Post, error) {
|
||||
var localPost entity.Post
|
||||
err := a.db.Model(&entity.Post{}).First(&localPost, id).Error
|
||||
if err != nil {
|
||||
return domain.Post{}, err
|
||||
}
|
||||
|
||||
localPost.IsOnline = isOnline
|
||||
err = a.db.Save(&localPost).Error
|
||||
if err != nil {
|
||||
return domain.Post{}, err
|
||||
}
|
||||
|
||||
return mapPostToDomain(localPost), 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
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ gateways.IPostRepository = &PostRepository{}
|
||||
@@ -1,10 +1,10 @@
|
||||
package gateways
|
||||
|
||||
import (
|
||||
entity "GoCMS/adapters/secondary/gateways/models"
|
||||
"GoCMS/domain/gateways"
|
||||
"GoCMS/domain/user"
|
||||
domain "GoCMS/domain/user"
|
||||
entity "RenewCMS/adapters/secondary/gateways/models"
|
||||
"RenewCMS/domain/gateways"
|
||||
"RenewCMS/domain/user"
|
||||
domain "RenewCMS/domain/user"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
+14
-14
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Create post</title>
|
||||
<title>RenewCMS | Create article</title>
|
||||
{{.Head}}
|
||||
<style>
|
||||
form {
|
||||
@@ -12,27 +12,27 @@
|
||||
<body class="text-dark">
|
||||
{{.Navbar}}
|
||||
<div class="container mt-3 text-black-50">
|
||||
<h1>Post - creation</h1>
|
||||
<p>Create a new post</p>
|
||||
<form action="create" method="post" class="d-flex align-items-center flex-column gap-3" id="createPostForm">
|
||||
<h1>Article - creation</h1>
|
||||
<p>Create a new article</p>
|
||||
<form action="create" method="post" class="d-flex align-items-center flex-column gap-3" id="createArticleForm">
|
||||
<div class="form-floating w-100">
|
||||
<input type="text" class="form-control {{ if .PageError.IsError }} is-invalid {{ end }}" id="name"
|
||||
name="name" placeholder="Chose the post name" value="{{ .Name }}">
|
||||
name="name" placeholder="Chose the article name" value="{{ .Name }}">
|
||||
<label for="name">Name</label>
|
||||
<div class="invalid-feedback">{{ .PageError.Message }}</div>
|
||||
</div>
|
||||
<button id="createPostButton" class="btn btn-primary w-100" disabled type="submit">
|
||||
<span class="createPostFormButtonLoading visually-hidden spinner-border spinner-border-sm"
|
||||
<button id="createArticleButton" class="btn btn-primary w-100" disabled type="submit">
|
||||
<span class="createArticleFormButtonLoading visually-hidden spinner-border spinner-border-sm"
|
||||
role="status"></span>
|
||||
<span class="createPostFormButtonDefault">Create</span>
|
||||
<span class="createArticleFormButtonDefault">Create</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const button = document.querySelector("#createPostButton")
|
||||
const button = document.querySelector("#createArticleButton")
|
||||
const inputs = document.querySelectorAll('input')
|
||||
const form = document.querySelector("#createPostForm")
|
||||
const form = document.querySelector("#createArticleForm")
|
||||
|
||||
function formFieldsEmpty() {
|
||||
return Array.from(inputs).some((input) => input.value === "")
|
||||
@@ -44,11 +44,11 @@
|
||||
|
||||
function setButtonLoading() {
|
||||
button.classList.add("disabled")
|
||||
button.querySelector(".createPostFormButtonDefault").classList.add("visually-hidden")
|
||||
button.querySelector(".createPostFormButtonLoading").classList.remove("visually-hidden")
|
||||
button.querySelector(".createArticleFormButtonDefault").classList.add("visually-hidden")
|
||||
button.querySelector(".createArticleFormButtonLoading").classList.remove("visually-hidden")
|
||||
}
|
||||
|
||||
function onCreatePostFormSubmit(event) {
|
||||
function onCreateArticleFormSubmit(event) {
|
||||
setButtonLoading()
|
||||
event.target.submit()
|
||||
}
|
||||
@@ -57,7 +57,7 @@
|
||||
if (event.target.tagName === "INPUT") setButtonDisabled()
|
||||
}
|
||||
|
||||
form.addEventListener('submit', onCreatePostFormSubmit)
|
||||
form.addEventListener('submit', onCreateArticleFormSubmit)
|
||||
window.addEventListener('input', onInput)
|
||||
setButtonDisabled()
|
||||
</script>
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Post edition</title>
|
||||
<title>RenewCMS | Article edition</title>
|
||||
{{.Head}}
|
||||
</head>
|
||||
<body class="text-dark vh-100 d-flex flex-column">
|
||||
@@ -9,8 +9,8 @@
|
||||
<form class="container mt-3 text-black-50 d-flex flex-column h-100" action="edit" method="post">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h1>Post - edition</h1>
|
||||
<label for="postBody">Edition</label>
|
||||
<h1>Article - edition</h1>
|
||||
<label for="articleBody">Edition</label>
|
||||
</div>
|
||||
{{ if .Alert.Message }}
|
||||
<div class="alert {{ if .Alert.IsError }} alert-danger {{ else }} alert-success {{ end }} alert-dismissible"
|
||||
@@ -30,14 +30,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-black-50 d-flex align-items-center justify-content-center h-100 py-3">
|
||||
<textarea id="postBody" name="postBody">{{.Post.Body}}</textarea>
|
||||
<textarea id="articleBody" name="articleBody">{{.Article.Body}}</textarea>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script src="/static/tinymce/js/tinymce/tinymce.min.js"></script>
|
||||
<script>
|
||||
tinymce.init({
|
||||
selector: '#postBody',
|
||||
selector: '#articleBody',
|
||||
promotion: false,
|
||||
plugins: 'image lists visualblocks',
|
||||
toolbar: 'undo redo | formatselect | bold italic underline strikethrough | alignleft aligncenter alignright alignjustify | bullist numlist | outdent indent | removeformat | image',
|
||||
@@ -52,7 +52,7 @@
|
||||
images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.withCredentials = false;
|
||||
xhr.open('POST', "/post/{{.Post.ID}}/image/create");
|
||||
xhr.open('POST', "/article/{{.Article.ID}}/image/create");
|
||||
|
||||
xhr.upload.onprogress = (e) => {
|
||||
progress(e.loaded / e.total * 100);
|
||||
+20
-20
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Posts</title>
|
||||
<title>RenewCMS | Articles</title>
|
||||
{{.Head}}
|
||||
|
||||
<style>
|
||||
@@ -15,8 +15,8 @@
|
||||
<body class="text-dark">
|
||||
{{.Navbar}}
|
||||
<div class="container mt-3 text-black-50">
|
||||
<h1>Posts</h1>
|
||||
<p>List of your posts</p>
|
||||
<h1>Articles</h1>
|
||||
<p>List of your articles</p>
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -30,59 +30,59 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center">
|
||||
<form action="post/create" method="get">
|
||||
<button class="btn btn-sm btn-link w-100 h-100" type="submit">Create a new post...</button>
|
||||
<form action="article/create" method="get">
|
||||
<button class="btn btn-sm btn-link w-100 h-100" type="submit">Create a new article...</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{{ range $post := .Posts }}
|
||||
{{ range $article := .Articles }}
|
||||
<tr>
|
||||
<td>{{ $post.Title }}</td>
|
||||
<td class="date">{{ $post.CreatedAt }}</td>
|
||||
<td class="date">{{ $post.UpdatedAt }}</td>
|
||||
<td>{{ if $post.IsOnline }}🟢 Online{{ else }}🟠 Offline{{ end }}</td>
|
||||
<td>{{ $article.Title }}</td>
|
||||
<td class="date">{{ $article.CreatedAt }}</td>
|
||||
<td class="date">{{ $article.UpdatedAt }}</td>
|
||||
<td>{{ if $article.IsOnline }}🟢 Online{{ else }}🟠 Offline{{ end }}</td>
|
||||
<td>
|
||||
<a href="/post/{{ $post.ID }}/edit" class="btn btn-outline-primary btn-sm">
|
||||
<a href="/article/{{ $article.ID }}/edit" class="btn btn-outline-primary btn-sm">
|
||||
<svg width="12px" height="12px" fill="currentColor">
|
||||
<use xlink:href="/static/bootstrap-icons.svg#pen"/>
|
||||
</svg>
|
||||
</a>
|
||||
{{ if $post.IsOnline }}
|
||||
<a href="/post/{{ $post.ID }}/unpublish" class="btn btn-outline-info btn-sm">
|
||||
{{ if $article.IsOnline }}
|
||||
<a href="/article/{{ $article.ID }}/unpublish" class="btn btn-outline-info btn-sm">
|
||||
<svg width="12px" height="12px" fill="currentColor">
|
||||
<use xlink:href="/static/bootstrap-icons.svg#eye-slash"/>
|
||||
</svg>
|
||||
</a>
|
||||
{{ else }}
|
||||
<a href="/post/{{ $post.ID }}/publish" class="btn btn-outline-info btn-sm">
|
||||
<a href="/article/{{ $article.ID }}/publish" class="btn btn-outline-info btn-sm">
|
||||
<svg width="12px" height="12px" fill="currentColor">
|
||||
<use xlink:href="/static/bootstrap-icons.svg#eye"/>
|
||||
</svg>
|
||||
</a>
|
||||
{{ end }}
|
||||
<a href="/post/{{ $post.Title }}/delete" class="btn btn-outline-danger btn-sm" data-bs-toggle="modal"
|
||||
data-bs-target="#{{ $post.ID }}">
|
||||
<a href="/article/{{ $article.Title }}/delete" class="btn btn-outline-danger btn-sm" data-bs-toggle="modal"
|
||||
data-bs-target="#{{ $article.ID }}">
|
||||
<svg width=" 12px" height="12px" fill="currentColor">
|
||||
<use xlink:href="/static/bootstrap-icons.svg#trash"/>
|
||||
</svg>
|
||||
</a>
|
||||
<div class="modal fade" id="{{ $post.ID }}" tabindex="-1" aria-labelledby="{{ $post.ID }}Label"
|
||||
<div class="modal fade" id="{{ $article.ID }}" tabindex="-1" aria-labelledby="{{ $article.ID }}Label"
|
||||
aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1 class="modal-title fs-5" id="{{ $post.ID }}Label">Delete post</h1>
|
||||
<h1 class="modal-title fs-5" id="{{ $article.ID }}Label">Delete post</h1>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"
|
||||
aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>You are about to delete the post <b>« {{ $post.Title }} »</b>, this is definitive,
|
||||
<p>You are about to delete the post <b>« {{ $article.Title }} »</b>, this is definitive,
|
||||
are you sure?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel
|
||||
</button>
|
||||
<a href="/post/{{$post.ID}}/delete" class="btn btn-danger">Delete</a>
|
||||
<a href="/article/{{$article.ID}}/delete" class="btn btn-danger">Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,9 +1,9 @@
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||
<div class="container">
|
||||
<div class="d-flex gap-2 justify-content-center align-items-center">
|
||||
<img src="/static/gocms-favicon-128.png" alt="Logo" style="width: 2.5rem"/>
|
||||
<a class="navbar-brand h1 my-auto" href="https://github.com/Floriansylvain/GoCMS" target="_blank">
|
||||
GoCMS
|
||||
<img src="/static/renewcms-favicon-64.png" alt="Logo" style="width: 2.5rem"/>
|
||||
<a class="navbar-brand h1 my-auto" href="https://github.com/Floriansylvain/RenewCMS" target="_blank">
|
||||
RenewCMS
|
||||
</a>
|
||||
</div>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
@@ -16,16 +16,13 @@
|
||||
<a class="nav-link" href="/home">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/post">Posts</a>
|
||||
<a class="nav-link" href="/article">Articles</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/integration">Integration</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-body-tertiary text-decoration-underline" href="https://www.paypal.com/donate/?hosted_button_id=S6LUFUYK84CYY">support me!</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link disconnect-link" href="/logout">Log out</a>
|
||||
</li>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Home</title>
|
||||
<title>RenewCMS | Home</title>
|
||||
{{.Head}}
|
||||
</head>
|
||||
<body class="text-dark">
|
||||
{{.Navbar}}
|
||||
<div class="container mt-3 text-black-50">
|
||||
<h1>Accueil</h1>
|
||||
<p>Welcome on GoCMS !</p>
|
||||
<a href="/post">
|
||||
<button class="btn btn-outline-primary">Posts »</button>
|
||||
<h1>Home</h1>
|
||||
<p>Welcome on RenewCMS !</p>
|
||||
<a href="/article">
|
||||
<button class="btn btn-outline-primary">Articles »</button>
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Home</title>
|
||||
<title>RenewCMS | Home</title>
|
||||
{{.Head}}
|
||||
</head>
|
||||
<body class="text-dark">
|
||||
@@ -12,19 +12,19 @@
|
||||
<div class="mt-5">
|
||||
<section>
|
||||
<h2>Introduction</h2>
|
||||
<p>This documentation explains how to integrate our headless CMS API to retrieve post data via the <code>/post</code>
|
||||
<p>This documentation explains how to integrate our headless CMS API to retrieve article data via the <code>/article</code>
|
||||
route.</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>/v1/post</h2>
|
||||
<p>The <code>{{ .Host }}/v1/post</code> route returns a list of posts in JSON format. Each post has the
|
||||
<h2>/v1/article</h2>
|
||||
<p>The <code>{{ .Host }}/v1/article</code> route returns a list of articles in JSON format. Each article has the
|
||||
following
|
||||
structure:</p>
|
||||
<pre>
|
||||
<code>[
|
||||
{
|
||||
"id": 12,
|
||||
"title": "This is a post!",
|
||||
"title": "This is a article!",
|
||||
"body": "<p>?</p>\r\n<p><img src=\"../../static/uploadedImages/649691a8-4f2e-48ca-9abe-27a60621d2e4.png\"
|
||||
alt=\"\" width=\"391\" height=\"465\"></p>",
|
||||
"created_at": "2024-06-13T15:30:55.3563238+02:00",
|
||||
@@ -34,21 +34,21 @@
|
||||
</pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>/v1/post/{id}</h2>
|
||||
<p>The <code>{{ .Host }}/v1/post/{id}</code> route returns a single post in JSON format. The post has the
|
||||
<h2>/v1/article/{id}</h2>
|
||||
<p>The <code>{{ .Host }}/v1/article/{id}</code> route returns a single article in JSON format. The article has the
|
||||
following
|
||||
structure:</p>
|
||||
<pre>
|
||||
<code>{
|
||||
"id": 12,
|
||||
"title": "ravioli sans le ra et le i",
|
||||
"title": "ravioli",
|
||||
"body": "<\p>?<\/p>\r\n<\p><\img src=\"../../static/uploadedImages/649691a8-4f2e-48ca-9abe-27a60621d2e4.png\" alt=\"\"
|
||||
width=\"391\" height=\"465\"><\/p>",
|
||||
"images": [
|
||||
{
|
||||
"id": 17,
|
||||
"path": "/static/uploadedImages/649691a8-4f2e-48ca-9abe-27a60621d2e4.png",
|
||||
"post_id": 0,
|
||||
"article_id": 0,
|
||||
"created_at": "2024-06-13T15:31:09.728359+02:00",
|
||||
"updated_at": "2024-06-13T15:31:09.728359+02:00"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Login</title>
|
||||
<title>RenewCMS | Login</title>
|
||||
{{.Head}}
|
||||
|
||||
<style>
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column m-auto form-container">
|
||||
<div>
|
||||
<h1>GoCMS</h1>
|
||||
<h1>RenewCMS</h1>
|
||||
<h2>Login</h2>
|
||||
</div>
|
||||
<form action="login" method="POST" class="mt-5" id="loginForm">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Password reset</title>
|
||||
<title>RenewCMS | Password reset</title>
|
||||
{{.Head}}
|
||||
|
||||
<style>
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column m-auto form-container">
|
||||
<div>
|
||||
<h1>GoCMS</h1>
|
||||
<h1>RenewCMS</h1>
|
||||
<h2>Admin account password reset</h2>
|
||||
</div>
|
||||
<form action="request" method="POST" class="mt-5" id="registerForm">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Password reset</title>
|
||||
<title>RenewCMS | Password reset</title>
|
||||
{{.Head}}
|
||||
|
||||
<style>
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column m-auto form-container">
|
||||
<div>
|
||||
<h1>GoCMS</h1>
|
||||
<h1>RenewCMS</h1>
|
||||
<h2>Admin account password reset</h2>
|
||||
</div>
|
||||
<form action="validate" method="POST" class="mt-5" id="registerForm">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Setup</title>
|
||||
<title>RenewCMS | Setup</title>
|
||||
{{.Head}}
|
||||
|
||||
<style>
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column m-auto form-container">
|
||||
<div>
|
||||
<h1>GoCMS</h1>
|
||||
<h1>RenewCMS</h1>
|
||||
<h2>Admin account creation</h2>
|
||||
</div>
|
||||
<form action="register" method="POST" class="mt-5" id="registerForm">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Setup</title>
|
||||
<title>RenewCMS | Setup</title>
|
||||
{{.Head}}
|
||||
|
||||
<style>
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column m-auto form-container">
|
||||
<div>
|
||||
<h1>GoCMS</h1>
|
||||
<h1>RenewCMS</h1>
|
||||
<h2>Verify your email</h2>
|
||||
</div>
|
||||
<p>An e-mail with the validation link was sent to the address you just registered.</p>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>GoCMS | Setup</title>
|
||||
<title>RenewCMS | Setup</title>
|
||||
{{.Head}}
|
||||
|
||||
<style>
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="container">
|
||||
<div class="d-flex flex-column gap-5 m-auto form-container">
|
||||
<div>
|
||||
<h1>GoCMS</h1>
|
||||
<h1>RenewCMS</h1>
|
||||
<h2>E-mail verification</h2>
|
||||
</div>
|
||||
{{ if .PageError.IsError }}
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
package article
|
||||
|
||||
import (
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/api/controllers/auth"
|
||||
"RenewCMS/domain/article"
|
||||
"RenewCMS/useCases"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type PostArticle struct {
|
||||
Title string `json:"title" validate:"required,min=3,max=50"`
|
||||
Body string `json:"body" validate:"required,max=10000"`
|
||||
}
|
||||
|
||||
const IdUint32ErrorMessage = "The server expects the ID to be in the format of an unsigned 32-bit integer (uint32)."
|
||||
|
||||
func getArticle(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 32)
|
||||
if err != nil {
|
||||
http.Error(w, IdUint32ErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
localArticle, err := api.Container.GetArticleUseCase.GetArticle(uint32(id))
|
||||
if err != nil || !localArticle.IsOnline {
|
||||
http.Error(w, "The requested resource, identified by its unique ID, could not be found on the server.", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
articleJson, _ := json.Marshal(localArticle)
|
||||
_, _ = w.Write(articleJson)
|
||||
}
|
||||
|
||||
func postArticle(w http.ResponseWriter, r *http.Request) {
|
||||
var localArticle PostArticle
|
||||
err := json.NewDecoder(r.Body).Decode(&localArticle)
|
||||
if err != nil {
|
||||
http.Error(w, auth.BodyErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err = api.Validate.Struct(localArticle)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
createdArticle, err := api.Container.CreateArticleUseCase.CreateArticle(useCases.CreateArticleCommand{
|
||||
Title: localArticle.Title,
|
||||
Body: localArticle.Body,
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
articleJson, _ := json.Marshal(createdArticle)
|
||||
|
||||
_, _ = w.Write(articleJson)
|
||||
}
|
||||
|
||||
func listArticles(w http.ResponseWriter, _ *http.Request) {
|
||||
articles := api.Container.ListArticlesUseCase.ListArticles()
|
||||
onlineArticles := make([]article.Article, 0)
|
||||
for _, localArticle := range articles {
|
||||
if localArticle.IsOnline {
|
||||
onlineArticles = append(onlineArticles, localArticle)
|
||||
}
|
||||
}
|
||||
articlesJson, _ := json.Marshal(onlineArticles)
|
||||
_, _ = w.Write(articlesJson)
|
||||
}
|
||||
|
||||
func deleteArticle(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 32)
|
||||
if err != nil {
|
||||
http.Error(w, IdUint32ErrorMessage, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
err = api.Container.DeleteArticleUseCase.DeleteArticle(uint32(id))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
}
|
||||
|
||||
_, _ = w.Write([]byte("article deleted"))
|
||||
}
|
||||
|
||||
func NewArticleRouter() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/{id}", getArticle)
|
||||
r.Post("/", postArticle)
|
||||
r.Get("/", listArticles)
|
||||
r.Delete("/{id}", deleteArticle)
|
||||
return r
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/domain/user"
|
||||
"GoCMS/useCases"
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/domain/user"
|
||||
"RenewCMS/useCases"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/jwtauth/v5"
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
@@ -29,12 +28,11 @@ type LoginCredentials struct {
|
||||
var shouldCookieBeSecure = os.Getenv("ENVIRONMENT") == "production"
|
||||
var Token *jwtauth.JWTAuth
|
||||
|
||||
// TODO Move into its own file or package that handles api errors
|
||||
const LogsErrorMessage = "Access to the requested resource is forbidden due to incorrect password and/or username."
|
||||
const BodyErrorMessage = "The request cannot be processed due to a mismatch in the format of the body."
|
||||
|
||||
func SetJwtCookie(w *http.ResponseWriter, userId uint32) error {
|
||||
_, tokenString, err := Token.Encode(map[string]interface{}{"user_id": userId})
|
||||
_, tokenString, err := Token.Encode(map[string]any{"user_id": userId})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -103,19 +101,6 @@ func GetUserFromCredentials(credentials LoginCredentials) (user.User, error) {
|
||||
return dbUser, nil
|
||||
}
|
||||
|
||||
func GetNewUser(newUserCredentials RegisterCredentials, verificationCode string) (user.User, error) {
|
||||
createdUser, err := api.Container.CreateUserUseCase.CreateUser(useCases.CreateUserCommand{
|
||||
Username: newUserCredentials.Username,
|
||||
Password: newUserCredentials.Password,
|
||||
Email: newUserCredentials.Email,
|
||||
VerificationCode: verificationCode,
|
||||
})
|
||||
if err != nil {
|
||||
return user.User{}, err
|
||||
}
|
||||
return createdUser, nil
|
||||
}
|
||||
|
||||
func login(w http.ResponseWriter, r *http.Request) {
|
||||
var credentials LoginCredentials
|
||||
|
||||
@@ -134,11 +119,12 @@ func login(w http.ResponseWriter, r *http.Request) {
|
||||
dbUser, err := GetUserFromCredentials(credentials)
|
||||
if err != nil {
|
||||
http.Error(w, LogsErrorMessage, http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
_ = SetJwtCookie(&w, dbUser.ID)
|
||||
|
||||
message, _ := json.Marshal(map[string]interface{}{"message": "User logged in! HTTPonly jwt cookie created"})
|
||||
message, _ := json.Marshal(map[string]any{"message": "User logged in! HTTPonly jwt cookie created"})
|
||||
_, _ = w.Write(message)
|
||||
}
|
||||
|
||||
@@ -161,8 +147,11 @@ func register(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
verificationCode := uuid.NewString()
|
||||
createdUser, err := GetNewUser(credentials, verificationCode)
|
||||
createdUser, err := api.Container.CreateUserUseCase.CreateUser(useCases.CreateUserCommand{
|
||||
Username: credentials.Username,
|
||||
Password: credentials.Password,
|
||||
Email: credentials.Email,
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
@@ -170,7 +159,7 @@ func register(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
_ = SetJwtCookie(&w, createdUser.ID)
|
||||
|
||||
message, _ := json.Marshal(map[string]interface{}{"message": "User registered! HTTPonly jwt cookie created"})
|
||||
message, _ := json.Marshal(map[string]any{"message": "User registered! HTTPonly jwt cookie created"})
|
||||
_, _ = w.Write(message)
|
||||
}
|
||||
|
||||
@@ -188,7 +177,7 @@ func RemoveJwtCookie(w http.ResponseWriter) {
|
||||
|
||||
func logout(w http.ResponseWriter, _ *http.Request) {
|
||||
RemoveJwtCookie(w)
|
||||
message, _ := json.Marshal(map[string]interface{}{"message": "User logged out! HTTPonly jwt cookie deleted"})
|
||||
message, _ := json.Marshal(map[string]any{"message": "User logged out! HTTPonly jwt cookie deleted"})
|
||||
_, _ = w.Write(message)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package image
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"RenewCMS/api"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -27,13 +27,13 @@ func PostImage(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
err = api.Container.UpdatePostUseCase.AddImage(uint32(idInt), newImage.ID)
|
||||
err = api.Container.UpdateArticleUseCase.AddImage(uint32(idInt), newImage.ID)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
newJson := map[string]interface{}{"location": newImage.Path}
|
||||
newJson := map[string]any{"location": newImage.Path}
|
||||
newJsonBytes, _ := json.Marshal(newJson)
|
||||
|
||||
_, _ = w.Write(newJsonBytes)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/useCases"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type ArticleCreatePageError struct {
|
||||
IsError bool
|
||||
Message string
|
||||
}
|
||||
|
||||
func GetArticleCreatePageTemplate(postName string, errorMessage string) ([]byte, error) {
|
||||
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
|
||||
return api.Container.GetPageUseCase.GetPage("articleCreate", map[string]any{
|
||||
"Navbar": template.HTML(navbarTmpl),
|
||||
"Head": headTmpl,
|
||||
"PageError": ArticleCreatePageError{
|
||||
IsError: errorMessage != "",
|
||||
Message: errorMessage,
|
||||
},
|
||||
"Name": postName,
|
||||
})
|
||||
}
|
||||
|
||||
func PostArticleCreatePage(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
|
||||
postName := r.FormValue("name")
|
||||
pattern := regexp.MustCompile("^[a-zA-Z0-9À-ÖØ-öø-ÿĀ-ſḀ-ỿ ]{3,50}$")
|
||||
|
||||
if !pattern.MatchString(postName) {
|
||||
postsTmpl, _ := GetArticleCreatePageTemplate(postName, "Name should be alphanumeric, and between 3 and 50 characters.")
|
||||
_, _ = w.Write(postsTmpl)
|
||||
return
|
||||
}
|
||||
|
||||
post, err := api.Container.CreateArticleUseCase.CreateArticle(useCases.CreateArticleCommand{
|
||||
Title: postName,
|
||||
Body: "",
|
||||
})
|
||||
if err != nil {
|
||||
postsTmpl, _ := GetArticleCreatePageTemplate(postName, "Something went wrong when creating the article, please contact admin.")
|
||||
_, _ = w.Write(postsTmpl)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/article/"+strconv.Itoa(int(post.ID))+"/edit", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func GetArticleCreatePage(w http.ResponseWriter, _ *http.Request) {
|
||||
postsTmpl, _ := GetArticleCreatePageTemplate("", "")
|
||||
_, _ = w.Write(postsTmpl)
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/api/controllers/post"
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/api/controllers/article"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
@@ -10,21 +10,21 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
func GetPostDeletePage(w http.ResponseWriter, r *http.Request) {
|
||||
func GetArticleDeletePage(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 32)
|
||||
if err != nil {
|
||||
http.Error(w, post.IdUint32ErrorMessage, http.StatusBadRequest)
|
||||
http.Error(w, article.IdUint32ErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
localPost, err := api.Container.GetPostUseCase.GetPost(uint32(id))
|
||||
localArticle, err := api.Container.GetArticleUseCase.GetArticle(uint32(id))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(localPost.Images)
|
||||
for _, image := range localPost.Images {
|
||||
fmt.Println(localArticle.Images)
|
||||
for _, image := range localArticle.Images {
|
||||
err = api.Container.DeleteImageUseCase.DeleteImage(image.ID)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
@@ -32,11 +32,11 @@ func GetPostDeletePage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
err = api.Container.DeletePostUseCase.DeletePost(uint32(id))
|
||||
err = api.Container.DeleteArticleUseCase.DeleteArticle(uint32(id))
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(400), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/post", http.StatusSeeOther)
|
||||
http.Redirect(w, r, "/article", http.StatusSeeOther)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/domain/article"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type ArticleEditPageAlert struct {
|
||||
IsError bool
|
||||
Message string
|
||||
}
|
||||
|
||||
func getArticleEditPageTemplate(post article.Article, alert ArticleEditPageAlert) []byte {
|
||||
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
|
||||
articleTmpl, _ := api.Container.GetPageUseCase.GetPage("articleEdit", map[string]any{
|
||||
"Navbar": template.HTML(navbarTmpl),
|
||||
"Head": headTmpl,
|
||||
"Article": post,
|
||||
"Alert": alert,
|
||||
"Secured": os.Getenv("ENVIRONMENT") == "production",
|
||||
})
|
||||
return articleTmpl
|
||||
}
|
||||
|
||||
func PostArticleEditPage(w http.ResponseWriter, r *http.Request) {
|
||||
articleID := chi.URLParam(r, "id")
|
||||
articleIDint, err := strconv.Atoi(articleID)
|
||||
if err != nil {
|
||||
_, _ = w.Write(getArticleEditPageTemplate(article.Article{}, ArticleEditPageAlert{
|
||||
IsError: true,
|
||||
Message: "Could not find the requested article.",
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
_ = r.ParseForm()
|
||||
articleBody := r.FormValue("articleBody")
|
||||
|
||||
getArticle, _ := api.Container.GetArticleUseCase.GetArticle(uint32(articleIDint))
|
||||
updatedArticle, err := api.Container.UpdateArticleUseCase.UpdateBody(getArticle.ID, articleBody)
|
||||
if err != nil {
|
||||
_, _ = w.Write(getArticleEditPageTemplate(article.Article{Body: articleBody}, ArticleEditPageAlert{
|
||||
IsError: true,
|
||||
Message: "Could not save the article: " + err.Error(),
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = w.Write(getArticleEditPageTemplate(updatedArticle, ArticleEditPageAlert{
|
||||
IsError: false,
|
||||
Message: "Article successfully edited!",
|
||||
}))
|
||||
}
|
||||
|
||||
func GetArticleEditPage(w http.ResponseWriter, r *http.Request) {
|
||||
articleID := chi.URLParam(r, "id")
|
||||
articleIDint, err := strconv.Atoi(articleID)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
getArticle, _ := api.Container.GetArticleUseCase.GetArticle(uint32(articleIDint))
|
||||
|
||||
_, _ = w.Write(getArticleEditPageTemplate(getArticle, ArticleEditPageAlert{
|
||||
IsError: false,
|
||||
Message: "",
|
||||
}))
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"RenewCMS/api"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
func updateIsOnline(articleId string, isOnline bool) (error, int) {
|
||||
articleIdInt, err := strconv.Atoi(articleId)
|
||||
if err != nil {
|
||||
return errors.New("the server expects the ID to be in the format of an unsigned 32-bit integer (uint32)"), http.StatusBadRequest
|
||||
}
|
||||
|
||||
_, err = api.Container.UpdateArticleUseCase.UpdateIsOnline(uint32(articleIdInt), isOnline)
|
||||
if err != nil {
|
||||
return errors.New("the requested resource, identified by its unique ID, could not be found on the server"), http.StatusNotFound
|
||||
}
|
||||
|
||||
return nil, http.StatusOK
|
||||
}
|
||||
|
||||
func GetArticleUnpublishPage(w http.ResponseWriter, r *http.Request) {
|
||||
articleId := chi.URLParam(r, "id")
|
||||
err, statusCode := updateIsOnline(articleId, false)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), statusCode)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/article", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func GetArticlePublishPage(w http.ResponseWriter, r *http.Request) {
|
||||
articleId := chi.URLParam(r, "id")
|
||||
err, statusCode := updateIsOnline(articleId, true)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), statusCode)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/article", http.StatusSeeOther)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"RenewCMS/api"
|
||||
"html/template"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func GetArticlesPage(w http.ResponseWriter, _ *http.Request) {
|
||||
articles := api.Container.ListArticlesUseCase.ListArticles()
|
||||
|
||||
var formattedArticles []map[string]any
|
||||
for _, article := range articles {
|
||||
formattedArticles = append(formattedArticles, map[string]any{
|
||||
"ID": article.ID,
|
||||
"Title": article.Title,
|
||||
"IsOnline": article.IsOnline,
|
||||
"CreatedAt": article.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
"UpdatedAt": article.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
|
||||
articlesTmpl, _ := api.Container.GetPageUseCase.GetPage("articles", map[string]any{
|
||||
"Navbar": template.HTML(navbarTmpl),
|
||||
"Head": headTmpl,
|
||||
"Articles": formattedArticles,
|
||||
})
|
||||
|
||||
_, _ = w.Write(articlesTmpl)
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"RenewCMS/api"
|
||||
"html/template"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func GetHomePage(w http.ResponseWriter, _ *http.Request) {
|
||||
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
|
||||
homeTmpl, _ := api.Container.GetPageUseCase.GetPage("home", map[string]interface{}{
|
||||
homeTmpl, _ := api.Container.GetPageUseCase.GetPage("home", map[string]any{
|
||||
"Navbar": template.HTML(navbarTmpl),
|
||||
"Head": headTmpl,
|
||||
})
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"RenewCMS/api"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func GetPageIntegration(w http.ResponseWriter, r *http.Request) {
|
||||
func GetPageIntegration(w http.ResponseWriter, _ *http.Request) {
|
||||
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
|
||||
templ, _ := api.Container.GetPageUseCase.GetPage("integration", map[string]interface{}{
|
||||
templ, _ := api.Container.GetPageUseCase.GetPage("integration", map[string]any{
|
||||
"Navbar": template.HTML(navbarTmpl),
|
||||
"Head": headTmpl,
|
||||
"Host": os.Getenv("HOST"),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/api/controllers/auth"
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/api/controllers/auth"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
@@ -35,7 +35,7 @@ func GetLoginPageHandler(loginPage *LoginPage) http.HandlerFunc {
|
||||
}
|
||||
success, _ := url.QueryUnescape(r.URL.Query().Get("success"))
|
||||
failure, _ := url.QueryUnescape(r.URL.Query().Get("failure"))
|
||||
bs, _ := api.Container.GetPageUseCase.GetPage("login", map[string]interface{}{
|
||||
bs, _ := api.Container.GetPageUseCase.GetPage("login", map[string]any{
|
||||
"PageError": loginPage.PageError,
|
||||
"Username": loginPage.Username,
|
||||
"Head": headTmpl,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/api/controllers/auth"
|
||||
"GoCMS/api/controllers/image"
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/api/controllers/auth"
|
||||
"RenewCMS/api/controllers/image"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -140,20 +140,20 @@ func NewPageRouter() http.Handler {
|
||||
|
||||
r.Get("/home", GetHomePage)
|
||||
|
||||
r.Get("/post", GetPostsPage)
|
||||
r.Get("/article", GetArticlesPage)
|
||||
|
||||
r.Get("/post/{id}/edit", GetPostEditPage)
|
||||
r.Post("/post/{id}/edit", PostPostEditPage)
|
||||
r.Get("/article/{id}/edit", GetArticleEditPage)
|
||||
r.Post("/article/{id}/edit", PostArticleEditPage)
|
||||
|
||||
r.Get("/post/{id}/delete", GetPostDeletePage)
|
||||
r.Get("/article/{id}/delete", GetArticleDeletePage)
|
||||
|
||||
r.Get("/post/create", GetPostCreatePage)
|
||||
r.Post("/post/create", PostPostCreatePage)
|
||||
r.Get("/article/create", GetArticleCreatePage)
|
||||
r.Post("/article/create", PostArticleCreatePage)
|
||||
|
||||
r.Post("/post/{id}/image/create", image.PostImage)
|
||||
r.Post("/article/{id}/image/create", image.PostImage)
|
||||
|
||||
r.Get("/post/{id}/publish", GetPostPublishPage)
|
||||
r.Get("/post/{id}/unpublish", GetPostUnpublishPage)
|
||||
r.Get("/article/{id}/publish", GetArticlePublishPage)
|
||||
r.Get("/article/{id}/unpublish", GetArticleUnpublishPage)
|
||||
|
||||
r.Get("/integration", GetPageIntegration)
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"RenewCMS/api"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
@@ -18,7 +18,7 @@ func GetPasswordResetRequest(w http.ResponseWriter, r *http.Request) {
|
||||
success := r.URL.Query().Get("success")
|
||||
email := r.URL.Query().Get("email")
|
||||
|
||||
bs, _ := api.Container.GetPageUseCase.GetPage("passwordResetRequest", map[string]interface{}{
|
||||
bs, _ := api.Container.GetPageUseCase.GetPage("passwordResetRequest", map[string]any{
|
||||
"Head": headTmpl,
|
||||
"Email": email,
|
||||
"Success": success,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"RenewCMS/api"
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
@@ -16,7 +16,7 @@ func GetPasswordResetValidate(w http.ResponseWriter, r *http.Request) {
|
||||
if failure != "" {
|
||||
pageError = NewPageError(failure)
|
||||
}
|
||||
template, _ := api.Container.GetPageUseCase.GetPage("passwordResetValidate", map[string]interface{}{
|
||||
template, _ := api.Container.GetPageUseCase.GetPage("passwordResetValidate", map[string]any{
|
||||
"Head": headTmpl,
|
||||
"Error": pageError,
|
||||
"Email": r.URL.Query().Get("email"),
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/useCases"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type PostCreatePageError struct {
|
||||
IsError bool
|
||||
Message string
|
||||
}
|
||||
|
||||
func GetPostCreatePageTemplate(postName string, errorMessage string) ([]byte, error) {
|
||||
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
|
||||
return api.Container.GetPageUseCase.GetPage("postCreate", map[string]interface{}{
|
||||
"Navbar": template.HTML(navbarTmpl),
|
||||
"Head": headTmpl,
|
||||
"PageError": PostCreatePageError{
|
||||
IsError: errorMessage != "",
|
||||
Message: errorMessage,
|
||||
},
|
||||
"Name": postName,
|
||||
})
|
||||
}
|
||||
|
||||
func PostPostCreatePage(w http.ResponseWriter, r *http.Request) {
|
||||
_ = r.ParseForm()
|
||||
|
||||
postName := r.FormValue("name")
|
||||
pattern := regexp.MustCompile("^[a-zA-Z0-9À-ÖØ-öø-ÿĀ-ſḀ-ỿ ]{3,50}$")
|
||||
|
||||
if !pattern.MatchString(postName) {
|
||||
postsTmpl, _ := GetPostCreatePageTemplate(postName, "Name should be alphanumeric, and between 3 and 50 characters.")
|
||||
_, _ = w.Write(postsTmpl)
|
||||
return
|
||||
}
|
||||
|
||||
post, err := api.Container.CreatePostUseCase.CreatePost(useCases.CreatePostCommand{
|
||||
Title: postName,
|
||||
Body: "",
|
||||
})
|
||||
if err != nil {
|
||||
postsTmpl, _ := GetPostCreatePageTemplate(postName, "Something went wrong when creating the post, please contact admin.")
|
||||
_, _ = w.Write(postsTmpl)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/post/"+strconv.Itoa(int(post.ID))+"/edit", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func GetPostCreatePage(w http.ResponseWriter, _ *http.Request) {
|
||||
postsTmpl, _ := GetPostCreatePageTemplate("", "")
|
||||
_, _ = w.Write(postsTmpl)
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/domain/post"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type PostEditPageAlert struct {
|
||||
IsError bool
|
||||
Message string
|
||||
}
|
||||
|
||||
func getPostEditPageTemplate(post post.Post, alert PostEditPageAlert) []byte {
|
||||
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
|
||||
postTmpl, _ := api.Container.GetPageUseCase.GetPage("postEdit", map[string]interface{}{
|
||||
"Navbar": template.HTML(navbarTmpl),
|
||||
"Head": headTmpl,
|
||||
"Post": post,
|
||||
"Alert": alert,
|
||||
"Secured": os.Getenv("ENVIRONMENT") == "production",
|
||||
})
|
||||
return postTmpl
|
||||
}
|
||||
|
||||
func PostPostEditPage(w http.ResponseWriter, r *http.Request) {
|
||||
postID := chi.URLParam(r, "id")
|
||||
postIDint, err := strconv.Atoi(postID)
|
||||
if err != nil {
|
||||
_, _ = w.Write(getPostEditPageTemplate(post.Post{}, PostEditPageAlert{
|
||||
IsError: true,
|
||||
Message: "Could not find the requested post.",
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
_ = r.ParseForm()
|
||||
postBody := r.FormValue("postBody")
|
||||
|
||||
getPost, _ := api.Container.GetPostUseCase.GetPost(uint32(postIDint))
|
||||
updatedPost, err := api.Container.UpdatePostUseCase.UpdateBody(getPost.ID, postBody)
|
||||
if err != nil {
|
||||
_, _ = w.Write(getPostEditPageTemplate(post.Post{Body: postBody}, PostEditPageAlert{
|
||||
IsError: true,
|
||||
Message: "Could not save the post: " + err.Error(),
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = w.Write(getPostEditPageTemplate(updatedPost, PostEditPageAlert{
|
||||
IsError: false,
|
||||
Message: "Post successfully edited!",
|
||||
}))
|
||||
}
|
||||
|
||||
func GetPostEditPage(w http.ResponseWriter, r *http.Request) {
|
||||
postID := chi.URLParam(r, "id")
|
||||
postIDint, err := strconv.Atoi(postID)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
getPost, _ := api.Container.GetPostUseCase.GetPost(uint32(postIDint))
|
||||
|
||||
_, _ = w.Write(getPostEditPageTemplate(getPost, PostEditPageAlert{
|
||||
IsError: false,
|
||||
Message: "",
|
||||
}))
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
func updateIsOnline(postId string, isOnline bool) (error, int) {
|
||||
postIdInt, err := strconv.Atoi(postId)
|
||||
if err != nil {
|
||||
return errors.New("the server expects the ID to be in the format of an unsigned 32-bit integer (uint32)"), http.StatusBadRequest
|
||||
}
|
||||
|
||||
_, err = api.Container.UpdatePostUseCase.UpdateIsOnline(uint32(postIdInt), isOnline)
|
||||
if err != nil {
|
||||
return errors.New("the requested resource, identified by its unique ID, could not be found on the server"), http.StatusNotFound
|
||||
}
|
||||
|
||||
return nil, http.StatusOK
|
||||
}
|
||||
|
||||
func GetPostUnpublishPage(w http.ResponseWriter, r *http.Request) {
|
||||
postId := chi.URLParam(r, "id")
|
||||
err, statusCode := updateIsOnline(postId, false)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), statusCode)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/post", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func GetPostPublishPage(w http.ResponseWriter, r *http.Request) {
|
||||
postId := chi.URLParam(r, "id")
|
||||
err, statusCode := updateIsOnline(postId, true)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), statusCode)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/post", http.StatusSeeOther)
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"html/template"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func GetPostsPage(w http.ResponseWriter, _ *http.Request) {
|
||||
posts := api.Container.ListPostsUseCase.ListPosts()
|
||||
|
||||
var formattedPosts []map[string]interface{}
|
||||
for _, post := range posts {
|
||||
formattedPosts = append(formattedPosts, map[string]interface{}{
|
||||
"ID": post.ID,
|
||||
"Title": post.Title,
|
||||
"IsOnline": post.IsOnline,
|
||||
"CreatedAt": post.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
"UpdatedAt": post.UpdatedAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
navbarTmpl, _ := api.Container.GetPageUseCase.GetPage("componentNavbar", nil)
|
||||
postsTmpl, _ := api.Container.GetPageUseCase.GetPage("posts", map[string]interface{}{
|
||||
"Navbar": template.HTML(navbarTmpl),
|
||||
"Head": headTmpl,
|
||||
"Posts": formattedPosts,
|
||||
})
|
||||
|
||||
_, _ = w.Write(postsTmpl)
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/api/controllers/auth"
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/api/controllers/auth"
|
||||
"RenewCMS/useCases"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type RegisterPageError struct {
|
||||
@@ -44,7 +43,7 @@ func GetRegisterPageHandler(registerPage *RegisterPage) http.HandlerFunc {
|
||||
PostRegisterPage(w, r)
|
||||
return
|
||||
}
|
||||
bs, err := api.Container.GetPageUseCase.GetPage("register", map[string]interface{}{
|
||||
bs, err := api.Container.GetPageUseCase.GetPage("register", map[string]any{
|
||||
"PageError": registerPage.PageError,
|
||||
"Username": registerPage.Username,
|
||||
"Email": registerPage.Email,
|
||||
@@ -80,8 +79,11 @@ func PostRegisterPage(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
verificationCode := uuid.NewString()
|
||||
createdUser, err := auth.GetNewUser(credentials, verificationCode)
|
||||
createdUser, err := api.Container.CreateUserUseCase.CreateUser(useCases.CreateUserCommand{
|
||||
Username: credentials.Username,
|
||||
Password: credentials.Password,
|
||||
Email: credentials.Email,
|
||||
})
|
||||
if err != nil {
|
||||
r.Method = http.MethodGet
|
||||
GetRegisterPageHandler(&RegisterPage{
|
||||
@@ -98,7 +100,7 @@ func PostRegisterPage(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
_ = api.Container.SendMailUseCase.SendMail(createdUser.Email, "mailValidation", map[string]string{
|
||||
"Host": os.Getenv("HOST"),
|
||||
"VerificationCode": verificationCode,
|
||||
"VerificationCode": createdUser.VerificationCode,
|
||||
})
|
||||
|
||||
_ = auth.SetJwtCookie(&w, createdUser.ID)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/api/controllers/auth"
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/api/controllers/auth"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
@@ -29,7 +29,7 @@ func PostRegisterPendingPage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func GetRegisterPendingPage(w http.ResponseWriter, _ *http.Request) {
|
||||
registerPendingTmpl, _ := api.Container.GetPageUseCase.GetPage("registerPending", map[string]interface{}{
|
||||
registerPendingTmpl, _ := api.Container.GetPageUseCase.GetPage("registerPending", map[string]any{
|
||||
"Head": headTmpl,
|
||||
})
|
||||
_, _ = w.Write(registerPendingTmpl)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package pages
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/api/controllers/auth"
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/api/controllers/auth"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@@ -38,7 +38,7 @@ func GetRegisterValidatePage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
registerValidateTmpl, _ := api.Container.GetPageUseCase.GetPage("registerValidate", map[string]interface{}{
|
||||
registerValidateTmpl, _ := api.Container.GetPageUseCase.GetPage("registerValidate", map[string]any{
|
||||
"Head": headTmpl,
|
||||
"PageError": NewPageError(errorMessage),
|
||||
})
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
package post
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/api/controllers/auth"
|
||||
"GoCMS/domain/post"
|
||||
"GoCMS/useCases"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type PostPost struct {
|
||||
Title string `json:"title" validate:"required,min=3,max=50"`
|
||||
Body string `json:"body" validate:"required,max=10000"`
|
||||
}
|
||||
|
||||
const IdUint32ErrorMessage = "The server expects the ID to be in the format of an unsigned 32-bit integer (uint32)."
|
||||
|
||||
func getPost(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 32)
|
||||
if err != nil {
|
||||
http.Error(w, IdUint32ErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
localPost, err := api.Container.GetPostUseCase.GetPost(uint32(id))
|
||||
if err != nil || !localPost.IsOnline {
|
||||
http.Error(w, "The requested resource, identified by its unique ID, could not be found on the server.", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
postJson, _ := json.Marshal(localPost)
|
||||
_, _ = w.Write(postJson)
|
||||
}
|
||||
|
||||
func postPost(w http.ResponseWriter, r *http.Request) {
|
||||
var localPost PostPost
|
||||
err := json.NewDecoder(r.Body).Decode(&localPost)
|
||||
if err != nil {
|
||||
http.Error(w, auth.BodyErrorMessage, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
err = api.Validate.Struct(localPost)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
createdPost, err := api.Container.CreatePostUseCase.CreatePost(useCases.CreatePostCommand{
|
||||
Title: localPost.Title,
|
||||
Body: localPost.Body,
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
postJson, _ := json.Marshal(createdPost)
|
||||
|
||||
_, _ = w.Write(postJson)
|
||||
}
|
||||
|
||||
func listPosts(w http.ResponseWriter, _ *http.Request) {
|
||||
posts := api.Container.ListPostsUseCase.ListPosts()
|
||||
onlinePosts := make([]post.Post, 0)
|
||||
for _, localPost := range posts {
|
||||
if localPost.IsOnline {
|
||||
onlinePosts = append(onlinePosts, localPost)
|
||||
}
|
||||
}
|
||||
postsJson, _ := json.Marshal(onlinePosts)
|
||||
_, _ = w.Write(postsJson)
|
||||
}
|
||||
|
||||
func deletePost(w http.ResponseWriter, r *http.Request) {
|
||||
id, err := strconv.ParseUint(chi.URLParam(r, "id"), 10, 32)
|
||||
if err != nil {
|
||||
http.Error(w, IdUint32ErrorMessage, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
err = api.Container.DeletePostUseCase.DeletePost(uint32(id))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
}
|
||||
|
||||
_, _ = w.Write([]byte("post deleted"))
|
||||
}
|
||||
|
||||
func NewPostRouter() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
r.Get("/{id}", getPost)
|
||||
r.Post("/", postPost)
|
||||
r.Get("/", listPosts)
|
||||
r.Delete("/{id}", deletePost)
|
||||
return r
|
||||
}
|
||||
+66
-47
@@ -1,30 +1,40 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways/models"
|
||||
"GoCMS/useCases"
|
||||
"github.com/glebarez/sqlite"
|
||||
"go.uber.org/dig"
|
||||
"gorm.io/gorm"
|
||||
"RenewCMS/adapters/secondary/gateways"
|
||||
"RenewCMS/adapters/secondary/gateways/models"
|
||||
domainGateways "RenewCMS/domain/gateways"
|
||||
"RenewCMS/useCases"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
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
|
||||
CreateImageUseCase *useCases.CreateImageUseCase
|
||||
DeleteImageUseCase *useCases.DeleteImageUseCase
|
||||
CreateArticleUseCase *useCases.CreateArticleUseCase
|
||||
GetArticleUseCase *useCases.GetArticleUseCase
|
||||
ListArticlesUseCase *useCases.ListArticlesUseCase
|
||||
UpdateArticleUseCase *useCases.UpdateArticleUseCase
|
||||
DeleteArticleUseCase *useCases.DeleteArticleUseCase
|
||||
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
|
||||
}
|
||||
|
||||
type Repositories struct {
|
||||
ArticleRepo domainGateways.IArticleRepository
|
||||
UserRepo domainGateways.IUserRepository
|
||||
ImageRepo domainGateways.IImageRepository
|
||||
MailRepo domainGateways.IMailRepository
|
||||
PageRepo domainGateways.IPageRepository
|
||||
}
|
||||
|
||||
var Container *UseCases
|
||||
@@ -38,36 +48,45 @@ func getDb() *gorm.DB {
|
||||
if err != nil {
|
||||
panic("Unable to open the database: " + err.Error())
|
||||
}
|
||||
|
||||
if err := db.AutoMigrate(&models.Article{}, &models.User{}); err != nil {
|
||||
panic("Failed to migrate database: " + err.Error())
|
||||
}
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
func InitContainer() {
|
||||
digContainer := dig.New()
|
||||
|
||||
database := getDb()
|
||||
_ = database.AutoMigrate(&models.Post{}, &models.User{})
|
||||
_ = digContainer.Provide(func() *gorm.DB { return database })
|
||||
|
||||
_ = 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(),
|
||||
CreateImageUseCase: useCases.NewCreateImageUseCase(db),
|
||||
DeleteImageUseCase: useCases.NewDeleteImageUseCase(db),
|
||||
}
|
||||
})
|
||||
err := digContainer.Invoke(func(useCases *UseCases) { Container = useCases })
|
||||
if err != nil {
|
||||
panic("Unable to invoke container: " + err.Error())
|
||||
func getRepositories(db *gorm.DB) *Repositories {
|
||||
return &Repositories{
|
||||
ArticleRepo: gateways.NewArticleRepository(db),
|
||||
UserRepo: gateways.NewUserRepository(db),
|
||||
ImageRepo: gateways.NewImageRepository(db),
|
||||
MailRepo: gateways.NewMailRepository(),
|
||||
PageRepo: gateways.NewPageRepository(),
|
||||
}
|
||||
}
|
||||
|
||||
func getUseCases(repos *Repositories) *UseCases {
|
||||
return &UseCases{
|
||||
CreateArticleUseCase: useCases.NewCreateArticleUseCase(repos.ArticleRepo),
|
||||
GetArticleUseCase: useCases.NewGetArticleUseCase(repos.ArticleRepo),
|
||||
ListArticlesUseCase: useCases.NewListArticlesUseCase(repos.ArticleRepo),
|
||||
UpdateArticleUseCase: useCases.NewUpdateArticleUseCase(repos.ArticleRepo),
|
||||
DeleteArticleUseCase: useCases.NewDeleteArticleUseCase(repos.ArticleRepo),
|
||||
GetUserUseCase: useCases.NewGetUserUseCase(repos.UserRepo),
|
||||
CreateUserUseCase: useCases.NewCreateUserUseCase(repos.UserRepo),
|
||||
UpdateUserUseCase: useCases.NewUpdateUserUseCase(repos.UserRepo),
|
||||
DeleteUserUseCase: useCases.NewDeleteUserUseCase(repos.UserRepo),
|
||||
ListUsersUseCase: useCases.NewListUsersUseCase(repos.UserRepo),
|
||||
GetPageUseCase: useCases.NewGetPageUseCase(repos.PageRepo),
|
||||
SendMailUseCase: useCases.NewSendMailUseCase(repos.MailRepo),
|
||||
CreateImageUseCase: useCases.NewCreateImageUseCase(repos.ImageRepo),
|
||||
DeleteImageUseCase: useCases.NewDeleteImageUseCase(repos.ImageRepo),
|
||||
}
|
||||
}
|
||||
|
||||
func InitContainer() {
|
||||
db := getDb()
|
||||
repos := getRepositories(db)
|
||||
Container = getUseCases(repos)
|
||||
}
|
||||
|
||||
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 15 KiB |
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 1.8 KiB |
Vendored
BIN
Binary file not shown.
|
After Width: | Height: | Size: 472 B |
+1
-1
@@ -7,6 +7,6 @@ services:
|
||||
- ${DOCKER_DB_FOLDER}:/app/db/
|
||||
environment:
|
||||
- PORT=8080
|
||||
- DB_FILE=/app/db/gocms.db
|
||||
- DB_FILE=/app/db/RenewCMS.db
|
||||
env_file:
|
||||
- ./.env
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package post
|
||||
package article
|
||||
|
||||
import (
|
||||
entity "GoCMS/adapters/secondary/gateways/models"
|
||||
domain "GoCMS/domain/image"
|
||||
entity "RenewCMS/adapters/secondary/gateways/models"
|
||||
domain "RenewCMS/domain/image"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Post struct {
|
||||
type Article struct {
|
||||
ID uint32 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
@@ -19,8 +19,8 @@ type Post struct {
|
||||
func FromApi(
|
||||
title string,
|
||||
body string,
|
||||
) Post {
|
||||
return Post{
|
||||
) Article {
|
||||
return Article{
|
||||
Title: title,
|
||||
Body: body,
|
||||
}
|
||||
@@ -34,19 +34,19 @@ func FromDb(
|
||||
isOnline bool,
|
||||
createdAt time.Time,
|
||||
updatedAt time.Time,
|
||||
) Post {
|
||||
) Article {
|
||||
domainImages := make([]*domain.Image, len(images))
|
||||
for i, img := range images {
|
||||
domainImage := domain.FromDB(
|
||||
img.ID,
|
||||
img.Path,
|
||||
img.PostID,
|
||||
img.ArticleID,
|
||||
img.CreatedAt,
|
||||
img.UpdatedAt,
|
||||
)
|
||||
domainImages[i] = &domainImage
|
||||
}
|
||||
return Post{
|
||||
return Article{
|
||||
ID: id,
|
||||
Title: title,
|
||||
Body: body,
|
||||
@@ -0,0 +1,16 @@
|
||||
package gateways
|
||||
|
||||
import (
|
||||
"RenewCMS/domain/article"
|
||||
)
|
||||
|
||||
type IArticleRepository interface {
|
||||
Get(id uint32) (article.Article, error)
|
||||
GetByName(name string) (article.Article, error)
|
||||
GetAll() []article.Article
|
||||
Create(post article.Article) (article.Article, error)
|
||||
UpdateBody(id uint32, body string) (article.Article, error)
|
||||
UpdateIsOnline(id uint32, isOnline bool) (article.Article, error)
|
||||
Delete(id uint32) error
|
||||
AddImage(postId uint32, imageId uint32) error
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package gateways
|
||||
|
||||
import (
|
||||
"GoCMS/domain/image"
|
||||
"RenewCMS/domain/image"
|
||||
"mime/multipart"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package gateways
|
||||
|
||||
type IMailRepository interface {
|
||||
Send(receiverAddress string, templateName string, data interface{}) error
|
||||
Send(receiverAddress string, templateName string, data any) error
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package gateways
|
||||
|
||||
type IPageRepository interface {
|
||||
Get(name string, data interface{}) ([]byte, error)
|
||||
Get(name string, data any) ([]byte, error)
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package gateways
|
||||
|
||||
import (
|
||||
"GoCMS/domain/post"
|
||||
)
|
||||
|
||||
type IPostRepository interface {
|
||||
Get(id uint32) (post.Post, error)
|
||||
GetByName(name string) (post.Post, error)
|
||||
GetAll() []post.Post
|
||||
Create(post post.Post) (post.Post, error)
|
||||
UpdateBody(id uint32, body string) (post.Post, error)
|
||||
UpdateIsOnline(id uint32, isOnline bool) (post.Post, error)
|
||||
Delete(id uint32) error
|
||||
AddImage(postId uint32, imageId uint32) error
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package gateways
|
||||
|
||||
import "GoCMS/domain/user"
|
||||
import "RenewCMS/domain/user"
|
||||
|
||||
type IUserRepository interface {
|
||||
Get(id uint32) (user.User, error)
|
||||
|
||||
@@ -7,16 +7,16 @@ import (
|
||||
type Image struct {
|
||||
ID uint32 `json:"id"`
|
||||
Path string `json:"path"`
|
||||
PostID uint32 `json:"post_id"`
|
||||
ArticleID uint32 `json:"article_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func FromDB(id uint32, path string, postId uint32, createdAt time.Time, updatedAt time.Time) Image {
|
||||
func FromDB(id uint32, path string, articleId uint32, createdAt time.Time, updatedAt time.Time) Image {
|
||||
return Image{
|
||||
ID: id,
|
||||
Path: path,
|
||||
PostID: postId,
|
||||
ArticleID: articleId,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
}
|
||||
|
||||
@@ -1,63 +1,54 @@
|
||||
module GoCMS
|
||||
module RenewCMS
|
||||
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.24.1
|
||||
go 1.25.4
|
||||
|
||||
require (
|
||||
github.com/MadAppGang/httplog v1.3.0
|
||||
github.com/glebarez/sqlite v1.11.0
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-chi/jwtauth/v5 v5.3.2
|
||||
github.com/go-playground/validator/v10 v10.25.0
|
||||
github.com/go-chi/cors v1.2.2
|
||||
github.com/go-chi/jwtauth/v5 v5.3.3
|
||||
github.com/go-playground/validator/v10 v10.28.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.uber.org/dig v1.18.1
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/crypto v0.44.0
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gorm.io/gorm v1.25.12
|
||||
gorm.io/gorm v1.31.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.11 // indirect
|
||||
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
|
||||
github.com/lestrrat-go/blackmagic v1.0.4 // indirect
|
||||
github.com/lestrrat-go/httpcc v1.0.1 // indirect
|
||||
github.com/lestrrat-go/httprc v1.0.6 // indirect
|
||||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||
github.com/lestrrat-go/jwx/v2 v2.1.4 // indirect
|
||||
github.com/lestrrat-go/jwx/v2 v2.1.6 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/segmentio/asm v1.2.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
|
||||
golang.org/x/net v0.37.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
github.com/segmentio/asm v1.2.1 // indirect
|
||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/libc v1.67.0 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
modernc.org/sqlite v1.36.0 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.40.1 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/go-chi/chi/v5 v5.2.1
|
||||
github.com/go-chi/chi/v5 v5.2.3
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
)
|
||||
|
||||
@@ -2,7 +2,6 @@ github.com/MadAppGang/httplog v1.3.0 h1:1XU54TO8kiqTeO+7oZLKAM3RP/cJ7SadzslRcKsp
|
||||
github.com/MadAppGang/httplog v1.3.0/go.mod h1:gpYEdkjh/Cda6YxtDy4AB7KY+fR7mb3SqBZw74A5hJ4=
|
||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4=
|
||||
github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -12,32 +11,34 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
|
||||
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
|
||||
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
|
||||
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
|
||||
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
|
||||
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
|
||||
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
|
||||
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-chi/jwtauth/v5 v5.3.2 h1:s+ON3ATyyMs3Me0kqyuua6Rwu+2zqIIkL0GCaMarwvs=
|
||||
github.com/go-chi/jwtauth/v5 v5.3.2/go.mod h1:O4QvPRuZLZghl9WvfVaON+ARfGzpD2PBX/QY5vUz7aQ=
|
||||
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
|
||||
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
|
||||
github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
|
||||
github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-chi/jwtauth/v5 v5.3.3 h1:50Uzmacu35/ZP9ER2Ht6SazwPsnLQ9LRJy6zTZJpHEo=
|
||||
github.com/go-chi/jwtauth/v5 v5.3.3/go.mod h1:O4QvPRuZLZghl9WvfVaON+ARfGzpD2PBX/QY5vUz7aQ=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
|
||||
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
|
||||
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
|
||||
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8=
|
||||
github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI=
|
||||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||
@@ -46,92 +47,86 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
|
||||
github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
|
||||
github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA=
|
||||
github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
|
||||
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
|
||||
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
|
||||
github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k=
|
||||
github.com/lestrrat-go/httprc v1.0.6/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
|
||||
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
|
||||
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
|
||||
github.com/lestrrat-go/jwx/v2 v2.1.4 h1:uBCMmJX8oRZStmKuMMOFb0Yh9xmEMgNJLgjuKKt4/qc=
|
||||
github.com/lestrrat-go/jwx/v2 v2.1.4/go.mod h1:nWRbDFR1ALG2Z6GJbBXzfQaYyvn751KuuyySN2yR6is=
|
||||
github.com/lestrrat-go/jwx/v2 v2.1.6 h1:hxM1gfDILk/l5ylers6BX/Eq1m/pnxe9NBwW6lVfecA=
|
||||
github.com/lestrrat-go/jwx/v2 v2.1.6/go.mod h1:Y722kU5r/8mV7fYDifjug0r8FK8mZdw0K0GpJw/l8pU=
|
||||
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
|
||||
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
|
||||
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
go.uber.org/dig v1.18.1 h1:rLww6NuajVjeQn+49u5NcezUJEGwd5uXmyoCKW2g5Es=
|
||||
go.uber.org/dig v1.18.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
|
||||
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6 h1:zfMcR1Cs4KNuomFFgGefv5N0czO2XZpUbxGUy8i8ug0=
|
||||
golang.org/x/exp v0.0.0-20251113190631-e25ba8c21ef6/go.mod h1:46edojNIoXTNOhySWIWdix628clX9ODXwPsQuG6hsK0=
|
||||
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
|
||||
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
|
||||
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
|
||||
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
|
||||
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
|
||||
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
|
||||
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=
|
||||
modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
|
||||
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
|
||||
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
|
||||
gorm.io/gorm v1.31.1 h1:7CA8FTFz/gRfgqgpeKIBcervUn3xSyPUmr6B2WXJ7kg=
|
||||
gorm.io/gorm v1.31.1/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
|
||||
modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=
|
||||
modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc=
|
||||
modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM=
|
||||
modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA=
|
||||
modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc=
|
||||
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE=
|
||||
modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||
modernc.org/libc v1.67.0 h1:QzL4IrKab2OFmxA3/vRYl0tLXrIamwrhD6CKD4WBVjQ=
|
||||
modernc.org/libc v1.67.0/go.mod h1:QvvnnJ5P7aitu0ReNpVIEyesuhmDLQ8kaEoyMjIFZJA=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
|
||||
modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU=
|
||||
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||
modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||
modernc.org/sqlite v1.36.0 h1:EQXNRn4nIS+gfsKeUTymHIz1waxuv5BzU7558dHSfH8=
|
||||
modernc.org/sqlite v1.36.0/go.mod h1:7MPwH7Z6bREicF9ZVUR78P1IKuxfZ8mRIDHD0iD+8TU=
|
||||
modernc.org/sqlite v1.40.1 h1:VfuXcxcUWWKRBuP8+BR9L7VnmusMgBNNnBYGEe9w/iY=
|
||||
modernc.org/sqlite v1.40.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE=
|
||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package main
|
||||
|
||||
import "GoCMS/main/server"
|
||||
import "RenewCMS/main/server"
|
||||
|
||||
func main() {
|
||||
router := server.InitServer()
|
||||
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"GoCMS/api/controllers/auth"
|
||||
"GoCMS/api/controllers/pages"
|
||||
"GoCMS/api/controllers/post"
|
||||
"RenewCMS/api/controllers/article"
|
||||
"RenewCMS/api/controllers/auth"
|
||||
"RenewCMS/api/controllers/pages"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -49,7 +49,7 @@ func InitBackendRoutes() *chi.Mux {
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(jwtauth.Verifier(auth.Token))
|
||||
r.Use(jwtauth.Authenticator(auth.Token))
|
||||
r.Mount("/post", post.NewPostRouter())
|
||||
r.Mount("/article", article.NewArticleRouter())
|
||||
})
|
||||
r.Mount("/auth", auth.NewAuthRouter())
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"GoCMS/api"
|
||||
"GoCMS/main/route"
|
||||
"RenewCMS/api"
|
||||
"RenewCMS/main/route"
|
||||
"fmt"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/joho/godotenv"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
var possibleEnvFileLocations = []string{".env", "../.env"}
|
||||
@@ -52,7 +53,7 @@ func InitServer() *chi.Mux {
|
||||
}
|
||||
|
||||
func StartServer(router *chi.Mux) error {
|
||||
fmt.Println("Server starting on :" + os.Getenv("PORT"))
|
||||
fmt.Println("Server starting on http://" + os.Getenv("HOST"))
|
||||
err := http.ListenAndServe(":"+os.Getenv("PORT"), router)
|
||||
return err
|
||||
}
|
||||
|
||||
+19
-21
@@ -1,30 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
export GOARCH=amd64
|
||||
OUTPUT_DIR=./bin
|
||||
|
||||
GO_FILE_PATH="./main/main.go"
|
||||
PROGRAM_NAME=GoCMS
|
||||
PROGRAM_NAME=RenewCMS
|
||||
|
||||
# Compile for Windows
|
||||
GOOS=windows go build -o "$OUTPUT_DIR/${PROGRAM_NAME}_windows.exe" "$GO_FILE_PATH"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compilation for Windows failed."
|
||||
exit $?
|
||||
fi
|
||||
platforms=("windows/amd64" "windows/arm64" "linux/amd64" "linux/arm64" "darwin/amd64" "darwin/arm64")
|
||||
|
||||
# Compile for Linux
|
||||
GOOS=linux go build -o "$OUTPUT_DIR/${PROGRAM_NAME}_linux" "$GO_FILE_PATH"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compilation for Linux failed."
|
||||
exit $?
|
||||
fi
|
||||
for platform in "${platforms[@]}"
|
||||
do
|
||||
platform_split=(${platform//\// })
|
||||
GOOS=${platform_split[0]}
|
||||
GOARCH=${platform_split[1]}
|
||||
output_name="$OUTPUT_DIR/${PROGRAM_NAME}_${GOOS}_${GOARCH}"
|
||||
|
||||
if [ "$GOOS" = "windows" ]; then
|
||||
output_name+='.exe'
|
||||
fi
|
||||
|
||||
# Compile for macOS
|
||||
GOOS=darwin go build -o "$OUTPUT_DIR/${PROGRAM_NAME}_darwin" "$GO_FILE_PATH"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compilation for macOS failed."
|
||||
exit $?
|
||||
fi
|
||||
echo "Building for $GOOS/$GOARCH..."
|
||||
env GOOS=$GOOS GOARCH=$GOARCH go build -o "$output_name" "$GO_FILE_PATH"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Compilation for $GOOS/$GOARCH failed."
|
||||
exit $?
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Compilation successful for all platforms."
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"GoCMS/domain/post"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var TestCreatePostSuccess = func(t *testing.T) {
|
||||
jsonBody, err := json.Marshal(map[string]string{
|
||||
"title": "Test Title",
|
||||
"body": "Test Body",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r, _ := ApiRequest("POST", "/post", bytes.NewBuffer(jsonBody))
|
||||
|
||||
var response post.Post
|
||||
bd, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bd, &response)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.StatusCode)
|
||||
assert.Equal(t, "Test Title", response.Title)
|
||||
assert.Equal(t, "Test Body", response.Body)
|
||||
}
|
||||
|
||||
var TestCreatePostFailTitleMissing = func(t *testing.T) {
|
||||
jsonBody, err := json.Marshal(map[string]string{
|
||||
"body": "Test Body",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r, _ := ApiRequest("POST", "/post", bytes.NewBuffer(jsonBody))
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, r.StatusCode)
|
||||
}
|
||||
|
||||
var TestCreatePostTitleTooShort = func(t *testing.T) {
|
||||
jsonBody, err := json.Marshal(map[string]string{
|
||||
"title": "Te",
|
||||
"body": "Test Body",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r, _ := ApiRequest("POST", "/post", bytes.NewBuffer(jsonBody))
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, r.StatusCode)
|
||||
}
|
||||
|
||||
var TestGetPostSuccess = func(t *testing.T) {
|
||||
var createdPost post.Post
|
||||
var postToCreate = post.Post{
|
||||
Title: "Test Title",
|
||||
Body: "Test Body",
|
||||
}
|
||||
db := GetDb()
|
||||
db.Create(&postToCreate).Scan(&createdPost)
|
||||
|
||||
r, _ := ApiRequest("GET", "/post/"+strconv.Itoa(int(createdPost.ID)), nil)
|
||||
|
||||
var response post.Post
|
||||
bd, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bd, &response)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.StatusCode)
|
||||
assert.Equal(t, createdPost.ID, response.ID)
|
||||
assert.Equal(t, createdPost.Title, response.Title)
|
||||
assert.Equal(t, createdPost.Body, response.Body)
|
||||
}
|
||||
|
||||
var TestGetAllPostsSuccess = func(t *testing.T) {
|
||||
var createdPost post.Post
|
||||
var postToCreate = post.Post{
|
||||
Title: "Test Title",
|
||||
Body: "Test Body",
|
||||
}
|
||||
db := GetDb()
|
||||
db.Create(&postToCreate).Scan(&createdPost)
|
||||
|
||||
r, _ := ApiRequest("GET", "/post", nil)
|
||||
|
||||
var response []post.Post
|
||||
bd, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(bd, &response)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.StatusCode)
|
||||
assert.Equal(t, createdPost.Title, response[0].Title)
|
||||
assert.Equal(t, createdPost.Body, response[0].Body)
|
||||
}
|
||||
|
||||
var TestDeletePostSuccess = func(t *testing.T) {
|
||||
var createdPost post.Post
|
||||
var postToCreate = post.Post{
|
||||
Title: "Test Title",
|
||||
Body: "Test Body",
|
||||
}
|
||||
db := GetDb()
|
||||
db.Create(&postToCreate).Scan(&createdPost)
|
||||
|
||||
r, _ := ApiRequest("DELETE", "/post/"+strconv.Itoa(int(createdPost.ID)), nil)
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.StatusCode)
|
||||
}
|
||||
|
||||
var TestPostCreate = func(t *testing.T) {
|
||||
t.Run("Should return a post with the given title and body", TestCreatePostSuccess)
|
||||
t.Run("Should return an error if the title is missing", TestCreatePostFailTitleMissing)
|
||||
t.Run("Should return an error if the title is too short", TestCreatePostTitleTooShort)
|
||||
}
|
||||
|
||||
var TestPostGet = func(t *testing.T) {
|
||||
t.Run("Should return a post with the given id", TestGetPostSuccess)
|
||||
}
|
||||
|
||||
var TestPostGetAll = func(t *testing.T) {
|
||||
t.Run("Should return all posts", TestGetAllPostsSuccess)
|
||||
}
|
||||
|
||||
var TestPostDelete = func(t *testing.T) {
|
||||
t.Run("Should return success", TestDeletePostSuccess)
|
||||
}
|
||||
|
||||
func TestPost(t *testing.T) {
|
||||
StartServerIfNotAlready()
|
||||
WaitForServer()
|
||||
|
||||
t.Run("Create", TestPostCreate)
|
||||
t.Run("Get", TestPostGet)
|
||||
t.Run("GetAll", TestPostGetAll)
|
||||
t.Run("Delete", TestPostDelete)
|
||||
}
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways/models"
|
||||
"GoCMS/api/controllers/auth"
|
||||
"GoCMS/main/server"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const testDbFile = "test.db"
|
||||
|
||||
var ApiUrl string
|
||||
var AuthorizationCookie *http.Cookie
|
||||
var HttpClient = http.Client{}
|
||||
|
||||
func GetDb() *gorm.DB {
|
||||
db, err := gorm.Open(sqlite.Open(testDbFile), &gorm.Config{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_ = db.AutoMigrate(&models.Post{}, &models.User{})
|
||||
return db
|
||||
}
|
||||
|
||||
func StartServerIfNotAlready() {
|
||||
_, err := http.Get(ApiUrl)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
_ = os.Remove(testDbFile)
|
||||
_ = os.Setenv("DB_FILE", testDbFile)
|
||||
go func(url *string) {
|
||||
router := server.InitServer()
|
||||
*url = "http://localhost:" + os.Getenv("PORT") + "/v1"
|
||||
err := server.StartServer(router)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}(&ApiUrl)
|
||||
}
|
||||
|
||||
func getAuthorizationCookie(userId uint32) *http.Cookie {
|
||||
_, tokenString, err := auth.Token.Encode(map[string]interface{}{"user_id": userId})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &http.Cookie{
|
||||
Name: "jwt",
|
||||
Value: tokenString,
|
||||
Expires: time.Now().Add(24 * time.Hour),
|
||||
Secure: false,
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
}
|
||||
}
|
||||
|
||||
func SetAuthorizationCookieIfNotAlready(r *http.Request) {
|
||||
if AuthorizationCookie != nil {
|
||||
r.AddCookie(AuthorizationCookie)
|
||||
return
|
||||
}
|
||||
db := GetDb()
|
||||
user := models.User{
|
||||
Username: "testuser",
|
||||
Password: "testpassword",
|
||||
Email: "testemail@a.com",
|
||||
}
|
||||
var createdUser models.User
|
||||
db.Create(&user).Scan(&createdUser)
|
||||
AuthorizationCookie = getAuthorizationCookie(createdUser.ID)
|
||||
r.AddCookie(AuthorizationCookie)
|
||||
}
|
||||
|
||||
func WaitForServer() {
|
||||
for {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
if ApiUrl == "" {
|
||||
continue
|
||||
}
|
||||
_, err := http.Get(ApiUrl)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ApiRequest(method string, route string, body io.Reader) (*http.Response, error) {
|
||||
request, err := http.NewRequest(method, ApiUrl+route, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
SetAuthorizationCookieIfNotAlready(request)
|
||||
|
||||
response, err := HttpClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/domain/article"
|
||||
"RenewCMS/domain/gateways"
|
||||
)
|
||||
|
||||
type CreateArticleUseCase struct {
|
||||
articleRepository gateways.IArticleRepository
|
||||
}
|
||||
|
||||
type CreateArticleCommand struct {
|
||||
Title string
|
||||
Body string
|
||||
}
|
||||
|
||||
func NewCreateArticleUseCase(articleRepository gateways.IArticleRepository) *CreateArticleUseCase {
|
||||
return &CreateArticleUseCase{articleRepository}
|
||||
}
|
||||
|
||||
func (g *CreateArticleUseCase) CreateArticle(createArticle CreateArticleCommand) (article.Article, error) {
|
||||
return g.articleRepository.Create(article.FromApi(
|
||||
createArticle.Title,
|
||||
createArticle.Body,
|
||||
))
|
||||
}
|
||||
@@ -1,20 +1,17 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"GoCMS/domain/image"
|
||||
"gorm.io/gorm"
|
||||
"RenewCMS/domain/gateways"
|
||||
"RenewCMS/domain/image"
|
||||
"mime/multipart"
|
||||
)
|
||||
|
||||
type CreateImageUseCase struct {
|
||||
imageRepository gateways.ImageRepository
|
||||
imageRepository gateways.IImageRepository
|
||||
}
|
||||
|
||||
func NewCreateImageUseCase(db *gorm.DB) *CreateImageUseCase {
|
||||
return &CreateImageUseCase{
|
||||
imageRepository: *gateways.NewImageRepository(db),
|
||||
}
|
||||
func NewCreateImageUseCase(imageRepository gateways.IImageRepository) *CreateImageUseCase {
|
||||
return &CreateImageUseCase{imageRepository}
|
||||
}
|
||||
|
||||
func (g *CreateImageUseCase) CreateImage(file multipart.File, fileHeader multipart.FileHeader) (image.Image, error) {
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"GoCMS/domain/post"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CreatePostUseCase struct {
|
||||
postRepository gateways.PostRepository
|
||||
}
|
||||
|
||||
type CreatePostCommand struct {
|
||||
Title string
|
||||
Body string
|
||||
}
|
||||
|
||||
func NewCreatePostUseCase(db *gorm.DB) *CreatePostUseCase {
|
||||
return &CreatePostUseCase{
|
||||
postRepository: *gateways.NewPostRepository(db),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *CreatePostUseCase) CreatePost(createPost CreatePostCommand) (post.Post, error) {
|
||||
return g.postRepository.Create(post.FromApi(
|
||||
createPost.Title,
|
||||
createPost.Body,
|
||||
))
|
||||
}
|
||||
+20
-14
@@ -1,34 +1,40 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"GoCMS/domain/user"
|
||||
"gorm.io/gorm"
|
||||
"RenewCMS/domain/gateways"
|
||||
"RenewCMS/domain/user"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CreateUserUseCase struct {
|
||||
userRepository gateways.UserRepository
|
||||
userRepository gateways.IUserRepository
|
||||
}
|
||||
|
||||
type CreateUserCommand struct {
|
||||
Username string
|
||||
Password string
|
||||
Email string
|
||||
VerificationCode string
|
||||
Username string
|
||||
Password string
|
||||
Email string
|
||||
}
|
||||
|
||||
func NewCreateUserUseCase(db *gorm.DB) *CreateUserUseCase {
|
||||
return &CreateUserUseCase{
|
||||
userRepository: *gateways.NewUserRepository(db),
|
||||
}
|
||||
func NewCreateUserUseCase(userRepository gateways.IUserRepository) *CreateUserUseCase {
|
||||
return &CreateUserUseCase{userRepository}
|
||||
}
|
||||
|
||||
func (g *CreateUserUseCase) CreateUser(createUser CreateUserCommand) (user.User, error) {
|
||||
return g.userRepository.Create(user.FromApi(
|
||||
rawUuid := uuid.NewString()
|
||||
|
||||
createdUser, err := g.userRepository.Create(user.FromApi(
|
||||
createUser.Username,
|
||||
createUser.Password,
|
||||
"",
|
||||
createUser.Email,
|
||||
createUser.VerificationCode,
|
||||
rawUuid,
|
||||
))
|
||||
if err != nil {
|
||||
return user.User{}, err
|
||||
}
|
||||
|
||||
createdUser.VerificationCode = rawUuid
|
||||
return createdUser, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/domain/gateways"
|
||||
)
|
||||
|
||||
type DeleteArticleUseCase struct {
|
||||
articleRepository gateways.IArticleRepository
|
||||
}
|
||||
|
||||
func NewDeleteArticleUseCase(articleRepository gateways.IArticleRepository) *DeleteArticleUseCase {
|
||||
return &DeleteArticleUseCase{articleRepository}
|
||||
}
|
||||
|
||||
func (g *DeleteArticleUseCase) DeleteArticle(userId uint32) error {
|
||||
return g.articleRepository.Delete(userId)
|
||||
}
|
||||
@@ -1,18 +1,15 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"gorm.io/gorm"
|
||||
"RenewCMS/domain/gateways"
|
||||
)
|
||||
|
||||
type DeleteImageUseCase struct {
|
||||
imageRepository gateways.ImageRepository
|
||||
imageRepository gateways.IImageRepository
|
||||
}
|
||||
|
||||
func NewDeleteImageUseCase(db *gorm.DB) *DeleteImageUseCase {
|
||||
return &DeleteImageUseCase{
|
||||
imageRepository: *gateways.NewImageRepository(db),
|
||||
}
|
||||
func NewDeleteImageUseCase(imageRepository gateways.IImageRepository) *DeleteImageUseCase {
|
||||
return &DeleteImageUseCase{imageRepository}
|
||||
}
|
||||
|
||||
func (g *DeleteImageUseCase) DeleteImage(imageId uint32) error {
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type DeletePostUseCase struct {
|
||||
postRepository gateways.PostRepository
|
||||
}
|
||||
|
||||
func NewDeletePostUseCase(db *gorm.DB) *DeletePostUseCase {
|
||||
return &DeletePostUseCase{
|
||||
postRepository: *gateways.NewPostRepository(db),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *DeletePostUseCase) DeletePost(userId uint32) error {
|
||||
return g.postRepository.Delete(userId)
|
||||
}
|
||||
@@ -1,18 +1,15 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"gorm.io/gorm"
|
||||
"RenewCMS/domain/gateways"
|
||||
)
|
||||
|
||||
type DeleteUserUseCase struct {
|
||||
userRepository gateways.UserRepository
|
||||
userRepository gateways.IUserRepository
|
||||
}
|
||||
|
||||
func NewDeleteUserUseCase(db *gorm.DB) *DeleteUserUseCase {
|
||||
return &DeleteUserUseCase{
|
||||
userRepository: *gateways.NewUserRepository(db),
|
||||
}
|
||||
func NewDeleteUserUseCase(userRepository gateways.IUserRepository) *DeleteUserUseCase {
|
||||
return &DeleteUserUseCase{userRepository}
|
||||
}
|
||||
|
||||
func (g *DeleteUserUseCase) DeleteUser(userId uint32) error {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/domain/article"
|
||||
"RenewCMS/domain/gateways"
|
||||
)
|
||||
|
||||
type GetArticleUseCase struct {
|
||||
articleRepository gateways.IArticleRepository
|
||||
}
|
||||
|
||||
func NewGetArticleUseCase(articleRepository gateways.IArticleRepository) *GetArticleUseCase {
|
||||
return &GetArticleUseCase{articleRepository}
|
||||
}
|
||||
|
||||
func (g *GetArticleUseCase) GetArticle(id uint32) (article.Article, error) {
|
||||
return g.articleRepository.Get(id)
|
||||
}
|
||||
|
||||
func (g *GetArticleUseCase) GetArticleByName(name string) (article.Article, error) {
|
||||
return g.articleRepository.GetByName(name)
|
||||
}
|
||||
+5
-7
@@ -1,19 +1,17 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"RenewCMS/domain/gateways"
|
||||
)
|
||||
|
||||
type GetPageUseCase struct {
|
||||
pageRepository gateways.PageRepository
|
||||
pageRepository gateways.IPageRepository
|
||||
}
|
||||
|
||||
func NewGetPageUseCase() *GetPageUseCase {
|
||||
return &GetPageUseCase{
|
||||
pageRepository: *gateways.NewPageRepository(),
|
||||
}
|
||||
func NewGetPageUseCase(pageRepository gateways.IPageRepository) *GetPageUseCase {
|
||||
return &GetPageUseCase{pageRepository}
|
||||
}
|
||||
|
||||
func (g *GetPageUseCase) GetPage(name string, data interface{}) ([]byte, error) {
|
||||
func (g *GetPageUseCase) GetPage(name string, data any) ([]byte, error) {
|
||||
return g.pageRepository.Get(name, data)
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"GoCMS/domain/post"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type GetPostUseCase struct {
|
||||
postRepository gateways.PostRepository
|
||||
}
|
||||
|
||||
func NewGetPostUseCase(db *gorm.DB) *GetPostUseCase {
|
||||
return &GetPostUseCase{
|
||||
postRepository: *gateways.NewPostRepository(db),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GetPostUseCase) GetPost(id uint32) (post.Post, error) {
|
||||
return g.postRepository.Get(id)
|
||||
}
|
||||
|
||||
func (g *GetPostUseCase) GetPostByName(name string) (post.Post, error) {
|
||||
return g.postRepository.GetByName(name)
|
||||
}
|
||||
+5
-8
@@ -1,19 +1,16 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"GoCMS/domain/user"
|
||||
"gorm.io/gorm"
|
||||
"RenewCMS/domain/gateways"
|
||||
"RenewCMS/domain/user"
|
||||
)
|
||||
|
||||
type GetUserUseCase struct {
|
||||
userRepository gateways.UserRepository
|
||||
userRepository gateways.IUserRepository
|
||||
}
|
||||
|
||||
func NewGetUserUseCase(db *gorm.DB) *GetUserUseCase {
|
||||
return &GetUserUseCase{
|
||||
userRepository: *gateways.NewUserRepository(db),
|
||||
}
|
||||
func NewGetUserUseCase(userRepository gateways.IUserRepository) *GetUserUseCase {
|
||||
return &GetUserUseCase{userRepository}
|
||||
}
|
||||
|
||||
func (g *GetUserUseCase) GetUser(id uint32) (user.User, error) {
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/domain/article"
|
||||
"RenewCMS/domain/gateways"
|
||||
)
|
||||
|
||||
type ListArticlesUseCase struct {
|
||||
articleRepository gateways.IArticleRepository
|
||||
}
|
||||
|
||||
func NewListArticlesUseCase(articleRepository gateways.IArticleRepository) *ListArticlesUseCase {
|
||||
return &ListArticlesUseCase{articleRepository}
|
||||
}
|
||||
|
||||
func (g *ListArticlesUseCase) ListArticles() []article.Article {
|
||||
return g.articleRepository.GetAll()
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"GoCMS/domain/post"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ListPostsUseCase struct {
|
||||
postRepository gateways.PostRepository
|
||||
}
|
||||
|
||||
func NewListPostsUseCase(db *gorm.DB) *ListPostsUseCase {
|
||||
return &ListPostsUseCase{
|
||||
postRepository: *gateways.NewPostRepository(db),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *ListPostsUseCase) ListPosts() []post.Post {
|
||||
return g.postRepository.GetAll()
|
||||
}
|
||||
@@ -1,19 +1,16 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"GoCMS/domain/user"
|
||||
"gorm.io/gorm"
|
||||
"RenewCMS/domain/gateways"
|
||||
"RenewCMS/domain/user"
|
||||
)
|
||||
|
||||
type ListUsersUseCase struct {
|
||||
userRepository gateways.UserRepository
|
||||
userRepository gateways.IUserRepository
|
||||
}
|
||||
|
||||
func NewListUsersUseCase(db *gorm.DB) *ListUsersUseCase {
|
||||
return &ListUsersUseCase{
|
||||
userRepository: *gateways.NewUserRepository(db),
|
||||
}
|
||||
func NewListUsersUseCase(userRepository gateways.IUserRepository) *ListUsersUseCase {
|
||||
return &ListUsersUseCase{userRepository}
|
||||
}
|
||||
|
||||
func (g *ListUsersUseCase) ListUsers() []user.User {
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"RenewCMS/domain/gateways"
|
||||
)
|
||||
|
||||
type SendMailUseCase struct {
|
||||
mailRepository gateways.MailRepository
|
||||
mailRepository gateways.IMailRepository
|
||||
}
|
||||
|
||||
func NewSendMailUseCase() *SendMailUseCase {
|
||||
return &SendMailUseCase{}
|
||||
func NewSendMailUseCase(mailRepository gateways.IMailRepository) *SendMailUseCase {
|
||||
return &SendMailUseCase{mailRepository}
|
||||
}
|
||||
|
||||
func (g *SendMailUseCase) SendMail(receiverAddress string, templateName string, data interface{}) error {
|
||||
func (g *SendMailUseCase) SendMail(receiverAddress string, templateName string, data any) error {
|
||||
return g.mailRepository.Send(receiverAddress, templateName, data)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"RenewCMS/domain/article"
|
||||
"RenewCMS/domain/gateways"
|
||||
)
|
||||
|
||||
type UpdateArticleUseCase struct {
|
||||
articleRepository gateways.IArticleRepository
|
||||
}
|
||||
|
||||
func NewUpdateArticleUseCase(articleRepository gateways.IArticleRepository) *UpdateArticleUseCase {
|
||||
return &UpdateArticleUseCase{articleRepository}
|
||||
}
|
||||
|
||||
func (g *UpdateArticleUseCase) UpdateBody(id uint32, body string) (article.Article, error) {
|
||||
return g.articleRepository.UpdateBody(id, body)
|
||||
}
|
||||
|
||||
func (g *UpdateArticleUseCase) AddImage(articleId uint32, imageId uint32) error {
|
||||
return g.articleRepository.AddImage(articleId, imageId)
|
||||
}
|
||||
|
||||
func (g *UpdateArticleUseCase) UpdateIsOnline(id uint32, isOnline bool) (article.Article, error) {
|
||||
return g.articleRepository.UpdateIsOnline(id, isOnline)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"GoCMS/domain/post"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type UpdatePostUseCase struct {
|
||||
postRepository gateways.PostRepository
|
||||
}
|
||||
|
||||
func NewUpdatePostUseCase(db *gorm.DB) *UpdatePostUseCase {
|
||||
return &UpdatePostUseCase{
|
||||
postRepository: *gateways.NewPostRepository(db),
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
func (g *UpdatePostUseCase) UpdateIsOnline(id uint32, isOnline bool) (post.Post, error) {
|
||||
return g.postRepository.UpdateIsOnline(id, isOnline)
|
||||
}
|
||||
@@ -1,19 +1,16 @@
|
||||
package useCases
|
||||
|
||||
import (
|
||||
"GoCMS/adapters/secondary/gateways"
|
||||
"GoCMS/domain/user"
|
||||
"gorm.io/gorm"
|
||||
"RenewCMS/domain/gateways"
|
||||
"RenewCMS/domain/user"
|
||||
)
|
||||
|
||||
type UpdateUserUseCase struct {
|
||||
userRepository gateways.UserRepository
|
||||
userRepository gateways.IUserRepository
|
||||
}
|
||||
|
||||
func NewUpdateUserUseCase(db *gorm.DB) *UpdateUserUseCase {
|
||||
return &UpdateUserUseCase{
|
||||
userRepository: *gateways.NewUserRepository(db),
|
||||
}
|
||||
func NewUpdateUserUseCase(userRepository gateways.IUserRepository) *UpdateUserUseCase {
|
||||
return &UpdateUserUseCase{userRepository}
|
||||
}
|
||||
|
||||
func (g *UpdateUserUseCase) UpdateVerificationStatus(userId uint32, isVerified bool) (user.User, error) {
|
||||
|
||||
Reference in New Issue
Block a user