Compare commits
7 Commits
bbefe7d28a
...
33a41ad066
| Author | SHA1 | Date | |
|---|---|---|---|
| 33a41ad066 | |||
| 8d6225f136 | |||
|
|
18b3e318ab | ||
|
|
482e8571af | ||
|
|
51f8a125e9 | ||
|
|
a96ef069cc | ||
|
|
ea8fa90a31 |
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: test build clean lint dev run-docker docs-upd docker
|
.PHONY: test build clean lint dev run-docker docs-upd docker docker-run
|
||||||
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@@ -29,6 +29,9 @@ docker:
|
|||||||
swag init -g ./cmd/main.go --parseDependency --parseInternal
|
swag init -g ./cmd/main.go --parseDependency --parseInternal
|
||||||
docker build -t backend .
|
docker build -t backend .
|
||||||
|
|
||||||
|
docker-run:
|
||||||
|
docker run --rm -p 8080:8080 --env-file .env -v /opt/d3m0k1d.ru/data:/data backend:latest
|
||||||
|
|
||||||
run-docker:
|
run-docker:
|
||||||
docker build -t backend .
|
docker build -t backend .
|
||||||
docker run --rm -p 8080:8080 --env-file .env backend:latest
|
docker run --rm -p 8080:8080 --env-file .env backend:latest
|
||||||
|
|||||||
@@ -412,6 +412,88 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/upload": {
|
||||||
|
"post": {
|
||||||
|
"description": "Upload static content to the server",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"static"
|
||||||
|
],
|
||||||
|
"summary": "Upload static content",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.SuccessResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal server error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.ErrorResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/upload/{file}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get static content",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"static"
|
||||||
|
],
|
||||||
|
"summary": "Get static content",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "File name",
|
||||||
|
"name": "file",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Static content",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.SuccessResponse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "File not found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.ErrorResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal server error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.ErrorResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
@@ -455,6 +537,9 @@ const docTemplate = `{
|
|||||||
"id": {
|
"id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"published": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
@@ -466,6 +551,9 @@ const docTemplate = `{
|
|||||||
"content": {
|
"content": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"published": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -401,6 +401,88 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/upload": {
|
||||||
|
"post": {
|
||||||
|
"description": "Upload static content to the server",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"static"
|
||||||
|
],
|
||||||
|
"summary": "Upload static content",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.SuccessResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal server error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.ErrorResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/upload/{file}": {
|
||||||
|
"get": {
|
||||||
|
"description": "Get static content",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"static"
|
||||||
|
],
|
||||||
|
"summary": "Get static content",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "File name",
|
||||||
|
"name": "file",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Static content",
|
||||||
|
"schema": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.SuccessResponse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"data": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "File not found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.ErrorResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"500": {
|
||||||
|
"description": "Internal server error",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.ErrorResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
@@ -444,6 +526,9 @@
|
|||||||
"id": {
|
"id": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"published": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
@@ -455,6 +540,9 @@
|
|||||||
"content": {
|
"content": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"published": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
id:
|
id:
|
||||||
type: integer
|
type: integer
|
||||||
|
published:
|
||||||
|
type: boolean
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
@@ -32,6 +34,8 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
content:
|
content:
|
||||||
type: string
|
type: string
|
||||||
|
published:
|
||||||
|
type: boolean
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
@@ -292,6 +296,57 @@ paths:
|
|||||||
summary: Get user session
|
summary: Get user session
|
||||||
tags:
|
tags:
|
||||||
- auth
|
- auth
|
||||||
|
/upload:
|
||||||
|
post:
|
||||||
|
description: Upload static content to the server
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.SuccessResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal server error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.ErrorResponse'
|
||||||
|
summary: Upload static content
|
||||||
|
tags:
|
||||||
|
- static
|
||||||
|
/upload/{file}:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Get static content
|
||||||
|
parameters:
|
||||||
|
- description: File name
|
||||||
|
in: path
|
||||||
|
name: file
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Static content
|
||||||
|
schema:
|
||||||
|
allOf:
|
||||||
|
- $ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.SuccessResponse'
|
||||||
|
- properties:
|
||||||
|
data:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
"404":
|
||||||
|
description: File not found
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.ErrorResponse'
|
||||||
|
"500":
|
||||||
|
description: Internal server error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/gitea_d3m0k1d_ru_d3m0k1d_d3m0k1d_ru_backend_internal_models.ErrorResponse'
|
||||||
|
summary: Get static content
|
||||||
|
tags:
|
||||||
|
- static
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
Bearer:
|
Bearer:
|
||||||
description: Type "Bearer" followed by a space and the JWT token.
|
description: Type "Bearer" followed by a space and the JWT token.
|
||||||
|
|||||||
@@ -11,8 +11,12 @@ import (
|
|||||||
func Register(router *gin.Engine, db *sql.DB) {
|
func Register(router *gin.Engine, db *sql.DB) {
|
||||||
handler_posts := NewPostHandlers(repositories.NewPostRepository(db))
|
handler_posts := NewPostHandlers(repositories.NewPostRepository(db))
|
||||||
handler_auth := NewAuthHandlers(repositories.NewAuthRepository(db))
|
handler_auth := NewAuthHandlers(repositories.NewAuthRepository(db))
|
||||||
|
handler_static := NewStaticHandlers()
|
||||||
router.GET("/health", func(c *gin.Context) { c.Status(200) })
|
router.GET("/health", func(c *gin.Context) { c.Status(200) })
|
||||||
v1 := router.Group("api/v1")
|
v1 := router.Group("api/v1")
|
||||||
|
v1.Static("/uploads", "/data/uploads")
|
||||||
|
v1.POST("/upload", auth.JWTMiddleware(), auth.RequireAdmin(), handler_static.PostStatic)
|
||||||
|
v1.GET("/upload/:file", handler_static.GetStatic)
|
||||||
v1.GET("/callback/github", handler_auth.CallbackGithub)
|
v1.GET("/callback/github", handler_auth.CallbackGithub)
|
||||||
v1.GET("/auth/github", handler_auth.LoginGithub)
|
v1.GET("/auth/github", handler_auth.LoginGithub)
|
||||||
v1.GET("/session", auth.JWTMiddleware(), handler_auth.GetSession)
|
v1.GET("/session", auth.JWTMiddleware(), handler_auth.GetSession)
|
||||||
|
|||||||
90
backend/internal/handlers/static_handlers.go
Normal file
90
backend/internal/handlers/static_handlers.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/logger"
|
||||||
|
"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/models"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StaticHandlers struct {
|
||||||
|
logger *logger.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStaticHandlers() *StaticHandlers {
|
||||||
|
return &StaticHandlers{
|
||||||
|
logger: logger.New(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostStatic godoc
|
||||||
|
// @Summary Upload static content
|
||||||
|
// @Description Upload static content to the server
|
||||||
|
// @Tags static
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} models.SuccessResponse(data=string) "Static content"
|
||||||
|
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
||||||
|
// @Router /upload [post]
|
||||||
|
func (h *StaticHandlers) PostStatic(c *gin.Context) {
|
||||||
|
content, err := c.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Error("error request: " + err.Error())
|
||||||
|
models.Error(c, 500, "Internal server error", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dst := "/data/upload/" + content.Filename
|
||||||
|
if err = c.SaveUploadedFile(content, dst); err != nil {
|
||||||
|
h.logger.Error("error request: " + err.Error())
|
||||||
|
models.Error(c, 500, "Internal server error", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
models.Success(c, "Static content saved")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStatic godoc
|
||||||
|
// @Summary Get static content
|
||||||
|
// @Description Get static content
|
||||||
|
// @Tags static
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param file path string true "File name"
|
||||||
|
// @Success 200 {object} models.SuccessResponse{data=string} "Static content"
|
||||||
|
// @Failure 500 {object} models.ErrorResponse "Internal server error"
|
||||||
|
// @Failure 404 {object} models.ErrorResponse "File not found"
|
||||||
|
// @Router /upload/{file} [get]
|
||||||
|
func (h *StaticHandlers) GetStatic(c *gin.Context) {
|
||||||
|
|
||||||
|
filename := c.Param("file")
|
||||||
|
if filename == "" {
|
||||||
|
models.Error(c, 404, "File not found", "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = filepath.Clean(filename)
|
||||||
|
|
||||||
|
if strings.Contains(filename, "..") {
|
||||||
|
models.Error(c, 400, "Invalid file path", "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if filepath.IsAbs(filename) {
|
||||||
|
models.Error(c, 400, "Invalid file path", "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
baseDir := "/data/upload/"
|
||||||
|
fullPath := filepath.Join(baseDir, filename)
|
||||||
|
if !strings.HasPrefix(fullPath, baseDir) {
|
||||||
|
models.Error(c, 400, "Invalid file path", "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(fullPath); os.IsNotExist(err) {
|
||||||
|
models.Error(c, 404, "File not found", "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.File(fullPath)
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package repositories
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/logger"
|
"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/logger"
|
||||||
"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/storage"
|
"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/storage"
|
||||||
@@ -21,7 +22,7 @@ func NewPostRepository(db *sql.DB) PostRepository {
|
|||||||
}
|
}
|
||||||
func (p *postRepository) GetAll(ctx context.Context) ([]storage.PostReq, error) {
|
func (p *postRepository) GetAll(ctx context.Context) ([]storage.PostReq, error) {
|
||||||
var result []storage.PostReq
|
var result []storage.PostReq
|
||||||
rows, err := p.db.Query("SELECT id, title, content FROM posts")
|
rows, err := p.db.Query("SELECT id, title, content FROM posts WHERE published = 1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.logger.Error(err.Error())
|
p.logger.Error(err.Error())
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -45,7 +46,7 @@ func (p *postRepository) GetAll(ctx context.Context) ([]storage.PostReq, error)
|
|||||||
|
|
||||||
func (p *postRepository) GetByID(ctx context.Context, id int) (storage.PostReq, error) {
|
func (p *postRepository) GetByID(ctx context.Context, id int) (storage.PostReq, error) {
|
||||||
var result storage.PostReq
|
var result storage.PostReq
|
||||||
row := p.db.QueryRow("SELECT title, content FROM posts WHERE id = ?", id)
|
row := p.db.QueryRow("SELECT title, content FROM posts WHERE id = ? AND published = 1", id)
|
||||||
var title string
|
var title string
|
||||||
var content string
|
var content string
|
||||||
err := row.Scan(&title, &content)
|
err := row.Scan(&title, &content)
|
||||||
@@ -78,17 +79,29 @@ func (p *postRepository) Create(ctx context.Context, post storage.Post) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *postRepository) Update(ctx context.Context, id int, post storage.Post) error {
|
func (p *postRepository) Update(ctx context.Context, id int, post storage.Post) error {
|
||||||
_, err := p.db.Exec(
|
query := "UPDATE posts SET "
|
||||||
"UPDATE posts SET title = ?, content = ? WHERE id = ?",
|
args := []interface{}{}
|
||||||
post.Title,
|
updates := []string{}
|
||||||
post.Content,
|
|
||||||
id,
|
if post.Title != "" {
|
||||||
)
|
updates = append(updates, "title = ?")
|
||||||
if err != nil {
|
args = append(args, post.Title)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
p.logger.Info("Post updated:", "id", id)
|
|
||||||
return nil
|
if post.Content != "" {
|
||||||
|
updates = append(updates, "content = ?")
|
||||||
|
args = append(args, post.Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
updates = append(updates, "published = ?")
|
||||||
|
args = append(args, post.Published)
|
||||||
|
updates = append(updates, "updated_at = CURRENT_TIMESTAMP")
|
||||||
|
query += strings.Join(updates, ", ")
|
||||||
|
query += " WHERE id = ?"
|
||||||
|
args = append(args, id)
|
||||||
|
|
||||||
|
_, err := p.db.ExecContext(ctx, query, args...)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *postRepository) Delete(ctx context.Context, id int) error {
|
func (p *postRepository) Delete(ctx context.Context, id int) error {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const Migrations = `
|
|||||||
CREATE TABLE IF NOT EXISTS posts(
|
CREATE TABLE IF NOT EXISTS posts(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
title TEXT NOT NULL,
|
title TEXT NOT NULL,
|
||||||
|
published BOOLEAN DEFAULT 0,
|
||||||
content TEXT NOT NULL,
|
content TEXT NOT NULL,
|
||||||
CREATED_AT DATETIME DEFAULT CURRENT_TIMESTAMP
|
CREATED_AT DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package storage
|
|||||||
type Post struct {
|
type Post struct {
|
||||||
ID int `db:"id" json:"id"`
|
ID int `db:"id" json:"id"`
|
||||||
Title string `db:"title" json:"title"`
|
Title string `db:"title" json:"title"`
|
||||||
|
Published bool `db:"published" json:"published"`
|
||||||
Content string `db:"content" json:"content"`
|
Content string `db:"content" json:"content"`
|
||||||
CreatedAt string `db:"created_at" json:"created_at"`
|
CreatedAt string `db:"created_at" json:"created_at"`
|
||||||
}
|
}
|
||||||
@@ -15,6 +16,7 @@ type PostReq struct {
|
|||||||
|
|
||||||
type PostCreate struct {
|
type PostCreate struct {
|
||||||
Title string `db:"title" json:"title"`
|
Title string `db:"title" json:"title"`
|
||||||
|
Published bool `db:"published" json:"published"`
|
||||||
Content string `db:"content" json:"content"`
|
Content string `db:"content" json:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function AuthCallback() {
|
|||||||
|
|
||||||
await checkAuth();
|
await checkAuth();
|
||||||
|
|
||||||
navigate("/", { replace: true });
|
window.location.href = "/";
|
||||||
} else {
|
} else {
|
||||||
console.error("No token in URL");
|
console.error("No token in URL");
|
||||||
navigate("/login?error=no_token");
|
navigate("/login?error=no_token");
|
||||||
|
|||||||
Reference in New Issue
Block a user