mirror of
https://github.com/Floriansylvain/RenewCMS.git
synced 2026-08-19 11:43:22 +02:00
@@ -1,11 +1,12 @@
|
||||
FROM node:latest as build-stage
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
COPY ./web/admin-gui/package*.json ./
|
||||
COPY ./.env ./
|
||||
RUN npm install
|
||||
COPY ./ .
|
||||
COPY ./web/admin-gui/ .
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx as production-stage
|
||||
RUN mkdir /app
|
||||
COPY --from=build-stage /app/dist /app
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
COPY ./web/admin-gui/nginx.conf /etc/nginx/nginx.conf
|
||||
@@ -12,7 +12,9 @@ docker-compose up
|
||||
TODO
|
||||
## Environment variables
|
||||
- ./env
|
||||
- API_PORT
|
||||
- FRONT_PORT
|
||||
- APP_HOST_ADDRESS
|
||||
- APP_API_PORT
|
||||
- APP_FRONT_PORT
|
||||
- APP_JWT_SECRET
|
||||
## Demo
|
||||
TODO
|
||||
+48
-10
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -8,30 +9,67 @@ import (
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
var ginMode = os.Getenv("APP_GIN_MODE")
|
||||
var apiPort = os.Getenv("APP_API_PORT")
|
||||
var frontPort = os.Getenv("APP_FRONT_PORT")
|
||||
var hostAddress = os.Getenv("APP_HOST_ADDRESS")
|
||||
|
||||
func initEnvVariables() {
|
||||
if godotenv.Load() != nil {
|
||||
panic("Error loading .env file.")
|
||||
}
|
||||
}
|
||||
|
||||
func initJWT() {
|
||||
errInit := internal.AuthMiddleware.MiddlewareInit()
|
||||
if errInit != nil {
|
||||
fmt.Printf(errInit.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func initBasicRoutes(r *gin.Engine) {
|
||||
r.POST("/login/", internal.AuthMiddleware.LoginHandler)
|
||||
r.GET("/ping/", internal.Ping)
|
||||
}
|
||||
|
||||
func corsMiddleware(c *gin.Context) {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", fmt.Sprintf("http://%v:%v", hostAddress, frontPort))
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(204)
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
|
||||
func initArticlesRoutes(r *gin.Engine) {
|
||||
articlesRouter := r.Group("/articles")
|
||||
articlesRouter.Use(corsMiddleware, internal.AuthMiddleware.MiddlewareFunc())
|
||||
|
||||
articlesRouter.GET("/", internal.GetAllArticlesHandler)
|
||||
articlesRouter.GET("/:id", internal.GetArticleHandler)
|
||||
articlesRouter.POST("/:id", internal.AddArticleHandler)
|
||||
articlesRouter.DELETE("/:id", internal.DeleteArticleHandler)
|
||||
}
|
||||
|
||||
func initGin() {
|
||||
r := gin.Default()
|
||||
r.SetTrustedProxies([]string{"localhost"})
|
||||
r.Use(corsMiddleware)
|
||||
|
||||
r.GET("/ping", internal.Ping)
|
||||
if ginMode == "release" {
|
||||
gin.SetMode(ginMode)
|
||||
}
|
||||
|
||||
r.GET("/articles/", internal.AuthCheck, internal.GetAllArticles)
|
||||
r.GET("/articles/:id", internal.AuthCheck, internal.GetArticle)
|
||||
r.POST("/articles/:id", internal.AuthCheck, internal.AddArticle)
|
||||
r.DELETE("/articles/:id", internal.AuthCheck, internal.DeleteArticle)
|
||||
initBasicRoutes(r)
|
||||
initArticlesRoutes(r)
|
||||
|
||||
r.POST("/login", internal.LoginUser)
|
||||
r.POST("/logout", internal.LogoutUser)
|
||||
|
||||
r.Run(":" + os.Getenv("API_PORT"))
|
||||
r.Run(":" + apiPort)
|
||||
}
|
||||
|
||||
func main() {
|
||||
initEnvVariables()
|
||||
initJWT()
|
||||
initGin()
|
||||
}
|
||||
|
||||
+8
-4
@@ -1,20 +1,24 @@
|
||||
services:
|
||||
backend:
|
||||
build: .
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: ./Dockerfile.backend
|
||||
image: gohcms-backend
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "${API_PORT}:8080"
|
||||
- "${APP_API_PORT}:${APP_API_PORT}"
|
||||
networks:
|
||||
- back-net
|
||||
frontend:
|
||||
build: web/admin-gui/.
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: ./Dockerfile.frontend
|
||||
image: gohcms-frontend
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "${FRONT_PORT}:80"
|
||||
- "${APP_FRONT_PORT}:80"
|
||||
networks:
|
||||
- front-net
|
||||
db:
|
||||
|
||||
@@ -2,37 +2,42 @@ module github.com/gotest
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/appleboy/gin-jwt/v2 v2.9.1
|
||||
github.com/gin-gonic/gin v1.8.1
|
||||
github.com/joho/godotenv v1.4.0
|
||||
go.mongodb.org/mongo-driver v1.11.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/gin-gonic/gin v1.8.1 // indirect
|
||||
github.com/go-playground/locales v0.14.0 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.10.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.11.1 // indirect
|
||||
github.com/go-sql-driver/mysql v1.6.0 // indirect
|
||||
github.com/goccy/go-json v0.9.7 // indirect
|
||||
github.com/golang/snappy v0.0.1 // indirect
|
||||
github.com/joho/godotenv v1.4.0 // indirect
|
||||
github.com/goccy/go-json v0.10.0 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/klauspost/compress v1.15.13 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.15 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 // indirect
|
||||
github.com/montanaflynn/stats v0.6.6 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.7 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.1 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.3 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||
go.mongodb.org/mongo-driver v1.10.3 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/net v0.4.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.3.0 // indirect
|
||||
golang.org/x/text v0.5.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
github.com/appleboy/gin-jwt/v2 v2.9.1 h1:l29et8iLW6omcHltsOP6LLk4s3v4g2FbFs0koxGWVZs=
|
||||
github.com/appleboy/gin-jwt/v2 v2.9.1/go.mod h1:jwcPZJ92uoC9nOUTOKWoN/f6JZOgMSKlFSHw5/FrRUk=
|
||||
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
|
||||
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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -12,13 +15,21 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
|
||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
|
||||
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
||||
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
|
||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
|
||||
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -28,6 +39,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0=
|
||||
github.com/klauspost/compress v1.15.13/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
@@ -38,16 +51,24 @@ github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/montanaflynn/stats v0.6.6 h1:Duep6KMIDpY4Yo11iFsvyqJDyfzLF9+sndUKT+v64GQ=
|
||||
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -55,11 +76,19 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
@@ -67,39 +96,84 @@ github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
|
||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA=
|
||||
go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8=
|
||||
go.mongodb.org/mongo-driver v1.11.1 h1:QP0znIRTuL0jf1oBQoAoM0C6ZJfBK4kx0Uumtv1A7w8=
|
||||
go.mongodb.org/mongo-driver v1.11.1/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
|
||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
type Article struct {
|
||||
Id_name string `json:"id_name" bson:"id_name"`
|
||||
Date int64 `json:"date" bson:"date"`
|
||||
Content interface{} `json:"content" bson:"content"`
|
||||
}
|
||||
|
||||
type DelArticle struct {
|
||||
Id_name string `json:"id_name" bson:"id_name"`
|
||||
}
|
||||
|
||||
var ARTICLES_LOCATION = Location{Database: "gohcms", Collection: "articles"}
|
||||
|
||||
// TODO Change to GetArticleList that will find filter json context
|
||||
func GetAllArticles(c *gin.Context) {
|
||||
var articles []Article
|
||||
documents, err := getDocuments(ARTICLES_LOCATION, bson.D{})
|
||||
if err != nil {
|
||||
SendBadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < len(documents); i++ {
|
||||
var newArticle Article
|
||||
bson.Unmarshal(documents[i], &newArticle)
|
||||
articles = append(articles, newArticle)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, articles)
|
||||
}
|
||||
|
||||
func GetArticle(c *gin.Context) {
|
||||
articleID := c.Params.ByName("id")
|
||||
articles, err := getDocuments(ARTICLES_LOCATION,
|
||||
bson.D{{Key: "id_name", Value: articleID}})
|
||||
if err != nil {
|
||||
SendBadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
if len(articles) == 0 {
|
||||
SendBadRequest(c, "The ID provided doesn't match any article.")
|
||||
return
|
||||
}
|
||||
var parsedArticle Article
|
||||
bson.Unmarshal(articles[0], &parsedArticle)
|
||||
c.JSON(http.StatusOK, parsedArticle)
|
||||
}
|
||||
|
||||
func IsArticleIdAlreadyUsed(id string) bool {
|
||||
documents, _ := getDocuments(ARTICLES_LOCATION, bson.D{})
|
||||
for i := 0; i < len(documents); i++ {
|
||||
var newArticle Article
|
||||
bson.Unmarshal(documents[i], &newArticle)
|
||||
if newArticle.Id_name == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func AddArticle(c *gin.Context) {
|
||||
var article Article
|
||||
article.Id_name = c.Params.ByName("id")
|
||||
if c.BindJSON(&article) != nil {
|
||||
SendBadRequest(c, "Could not correctly parse the article.")
|
||||
return
|
||||
}
|
||||
|
||||
document, err := bson.Marshal(article)
|
||||
if err != nil {
|
||||
SendBadRequest(c, "Could not correctly marshal the article.")
|
||||
return
|
||||
}
|
||||
|
||||
if IsArticleIdAlreadyUsed(article.Id_name) {
|
||||
SendBadRequest(c, "Article ID already used.")
|
||||
return
|
||||
}
|
||||
|
||||
err = pushDocument(ARTICLES_LOCATION, document)
|
||||
if err != nil {
|
||||
SendBadRequest(c, "Could not insert document into DB.")
|
||||
return
|
||||
}
|
||||
|
||||
SendOk(c, "Article successfully added!")
|
||||
}
|
||||
|
||||
func DeleteArticle(c *gin.Context) {
|
||||
var delArticle DelArticle
|
||||
delArticle.Id_name = c.Params.ByName("id")
|
||||
if c.BindJSON(&delArticle) != nil {
|
||||
SendBadRequest(c, "Could not correctly parse the article ID.")
|
||||
return
|
||||
}
|
||||
|
||||
document, err := bson.Marshal(delArticle)
|
||||
if err != nil {
|
||||
SendBadRequest(c, "Could not correctly marshal the article ID.")
|
||||
return
|
||||
}
|
||||
|
||||
deleteCount, err := deleteDocument(ARTICLES_LOCATION, document)
|
||||
if err != nil {
|
||||
SendBadRequest(c, "Could not insert document into DB.")
|
||||
return
|
||||
}
|
||||
|
||||
SendOk(c, fmt.Sprintf("%d articles were successfully deleted!", deleteCount))
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
type Article struct {
|
||||
IdName string `json:"id_name" bson:"id_name"`
|
||||
Date int64 `json:"date" bson:"date"`
|
||||
Content interface{} `json:"content" bson:"content"`
|
||||
}
|
||||
|
||||
type DelArticle struct {
|
||||
IdName string `json:"id_name" bson:"id_name"`
|
||||
}
|
||||
|
||||
var articlesLocation = Location{Database: "gohcms", Collection: "articles"}
|
||||
|
||||
func GetAllArticlesBusiness(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.IdName == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
func GetAllArticlesHandler(c *gin.Context) {
|
||||
documents, err := getDocuments(articlesLocation, bson.D{})
|
||||
if err != nil {
|
||||
SendBadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, GetAllArticlesBusiness(documents))
|
||||
}
|
||||
|
||||
func GetArticleHandler(c *gin.Context) {
|
||||
articleID := c.Params.ByName("id")
|
||||
article, err := getUniqueDocument(articlesLocation,
|
||||
bson.D{{Key: "id_name", Value: articleID}})
|
||||
if err != nil {
|
||||
SendBadRequest(c, "The ID provided doesn't match any article.")
|
||||
return
|
||||
}
|
||||
var parsedArticle Article
|
||||
bson.Unmarshal(article, &parsedArticle)
|
||||
c.JSON(http.StatusOK, parsedArticle)
|
||||
}
|
||||
|
||||
func AddArticleHandler(c *gin.Context) {
|
||||
var article Article
|
||||
article.IdName = c.Params.ByName("id")
|
||||
if c.BindJSON(&article) != nil {
|
||||
SendBadRequest(c, "Could not correctly parse the article.")
|
||||
return
|
||||
}
|
||||
|
||||
document, err := bson.Marshal(article)
|
||||
if err != nil {
|
||||
SendBadRequest(c, "Could not correctly marshal the article.")
|
||||
return
|
||||
}
|
||||
|
||||
documents, _ := getDocuments(articlesLocation, gin.H{})
|
||||
if IsArticleIdAlreadyUsed(article.IdName, documents) {
|
||||
SendBadRequest(c, "Article ID already used.")
|
||||
return
|
||||
}
|
||||
|
||||
err = pushDocument(articlesLocation, document)
|
||||
if err != nil {
|
||||
SendBadRequest(c, fmt.Sprintf(`Could not insert document into DB: %v`, err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
SendOk(c, "Article successfully added!")
|
||||
}
|
||||
|
||||
func DeleteArticleHandler(c *gin.Context) {
|
||||
var delArticle DelArticle
|
||||
delArticle.IdName = c.Params.ByName("id")
|
||||
if c.BindJSON(&delArticle) != nil {
|
||||
SendBadRequest(c, "Could not correctly parse the article ID.")
|
||||
return
|
||||
}
|
||||
|
||||
document, err := bson.Marshal(delArticle)
|
||||
if err != nil {
|
||||
SendBadRequest(c, "Could not correctly marshal the article ID.")
|
||||
return
|
||||
}
|
||||
|
||||
deleteCount, err := deleteDocument(articlesLocation, document)
|
||||
if err != nil {
|
||||
SendBadRequest(c, "Could not insert document into DB.")
|
||||
return
|
||||
}
|
||||
|
||||
SendOk(c, fmt.Sprintf("%d articles were successfully deleted!", deleteCount))
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
var Article1, _ = bson.Marshal(Article{
|
||||
IdName: "test_article_1",
|
||||
Date: 1671482492,
|
||||
Content: gin.H{},
|
||||
})
|
||||
|
||||
var Article2, _ = bson.Marshal(Article{
|
||||
IdName: "test_article_2",
|
||||
Date: 1671899112,
|
||||
Content: gin.H{},
|
||||
})
|
||||
|
||||
var BSONConvertedArticles = [][]byte{Article1, Article2}
|
||||
|
||||
func TestGetAllArticlesBusiness(t *testing.T) {
|
||||
documents := GetAllArticlesBusiness(BSONConvertedArticles)
|
||||
article := documents[0]
|
||||
|
||||
if article.IdName != "test_article_1" {
|
||||
log.Fatalf(`Excepted "test_article_1" as IdName, found "%v"`, article.IdName)
|
||||
} 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`)
|
||||
}
|
||||
}
|
||||
+23
-83
@@ -1,11 +1,13 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
jwt "github.com/appleboy/gin-jwt/v2"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
@@ -13,92 +15,30 @@ type User struct {
|
||||
Password string `json:"password" bson:"password"`
|
||||
}
|
||||
|
||||
var USERS_LOCATION = Location{Database: "gohcms", Collection: "users"}
|
||||
var UsersLocation = Location{Database: "gohcms", Collection: "users"}
|
||||
|
||||
func getUserHashedPassword(user User) string {
|
||||
password := sha256.New()
|
||||
password.Write([]byte(user.Password))
|
||||
return fmt.Sprintf("%x", password.Sum(nil))
|
||||
}
|
||||
var AuthMiddleware, _ = jwt.New(&jwt.GinJWTMiddleware{
|
||||
Realm: "GohCMS",
|
||||
Key: []byte(os.Getenv("APP_JWT_SECRET")),
|
||||
Timeout: time.Hour,
|
||||
MaxRefresh: time.Hour,
|
||||
Authenticator: JWTAuthenticator,
|
||||
})
|
||||
|
||||
func isUserLoggedIn(user User) bool {
|
||||
for i := 0; i < len(SESSIONS); i++ {
|
||||
hash1 := fmt.Sprint(SESSIONS[i].Token.Sum(nil))
|
||||
hash2 := fmt.Sprint(generateSessionToken(user).Sum(nil))
|
||||
if hash1 != hash2 {
|
||||
continue
|
||||
}
|
||||
sessionExpired := isSessionExpired(SESSIONS[i])
|
||||
if sessionExpired {
|
||||
removeSession(user)
|
||||
}
|
||||
return !sessionExpired
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isUserReal(user User) bool {
|
||||
docUsers, _ := getDocuments(USERS_LOCATION, user)
|
||||
return len(docUsers) == 1
|
||||
}
|
||||
|
||||
func parseUserFromContext(c *gin.Context) (User, error) {
|
||||
var user User
|
||||
if c.BindJSON(&user) != nil {
|
||||
return User{}, errors.New("could not correctly parse user crendentials")
|
||||
}
|
||||
user.Password = getUserHashedPassword(user)
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func LoginUser(c *gin.Context) {
|
||||
user, err := parseUserFromContext(c)
|
||||
func JWTAuthenticator(c *gin.Context) (interface{}, error) {
|
||||
var user = User{}
|
||||
err := c.BindJSON(&user)
|
||||
if err != nil {
|
||||
SendBadRequest(c, err.Error())
|
||||
return
|
||||
return nil, errors.New("wrong credentials json format.")
|
||||
}
|
||||
if isUserLoggedIn(user) {
|
||||
SendBadRequest(c, "User is already logged in!")
|
||||
return
|
||||
}
|
||||
if !isUserReal(user) {
|
||||
SendBadRequest(c, "Unknown email or wrong password.")
|
||||
return
|
||||
}
|
||||
addSession(user)
|
||||
SendOk(c, "User successfully logged in.")
|
||||
}
|
||||
|
||||
func LogoutUser(c *gin.Context) {
|
||||
user, err := parseUserFromContext(c)
|
||||
_, err = getUniqueDocument(UsersLocation, bson.D{
|
||||
{Key: "email", Value: user.Email},
|
||||
{Key: "password", Value: user.Password},
|
||||
})
|
||||
if err != nil {
|
||||
SendBadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
if !isUserLoggedIn(user) {
|
||||
SendBadRequest(c, "User is not logged in!")
|
||||
return
|
||||
}
|
||||
removeSession(user)
|
||||
SendOk(c, "User successfully logged out.")
|
||||
}
|
||||
|
||||
func AuthCheck(c *gin.Context) {
|
||||
var user User
|
||||
username, password, isOk := c.Request.BasicAuth()
|
||||
if !isOk {
|
||||
SendBadRequest(c, "Incorrect or missing user credentials.")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
user.Email = username
|
||||
user.Password = password
|
||||
user.Password = getUserHashedPassword(user)
|
||||
|
||||
if !isUserLoggedIn(user) {
|
||||
SendForbidden(c, "Authentification failed, credentials could be wrong, user may not be logged in, session may have expired.")
|
||||
c.Abort()
|
||||
return
|
||||
return nil, errors.New("wrong email or password.")
|
||||
}
|
||||
|
||||
return gin.H{"email": user.Email}, nil
|
||||
}
|
||||
|
||||
@@ -52,6 +52,18 @@ func getDocuments(location Location, filter interface{}) ([][]byte, error) {
|
||||
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()
|
||||
}
|
||||
|
||||
func deleteDocument(location Location, filter interface{}) (int64, error) {
|
||||
client := getNewClient()
|
||||
collection := client.Database(location.Database).Collection(location.Collection)
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"fmt"
|
||||
"hash"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
Token hash.Hash `json:"token"`
|
||||
ExpirationTimestamp int64 `json:"expirationTimestamp"`
|
||||
}
|
||||
|
||||
var SESSIONS []Session
|
||||
|
||||
const SESSION_DURATION int64 = 3600
|
||||
|
||||
func generateSessionToken(user User) hash.Hash {
|
||||
token := crypto.SHA256.New()
|
||||
stringToHash := fmt.Sprintf(user.Email + user.Password)
|
||||
token.Write([]byte(stringToHash))
|
||||
return token
|
||||
}
|
||||
|
||||
func isSessionExpired(session Session) bool {
|
||||
return session.ExpirationTimestamp < time.Now().Unix()
|
||||
}
|
||||
|
||||
func addSession(user User) {
|
||||
SESSIONS = append(SESSIONS, Session{
|
||||
Token: generateSessionToken(user),
|
||||
ExpirationTimestamp: time.Now().Unix() + SESSION_DURATION,
|
||||
})
|
||||
}
|
||||
|
||||
func removeSession(user User) {
|
||||
index := 0
|
||||
sessLen := len(SESSIONS)
|
||||
for i := 0; i < sessLen; i++ {
|
||||
if SESSIONS[i].Token == generateSessionToken(user) {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
SESSIONS[index] = SESSIONS[sessLen-1]
|
||||
SESSIONS[sessLen-1] = Session{}
|
||||
SESSIONS = SESSIONS[:sessLen-1]
|
||||
}
|
||||
@@ -42,3 +42,8 @@ db.createCollection('users', {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
db.users.insertOne({
|
||||
email: "root",
|
||||
password: "root"
|
||||
})
|
||||
Vendored
+1
@@ -1 +1,2 @@
|
||||
/// <reference types="vite/client" />
|
||||
declare const __APP_ENV__: Record<string, string>
|
||||
Generated
+565
-509
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
"type-check": "vue-tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"pinia": "^2.0.21",
|
||||
"pinia": "^2.0.28",
|
||||
"vue": "^3.2.38",
|
||||
"vue-editor-js": "^2.0.2",
|
||||
"vue-router": "^4.1.5"
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router'
|
||||
import { RouterView, useRoute } from 'vue-router'
|
||||
import Navbar from './components/Navbar.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Navbar v-if="useRoute().name !== 'login'"></Navbar>
|
||||
<RouterView />
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Frank+Ruhl+Libre:wght@500&family=Hind:wght@400;500;600;700&family=Nunito:wght@500;600;700&display=swap');
|
||||
|
||||
:root {
|
||||
--regular-weight: 400;
|
||||
--medium-weight: 500;
|
||||
--semibold-weight: 600;
|
||||
--bold-weight: 700;
|
||||
|
||||
--radius: 15px;
|
||||
|
||||
--font-body: 16px;
|
||||
--font-small: 14px;
|
||||
--font-verysmall: 12px;
|
||||
|
||||
--primary: #2CD358;
|
||||
--primary-dark: #00BA2A;
|
||||
--primary-light: #97E6A2;
|
||||
--secondary: #D32CA6;
|
||||
--secondary-dark: #BA0094;
|
||||
--secondary-light: #E88DCA;
|
||||
--neutral-dark: #121212;
|
||||
--neutral-medium: #707070;
|
||||
--neutral-light: #aaaaaa;
|
||||
--neutral-verylight: #e7e7e7;
|
||||
--brand-blue: #00ACD7;
|
||||
--error: #E80000;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: 'Frank Ruhl Libre', serif;
|
||||
font-size: 40px;
|
||||
}
|
||||
h2 { font-size: 32px; }
|
||||
h3 { font-size: 24px; }
|
||||
h4 { font-size: 18px; }
|
||||
h2, h3, h4, h5, h6 {
|
||||
font-family: 'Nunito', sans-serif;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Hind', sans-serif;
|
||||
color: var(--neutral-dark);
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.label-input,
|
||||
.label-input-error {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.label-input label,
|
||||
.label-input-error label {
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--semibold-weight);
|
||||
}
|
||||
|
||||
.label-input p,
|
||||
.label-input-error p {
|
||||
color: var(--neutral-medium);
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--medium-weight);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.label-input input,
|
||||
.label-input-error input {
|
||||
padding: 3px 16px;
|
||||
font-size: var(--font-body);
|
||||
|
||||
border: solid 1.25px var(--neutral-light);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.label-input-error input {
|
||||
border: solid 1.75px var(--error);
|
||||
}
|
||||
|
||||
.label-input-error p {
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.button-primary,
|
||||
.button-disabled {
|
||||
border-radius: var(--radius);
|
||||
border: none;
|
||||
|
||||
padding: 3px 16px;
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--medium-weight);
|
||||
|
||||
background-color: var(--primary);
|
||||
|
||||
transition: background-color 150ms;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button-primary:hover {
|
||||
background-color: var(--primary-light);
|
||||
}
|
||||
|
||||
.button-primary:active {
|
||||
background-color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.button-disabled {
|
||||
color: var(--neutral-dark);
|
||||
background-color: var(--neutral-light);
|
||||
cursor: default;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<script setup lang="ts">
|
||||
import { useAuthStore } from '@/stores/AuthStore';
|
||||
import { deleteCookie } from '@/utils/cookies';
|
||||
import { RouterLink, useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
function logout() {
|
||||
deleteCookie('JWTtoken')
|
||||
deleteCookie('JWTexpire')
|
||||
useAuthStore().clearAll()
|
||||
router.push('/')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<header>
|
||||
<h2><span style="color:var(--brand-blue)">Go</span>hCMS</h2>
|
||||
<nav>
|
||||
<RouterLink to="/home">Accueil</RouterLink>
|
||||
<RouterLink to="/articles">Articles</RouterLink>
|
||||
<a class="disconnect-link" @click="logout()">Se déconnecter</a>
|
||||
</nav>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 24px;
|
||||
|
||||
box-shadow: #0005 0 0 10px;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
header h2 {
|
||||
margin: 0;
|
||||
padding: 10px 0;
|
||||
|
||||
width: fit-content;
|
||||
|
||||
color: var(--neutral-dark);
|
||||
}
|
||||
|
||||
header h2 span {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
header nav {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
header nav a {
|
||||
text-decoration: none;
|
||||
border-radius: var(--radius);
|
||||
padding: 4px 16px;
|
||||
cursor: pointer;
|
||||
transition: 150ms background-color;
|
||||
}
|
||||
|
||||
header nav a:hover {
|
||||
background-color: var(--neutral-verylight);
|
||||
}
|
||||
|
||||
.disconnect-link {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.disconnect-link:hover {
|
||||
background-color: #fff;
|
||||
color: var(--error);
|
||||
}
|
||||
</style>
|
||||
@@ -1,11 +1,10 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
import './assets/main.css'
|
||||
import '@/assets/base.css'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
|
||||
@@ -1,15 +1,68 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import { createRouter, createWebHistory, type NavigationGuard } from 'vue-router'
|
||||
import { useAuthStore } from '@/stores/AuthStore'
|
||||
import { nextTick } from 'vue'
|
||||
import Debug from '@/views/Debug.vue'
|
||||
import Login from '@/views/Login.vue'
|
||||
import Home from '@/views/Home.vue'
|
||||
import Articles from '@/views/Articles.vue'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'login',
|
||||
component: Login,
|
||||
meta: {
|
||||
title: 'GohCMS - Connexion'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/debug',
|
||||
name: 'debug',
|
||||
component: Debug,
|
||||
meta: {
|
||||
title: 'GohCMS - Debug'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/home',
|
||||
name: 'home',
|
||||
component: Home
|
||||
component: Home,
|
||||
meta: {
|
||||
title: 'GohCMS - Accueil'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/articles',
|
||||
name: 'articles',
|
||||
component: Articles,
|
||||
meta: {
|
||||
title: 'GohCMS - Articles'
|
||||
}
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
router.beforeEach(async (to, from) => {
|
||||
const isTokenValid = useAuthStore().isValid()
|
||||
if (to.name === 'login') {
|
||||
if (isTokenValid) return {
|
||||
name: 'home'
|
||||
}
|
||||
} else {
|
||||
if (!isTokenValid) {
|
||||
return {
|
||||
name: 'login',
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
router.afterEach((to, from) => {
|
||||
nextTick(() => {
|
||||
document.title = to.meta.title as string ?? 'GohCMS'
|
||||
})
|
||||
})
|
||||
|
||||
export default router
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { getCookie } from "@/utils/cookies";
|
||||
import { defineStore } from "pinia";
|
||||
import { ref } from "vue";
|
||||
import { useErrorsStore } from "./ErrorsStore";
|
||||
|
||||
export interface jwtFormat {
|
||||
code: number,
|
||||
expire: string,
|
||||
token: string
|
||||
}
|
||||
|
||||
export const useAuthStore = defineStore("AuthStore", () => {
|
||||
const expire = ref('')
|
||||
const token = ref('')
|
||||
|
||||
function clearAll(): void {
|
||||
expire.value = ''
|
||||
token.value = ''
|
||||
}
|
||||
|
||||
function isSet(): boolean {
|
||||
return token.value !== undefined && token.value !== ''
|
||||
}
|
||||
|
||||
function isExpired(): boolean {
|
||||
const tokenDate = new Date(expire.value)
|
||||
const currentDate = new Date()
|
||||
|
||||
if (currentDate.getTime() > tokenDate.getTime()) {
|
||||
useErrorsStore().sessionExpired = true
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function isValid(): boolean {
|
||||
return isSet() && !isExpired()
|
||||
}
|
||||
|
||||
function initStore(): void {
|
||||
const JWTtoken = getCookie('JWTtoken')
|
||||
const JWTexpire = getCookie('JWTexpire')
|
||||
if (JWTtoken !== "" && JWTexpire !== "") {
|
||||
token.value = JWTtoken
|
||||
expire.value = JWTexpire
|
||||
}
|
||||
}
|
||||
|
||||
initStore()
|
||||
|
||||
return { expire, token, isValid, clearAll }
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { ref, type Ref } from "vue";
|
||||
|
||||
interface storeErrors {
|
||||
sessionExpired: boolean
|
||||
}
|
||||
|
||||
export const useErrorsStore = defineStore("ErrorsStore", () => {
|
||||
const errors: Ref<storeErrors> = ref({
|
||||
sessionExpired: false
|
||||
})
|
||||
|
||||
return errors
|
||||
})
|
||||
@@ -0,0 +1,21 @@
|
||||
export interface cookie {
|
||||
key: string,
|
||||
value: string,
|
||||
expire: string
|
||||
}
|
||||
|
||||
export function setCookie(cookieData: cookie): void {
|
||||
document.cookie = `${cookieData.key}=${cookieData.value}; SameSite=Strict; Expires=${cookieData.expire};Secure`
|
||||
}
|
||||
|
||||
export function getCookie(cookieName: string): string {
|
||||
return document.cookie.match('(^|;)\\s*' + cookieName + '\\s*=\\s*([^;]+)')?.pop() || ''
|
||||
}
|
||||
|
||||
export function deleteCookie(cookieName: string): void {
|
||||
setCookie({
|
||||
key: cookieName,
|
||||
value: '',
|
||||
expire: new Date(0).toString()
|
||||
})
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export interface Pong {
|
||||
message: string;
|
||||
}
|
||||
|
||||
export async function pingApi(): Promise<String> {
|
||||
let result: String = ''
|
||||
await fetch('http://localhost:8080/ping')
|
||||
.then(response => response.json())
|
||||
.then(jsonResponse => result = jsonResponse.message)
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p>articles page</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,71 @@
|
||||
<script setup lang="ts">
|
||||
// import EditorJS from '@editorjs/editorjs';
|
||||
import { useAuthStore, type jwtFormat } from '@/stores/AuthStore';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
|
||||
const baseURL = `http://${__APP_ENV__.APP_HOST_ADDRESS}:${__APP_ENV__.APP_API_PORT}`
|
||||
|
||||
function getArticles() {
|
||||
fetch(`${baseURL}/articles/`, {
|
||||
headers: { "Authorization": `Bearer ${useAuthStore().token}` }
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => console.log(result))
|
||||
}
|
||||
|
||||
function ping() {
|
||||
fetch(`${baseURL}/ping/`, {
|
||||
headers: { "Authorization": `Bearer ${useAuthStore().token}` }
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => console.log(result))
|
||||
}
|
||||
|
||||
function jwtHandler(apiResponse: jwtFormat): void {
|
||||
if (apiResponse.code !== 200) {
|
||||
console.log(apiResponse)
|
||||
return
|
||||
}
|
||||
useAuthStore().token = apiResponse.token
|
||||
useAuthStore().expire = apiResponse.expire
|
||||
console.log('success! logged in.')
|
||||
}
|
||||
|
||||
function login(email: string, password: string): void {
|
||||
fetch(`${baseURL}/login/`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
password: password
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => jwtHandler(result))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<h2>Connexion</h2>
|
||||
|
||||
<form @submit.prevent="login(email, password)">
|
||||
<div>
|
||||
<label for="email">Email address</label>
|
||||
<input id="email" name="email" placeholder="email" type="text" v-model="email">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password">Password</label>
|
||||
<input id="password" name="password" placeholder="password" type="password" v-model="password">
|
||||
</div>
|
||||
<button type="submit">Se connecter</button>
|
||||
</form>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<button class="button-primary" @click="getArticles()">get all articles</button>
|
||||
<button class="button-primary" @click="ping()">ping</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,77 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
// import EditorJS from '@editorjs/editorjs';
|
||||
import { pingApi } from '@/utils/ping';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
const inputArticleID = ref('')
|
||||
const username = ref('')
|
||||
const password = ref('')
|
||||
|
||||
onMounted(async function() {
|
||||
console.log('ping...')
|
||||
const pong = await pingApi()
|
||||
console.log(pong)
|
||||
})
|
||||
|
||||
function addArticle() {
|
||||
fetch(`http://localhost:8080/articles/${Math.random() * 100}`, {
|
||||
method: "POST",
|
||||
headers: {"Authorization" : `Basic ${btoa(`${username.value}:${password.value}`)}`},
|
||||
body: JSON.stringify({
|
||||
content: {},
|
||||
date: new Date().getTime()
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => console.log(result))
|
||||
}
|
||||
|
||||
function deleteArticle(articleID: String) {
|
||||
fetch(`http://localhost:8080/articles/${articleID}`, {
|
||||
method: "DELETE",
|
||||
headers: {"Authorization" : `Basic ${btoa(`${username.value}:${password.value}`)}`},
|
||||
body: JSON.stringify({
|
||||
id_name: articleID
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => console.log(result))
|
||||
}
|
||||
|
||||
function getArticle(articleID: String) {
|
||||
fetch(`http://localhost:8080/articles/${articleID}`, {
|
||||
headers: {"Authorization" : `Basic ${btoa(`${username.value}:${password.value}`)}`},
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => console.log(result))
|
||||
}
|
||||
|
||||
function auth(type: string, username: string, password: string) {
|
||||
fetch(`http://localhost:8080/${type}`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
email: username,
|
||||
password: password
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => console.log(result))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p>Salut à tous</p>
|
||||
<button @click="addArticle">add rand article</button>
|
||||
<button @click="getArticle('')">display articles in console</button> <br>
|
||||
<label for="articleIDinput"></label>
|
||||
<input id="articleIDinput" name="articleIDinput" type="text" placeholder="article ID" v-model="inputArticleID">
|
||||
<button @click="deleteArticle(inputArticleID)">delete this article</button>
|
||||
<button @click="getArticle(inputArticleID)">get this article</button> <br>
|
||||
|
||||
<input type="text" name="username" id="username" v-model="username" placeholder="username">
|
||||
<input type="text" name="password" id="password" v-model="password" placeholder="password">
|
||||
<button @click="auth('login', username, password)">login</button>
|
||||
<button @click="auth('logout', username, password)">logout</button>
|
||||
<p>home page</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
<script setup lang="ts">
|
||||
import { useAuthStore, type jwtFormat } from '@/stores/AuthStore';
|
||||
import { useErrorsStore } from '@/stores/ErrorsStore';
|
||||
import { setCookie } from '@/utils/cookies';
|
||||
import { ref, type Ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const isTokenOK: Ref<boolean|undefined> = ref(undefined)
|
||||
const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
|
||||
const isFormEmpty: ()=>boolean = () => {
|
||||
return email.value === '' || password.value === ''
|
||||
}
|
||||
|
||||
function updateJWTcookies(JWTdata: jwtFormat): void {
|
||||
const cookieExpire = new Date(JWTdata.expire)
|
||||
cookieExpire.setDate(cookieExpire.getDate() + 1)
|
||||
|
||||
setCookie({
|
||||
key: 'JWTtoken',
|
||||
value: JWTdata.token,
|
||||
expire: cookieExpire.toString()
|
||||
})
|
||||
setCookie({
|
||||
key: 'JWTexpire',
|
||||
value: JWTdata.expire,
|
||||
expire: cookieExpire.toString()
|
||||
})
|
||||
}
|
||||
|
||||
function disableErrors(): void {
|
||||
useErrorsStore().sessionExpired = false
|
||||
}
|
||||
|
||||
function jwtHandler(apiResponse: jwtFormat): void {
|
||||
if (apiResponse.code !== 200) {
|
||||
console.error(apiResponse)
|
||||
isTokenOK.value = false
|
||||
return
|
||||
}
|
||||
updateJWTcookies(apiResponse)
|
||||
disableErrors()
|
||||
authStore.token = apiResponse.token
|
||||
authStore.expire = apiResponse.expire
|
||||
isTokenOK.value = true
|
||||
}
|
||||
|
||||
function login(email: string, password: string): void {
|
||||
fetch(`http://${__APP_ENV__.APP_HOST_ADDRESS}:${__APP_ENV__.APP_API_PORT}/login/`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
password: password
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
jwtHandler(result)
|
||||
if (isTokenOK.value === true) {
|
||||
router.push('/home')
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="login-page">
|
||||
<div class="login-form">
|
||||
<h2>Connexion à <span style="color:var(--brand-blue)">Go</span>hCMS</h2>
|
||||
|
||||
<form @submit.prevent="login(email, password)">
|
||||
<div class="inputs-group">
|
||||
<div :class="`label-input${isTokenOK === false ? '-error' : ''}`">
|
||||
<label for="email">Adresse mail</label>
|
||||
<input id="email" name="email" placeholder="E-mail" type="text" v-model="email">
|
||||
</div>
|
||||
<div :class="`label-input${isTokenOK === false ? '-error' : ''}`">
|
||||
<label for="password">Mot de passe</label>
|
||||
<input id="password" name="password" placeholder="Mot de passe" type="password" v-model="password">
|
||||
<p v-if="isTokenOK === false">❌ E-mail et/ou mot de passe incorrect(s).</p>
|
||||
<p v-else-if="useErrorsStore().sessionExpired">⌛ Votre session a expiré.</p>
|
||||
</div>
|
||||
</div>
|
||||
<button :class="`button-${isFormEmpty() ? 'disabled' : 'primary'}`" type="submit" :disabled="isFormEmpty()">
|
||||
Se connecter
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
h2 {
|
||||
margin: 0 0 16px 0;
|
||||
}
|
||||
|
||||
h2 span {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.login-page {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
.inputs-group,
|
||||
.login-form form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.login-form form {
|
||||
gap: 32px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,14 +1,27 @@
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
export default defineConfig(({ command, mode }) => {
|
||||
const env1 = loadEnv(mode, "./../../", "")
|
||||
const env2 = loadEnv(mode, process.cwd(), "")
|
||||
|
||||
return {
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
},
|
||||
define: {
|
||||
__APP_ENV__: {
|
||||
...env1,
|
||||
...env2,
|
||||
}
|
||||
},
|
||||
server: {
|
||||
port: env1.APP_FRONT_PORT,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user