mirror of
https://github.com/Floriansylvain/RenewCMS.git
synced 2026-08-19 11:43:22 +02:00
clean: removed everything to set up 2.0
This commit is contained in:
@@ -1,58 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/Floriansylvain/GohCMS/internal/database"
|
||||
jwt "github.com/appleboy/gin-jwt/v2"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Email string `json:"email" bson:"email"`
|
||||
Password string `json:"password" bson:"password"`
|
||||
}
|
||||
|
||||
var UsersLocation = database.Location{Database: "gohcms", Collection: "users"}
|
||||
|
||||
var AuthMiddleware, _ = jwt.New(&jwt.GinJWTMiddleware{
|
||||
Realm: "GohCMS",
|
||||
Key: []byte(os.Getenv("APP_JWT_SECRET")),
|
||||
SendCookie: true,
|
||||
CookieHTTPOnly: true,
|
||||
CookieSameSite: http.SameSiteStrictMode,
|
||||
Timeout: time.Hour,
|
||||
MaxRefresh: time.Hour,
|
||||
LoginResponse: JWTLoginResponse,
|
||||
Authenticator: JWTAuthenticator,
|
||||
})
|
||||
|
||||
func JWTLoginResponse(c *gin.Context, code int, message string, expire time.Time) {
|
||||
if code == http.StatusOK {
|
||||
c.JSON(code, gin.H{"code": code, "message": "Successfully logged in!", "expire": expire.Format(time.RFC3339)})
|
||||
} else {
|
||||
c.JSON(code, gin.H{"code": code, "message": "Something wrong has happened."})
|
||||
}
|
||||
}
|
||||
|
||||
func JWTAuthenticator(c *gin.Context) (interface{}, error) {
|
||||
var user = User{}
|
||||
err := c.BindJSON(&user)
|
||||
if err != nil {
|
||||
return nil, errors.New("wrong credentials json format.")
|
||||
}
|
||||
|
||||
_, err = database.GetUniqueDocument(UsersLocation, bson.D{
|
||||
{Key: "email", Value: user.Email},
|
||||
{Key: "password", Value: user.Password},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.New("wrong email or password.")
|
||||
}
|
||||
|
||||
return gin.H{"email": user.Email}, nil
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SendBadRequest(c *gin.Context, message string) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"message": message, "code": 400})
|
||||
}
|
||||
|
||||
func SendOk(c *gin.Context, message string) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": message, "code": 200})
|
||||
}
|
||||
|
||||
func SendForbidden(c *gin.Context, message string) {
|
||||
c.JSON(http.StatusForbidden, gin.H{"message": message, "code": 403})
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func Ping(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"message": "pong"})
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package articles
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Floriansylvain/GohCMS/internal/api"
|
||||
"github.com/Floriansylvain/GohCMS/internal/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
func Add(c *gin.Context) {
|
||||
var article Article
|
||||
article.TitleID = c.Params.ByName("id")
|
||||
if c.BindJSON(&article) != nil {
|
||||
api.SendBadRequest(c, "Could not correctly parse the article.")
|
||||
return
|
||||
}
|
||||
|
||||
document, err := bson.Marshal(article)
|
||||
if err != nil {
|
||||
api.SendBadRequest(c, "Could not correctly marshal the article.")
|
||||
return
|
||||
}
|
||||
|
||||
documents, _ := database.GetDocuments(articlesLocation, map[string]any{})
|
||||
if IsArticleIdAlreadyUsed(article.TitleID, documents) {
|
||||
api.SendBadRequest(c, fmt.Sprintf("Article ID '%v' already used.", article.TitleID))
|
||||
return
|
||||
}
|
||||
|
||||
err = database.PushDocument(articlesLocation, document)
|
||||
if err != nil {
|
||||
api.SendBadRequest(c, fmt.Sprintf(`Could not insert document(s) into DB: %v`, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
api.SendOk(c, "Article successfully added!")
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package articles
|
||||
|
||||
import (
|
||||
"github.com/Floriansylvain/GohCMS/internal/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
type Article struct {
|
||||
TitleID string `json:"titleID" bson:"titleID"`
|
||||
Title string `json:"title" bson:"title"`
|
||||
Date int64 `json:"date" bson:"date"`
|
||||
Content gin.H `json:"content" bson:"content"`
|
||||
Tags []string `json:"tags" bson:"tags"`
|
||||
Online bool `json:"online" bson:"online"`
|
||||
}
|
||||
|
||||
var articlesLocation = database.Location{Database: "gohcms", Collection: "articles"}
|
||||
|
||||
func ParseArticlesFromBytesToArray(documents [][]byte) []Article {
|
||||
var articles = []Article{}
|
||||
|
||||
for i := 0; i < len(documents); i++ {
|
||||
var newArticle Article
|
||||
bson.Unmarshal(documents[i], &newArticle)
|
||||
articles = append(articles, newArticle)
|
||||
}
|
||||
|
||||
return articles
|
||||
}
|
||||
|
||||
func IsArticleIdAlreadyUsed(id string, documents [][]byte) bool {
|
||||
for i := 0; i < len(documents); i++ {
|
||||
var newArticle Article
|
||||
bson.Unmarshal(documents[i], &newArticle)
|
||||
if newArticle.TitleID == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package articles
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
var Article1, _ = bson.Marshal(Article{
|
||||
TitleID: "test_article_1",
|
||||
Date: 1671482492,
|
||||
Content: gin.H{},
|
||||
Tags: []string{"blog"},
|
||||
Online: false,
|
||||
})
|
||||
|
||||
var Article2, _ = bson.Marshal(Article{
|
||||
TitleID: "test_article_2",
|
||||
Date: 1671899112,
|
||||
Content: gin.H{},
|
||||
Tags: []string{"blog"},
|
||||
Online: false,
|
||||
})
|
||||
|
||||
var BSONConvertedArticles = [][]byte{Article1, Article2}
|
||||
|
||||
func TestGetAllArticlesBusiness(t *testing.T) {
|
||||
documents := ParseArticlesFromBytesToArray(BSONConvertedArticles)
|
||||
article := documents[0]
|
||||
|
||||
if article.TitleID != "test_article_1" {
|
||||
log.Fatalf(`Excepted "test_article_1" as IdName, found "%v"`, article.TitleID)
|
||||
} else if article.Date != 1671482492 {
|
||||
log.Fatalf(`Excepted 1671482492 as Date, found "%v"`, article.Date)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsArticleIdAlreadyUsed(t *testing.T) {
|
||||
if IsArticleIdAlreadyUsed("test_article_1", BSONConvertedArticles) == false {
|
||||
log.Fatalf(`Excepted true, found false`)
|
||||
} else if IsArticleIdAlreadyUsed("test_article_3", BSONConvertedArticles) == true {
|
||||
log.Fatalf(`Excepted false, found true`)
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package articles
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Floriansylvain/GohCMS/internal/api"
|
||||
"github.com/Floriansylvain/GohCMS/internal/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func Delete(c *gin.Context) {
|
||||
id := c.Params.ByName("id")
|
||||
|
||||
deleteCount, err := database.DeleteDocument(articlesLocation, map[string]any{"titleID": id})
|
||||
if err != nil {
|
||||
api.SendBadRequest(c, fmt.Sprintf(`Could not delete document(s) from DB: %v`, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if deleteCount != 0 {
|
||||
api.SendOk(c, fmt.Sprintf("%d article(s) was/were successfully deleted!", deleteCount))
|
||||
} else {
|
||||
api.SendOk(c, "No articles were deleted.")
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package articles
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/Floriansylvain/GohCMS/internal/api"
|
||||
"github.com/Floriansylvain/GohCMS/internal/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func Edit(c *gin.Context) {
|
||||
id := c.Params.ByName("id")
|
||||
|
||||
var articleUpdate database.DocumentUpdate
|
||||
articleUpdate.Filter = map[string]any{"titleID": id}
|
||||
c.BindJSON(&articleUpdate.Update)
|
||||
|
||||
editCount, err := database.EditDocument(articlesLocation, articleUpdate)
|
||||
if err != nil {
|
||||
api.SendBadRequest(c, fmt.Sprintf(`Could not edit document(s) from DB: %v`, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
if editCount != 0 {
|
||||
api.SendOk(c, fmt.Sprintf("%d article(s) was/were successfully edited!", editCount))
|
||||
} else {
|
||||
api.SendOk(c, "No articles were edited.")
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package articles
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/Floriansylvain/GohCMS/internal/api"
|
||||
"github.com/Floriansylvain/GohCMS/internal/database"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
func getApiFullUrl() string {
|
||||
return fmt.Sprintf("%v%v", os.Getenv("APP_API_ADDRESS"), os.Getenv("APP_BASE_API_PATH"))
|
||||
}
|
||||
|
||||
func getArticleSkipTakeFullUrl(skip uint64, take uint64) string {
|
||||
return fmt.Sprintf("%varticles?skip=%v&take=%v", getApiFullUrl(), skip+take, take)
|
||||
}
|
||||
|
||||
func getBuiltGetResponse(articles []Article, skip uint64, take uint64) map[string]any {
|
||||
articlesCap := uint64(len(articles))
|
||||
|
||||
var normTake uint64
|
||||
if skip+take > articlesCap {
|
||||
normTake = articlesCap
|
||||
} else {
|
||||
normTake = skip + take
|
||||
}
|
||||
|
||||
slicedArticles := articles[skip:normTake]
|
||||
total := len(slicedArticles)
|
||||
return map[string]any{
|
||||
"content": slicedArticles,
|
||||
"total": total,
|
||||
"pagination": map[string]any{
|
||||
"skip": skip,
|
||||
"take": take,
|
||||
"links": map[string]any{
|
||||
"next": getArticleSkipTakeFullUrl(skip+take, take),
|
||||
"previous": getArticleSkipTakeFullUrl(skip-take, take),
|
||||
},
|
||||
},
|
||||
"last_page": math.Ceil(float64(articlesCap) / float64(take)),
|
||||
}
|
||||
}
|
||||
|
||||
func parseUintQueryParam(c *gin.Context, param string, defaultValue uint64) (uint64, error) {
|
||||
if c.Query(param) == "" {
|
||||
return defaultValue, nil
|
||||
}
|
||||
value, err := strconv.ParseUint(c.Query(param), 10, 0)
|
||||
return value, err
|
||||
}
|
||||
|
||||
func getArticleIdFilter(titleID string) map[string]any {
|
||||
filter := map[string]any{}
|
||||
if titleID != "" {
|
||||
filter["titleID"] = titleID
|
||||
}
|
||||
return filter
|
||||
}
|
||||
|
||||
func Get(c *gin.Context) {
|
||||
skip, skipErr := parseUintQueryParam(c, "skip", 0)
|
||||
take, takeErr := parseUintQueryParam(c, "take", 10)
|
||||
if skipErr != nil || takeErr != nil {
|
||||
api.SendBadRequest(c, "Take and Skip query parameters must be positive numbers.")
|
||||
return
|
||||
}
|
||||
|
||||
documents, _ := database.GetDocuments(articlesLocation, map[string]any{})
|
||||
articlesArray := ParseArticlesFromBytesToArray(documents)
|
||||
articlesArrayLength := uint64(len(articlesArray))
|
||||
if skip >= articlesArrayLength || take == 0 {
|
||||
c.JSON(http.StatusOK, map[string]any{
|
||||
"content": []string{},
|
||||
"total": "0",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, getBuiltGetResponse(articlesArray, skip, take))
|
||||
}
|
||||
|
||||
func GetUnique(c *gin.Context) {
|
||||
titleID := c.Params.ByName("id")
|
||||
|
||||
article, err := database.GetUniqueDocument(articlesLocation, getArticleIdFilter(titleID))
|
||||
if err != nil {
|
||||
api.SendBadRequest(c, fmt.Sprintf("The ID '%v' doesn't match any article.", titleID))
|
||||
return
|
||||
}
|
||||
|
||||
var parsedArticle Article
|
||||
bson.Unmarshal(article, &parsedArticle)
|
||||
|
||||
c.JSON(http.StatusOK, parsedArticle)
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
type Location struct {
|
||||
Database string
|
||||
Collection string
|
||||
}
|
||||
|
||||
func GetNewClient() *mongo.Client {
|
||||
client, err := mongo.Connect(
|
||||
context.TODO(),
|
||||
options.Client().ApplyURI("mongodb://db:27017/"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func DeleteDocument(location Location, filter interface{}) (int64, error) {
|
||||
client := GetNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
result, err := collection.DeleteOne(context.TODO(), filter)
|
||||
if err != nil {
|
||||
return 0, errors.New("something is wrong with filter to delete the document.")
|
||||
}
|
||||
|
||||
return result.DeletedCount, nil
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type DocumentUpdate struct {
|
||||
Filter gin.H `json:"filter"`
|
||||
Update gin.H `json:"update"`
|
||||
}
|
||||
|
||||
func EditDocument(location Location, jsons DocumentUpdate) (int64, error) {
|
||||
client := GetNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
result, err := collection.UpdateOne(context.TODO(), jsons.Filter, gin.H{"$set": jsons.Update})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if result.MatchedCount == 0 {
|
||||
return 0, errors.New("cannot find document matching filter.")
|
||||
}
|
||||
|
||||
return result.ModifiedCount, nil
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func GetDocuments(location Location, filter interface{}) ([][]byte, error) {
|
||||
client := GetNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
var results [][]byte
|
||||
|
||||
cursor, err := collection.Find(context.TODO(), filter)
|
||||
if err != nil {
|
||||
return results, errors.New("something is wrong with filter to find the document.")
|
||||
}
|
||||
for cursor.TryNext(context.TODO()) {
|
||||
results = append(results, cursor.Current)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func GetUniqueDocument(location Location, filter interface{}) ([]byte, error) {
|
||||
client := GetNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
singleResult := collection.FindOne(context.TODO(), filter)
|
||||
if singleResult.Err() != nil {
|
||||
return nil, errors.New("no document was found, check the filter or the location.")
|
||||
}
|
||||
return singleResult.DecodeBytes()
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package database
|
||||
|
||||
import "context"
|
||||
|
||||
func PushDocument(location Location, document interface{}) error {
|
||||
client := GetNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
defer client.Disconnect(context.TODO())
|
||||
|
||||
_, err := collection.InsertOne(context.TODO(), document)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user