stage commit (pagination, sorting, a lil bit refactored)
This commit is contained in:
parent
848dd5df8a
commit
7ed9f67c37
@ -1,15 +0,0 @@
|
|||||||
package controllers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"system-trace/core/auth"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func InitAuth(app *fiber.App, version *fiber.Router) {
|
|
||||||
v := *version
|
|
||||||
g := v.Group("/auth")
|
|
||||||
{
|
|
||||||
g.Post("/login", auth.ReqTokens)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"system-trace/core/app/controllers"
|
|
||||||
_ "system-trace/core/docs"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/gofiber/swagger"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Init(app *fiber.App) {
|
|
||||||
app.Get("/swagger/*", swagger.HandlerDefault)
|
|
||||||
v1 := app.Group("/v1")
|
|
||||||
{
|
|
||||||
controllers.InitAuth(app, &v1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"system-trace/core/app/constants"
|
|
||||||
"system-trace/core/app/router"
|
|
||||||
"system-trace/core/app/router/middlewares"
|
|
||||||
"system-trace/core/environment"
|
|
||||||
|
|
||||||
"github.com/goccy/go-json"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
|
||||||
"github.com/gofiber/fiber/v2/middleware/recover"
|
|
||||||
)
|
|
||||||
|
|
||||||
var Instance *fiber.App
|
|
||||||
|
|
||||||
func Serve() {
|
|
||||||
Instance = initServer()
|
|
||||||
Instance.Use(recover.New())
|
|
||||||
Instance.Use(cors.New())
|
|
||||||
Instance.Use(middlewares.ValidateSession)
|
|
||||||
router.Init(Instance)
|
|
||||||
Instance.Use(func(c *fiber.Ctx) error {
|
|
||||||
return c.
|
|
||||||
Status(fiber.StatusNotFound).
|
|
||||||
JSON(fiber.Map{
|
|
||||||
"error": constants.NOT_FOUND,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
Instance.Listen(":" + os.Getenv("APP_PORT"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func initServer() *fiber.App {
|
|
||||||
debug := environment.IsDebug()
|
|
||||||
|
|
||||||
return fiber.New(fiber.Config{
|
|
||||||
JSONEncoder: json.Marshal,
|
|
||||||
JSONDecoder: json.Unmarshal,
|
|
||||||
CaseSensitive: true,
|
|
||||||
EnablePrintRoutes: debug,
|
|
||||||
Prefork: true,
|
|
||||||
AppName: "System Trace API",
|
|
||||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
||||||
"error": err.Error(),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AUTH_FAILED = "User with specified email and password not found"
|
AUTH_FAILED = "User with specified E-Mail and password not found"
|
||||||
NOT_FOUND = "Wrong request method or path"
|
NOT_FOUND = "Wrong request method or path"
|
||||||
UNAUTHORIZED = "Unauthorized"
|
UNAUTHORIZED = "Unauthorized"
|
||||||
)
|
)
|
||||||
42
constants/permissions/permissions.go
Normal file
42
constants/permissions/permissions.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package permissions
|
||||||
|
|
||||||
|
const (
|
||||||
|
DASHBOARD_READ = "DASHBOARD_READ"
|
||||||
|
SETTINGS_READ = "SETTINGS_READ"
|
||||||
|
SETTINGS_UPDATE = "SETTINGS_UPDATE"
|
||||||
|
LOGS_READ = "LOGS_READ"
|
||||||
|
TASKS_READ = "TASKS_READ"
|
||||||
|
TASKS_UPDATE = "TASKS_UPDATE"
|
||||||
|
USERS_READ = "USERS_READ"
|
||||||
|
USERS_CREATE = "USERS_CREATE"
|
||||||
|
USERS_UPDATE = "USERS_UPDATE"
|
||||||
|
USERS_DELETE = "USERS_DELETE"
|
||||||
|
USERS_BLOCK = "USERS_BLOCK"
|
||||||
|
GROUPS_READ = "GROUPS_READ"
|
||||||
|
GROUPS_CREATE = "GROUPS_CREATE"
|
||||||
|
GROUPS_UPDATE = "GROUPS_UPDATE"
|
||||||
|
GROUPS_DELETE = "GROUPS_DELETE"
|
||||||
|
)
|
||||||
|
|
||||||
|
var All = map[string]int8{
|
||||||
|
DASHBOARD_READ: 1,
|
||||||
|
|
||||||
|
SETTINGS_READ: 2,
|
||||||
|
SETTINGS_UPDATE: 3,
|
||||||
|
|
||||||
|
LOGS_READ: 4,
|
||||||
|
|
||||||
|
TASKS_READ: 5,
|
||||||
|
TASKS_UPDATE: 6,
|
||||||
|
|
||||||
|
USERS_READ: 7,
|
||||||
|
USERS_CREATE: 9,
|
||||||
|
USERS_UPDATE: 10,
|
||||||
|
USERS_DELETE: 11,
|
||||||
|
USERS_BLOCK: 12,
|
||||||
|
|
||||||
|
GROUPS_READ: 13,
|
||||||
|
GROUPS_CREATE: 14,
|
||||||
|
GROUPS_UPDATE: 15,
|
||||||
|
GROUPS_DELETE: 16,
|
||||||
|
}
|
||||||
@ -1,16 +1,22 @@
|
|||||||
package auth
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"system-trace/core/database"
|
"system-trace/core/types"
|
||||||
"system-trace/core/database/entities"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetPair(p *PairTokens) (*entities.AuthToken, error) {
|
type AuthToken struct {
|
||||||
aut := new(entities.AuthToken)
|
UserID int32
|
||||||
|
AccessToken string `bun:"type:varchar"`
|
||||||
|
RefreshToken string `bun:"type:varchar"`
|
||||||
|
IsRevoked bool `bun:",default:false"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPairOfTokens(p *types.PairTokens) (*AuthToken, error) {
|
||||||
|
aut := new(AuthToken)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := database.PG.NewSelect().
|
err := PG.NewSelect().
|
||||||
Model(aut).
|
Model(aut).
|
||||||
Where("access_token = ?", p.AccessToken).
|
Where("access_token = ?", p.AccessToken).
|
||||||
Where("refresh_token = ?", p.RefreshToken).
|
Where("refresh_token = ?", p.RefreshToken).
|
||||||
@ -20,13 +26,29 @@ func GetPair(p *PairTokens) (*entities.AuthToken, error) {
|
|||||||
return aut, err
|
return aut, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func RevokePair(p *PairTokens) error {
|
func InsertPairOfTokens(id int32, at, rt string) error {
|
||||||
aut := entities.AuthToken{
|
p := AuthToken{
|
||||||
|
UserID: id,
|
||||||
|
AccessToken: at,
|
||||||
|
RefreshToken: rt,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err := PG.NewInsert().
|
||||||
|
Model(&p).
|
||||||
|
Returning("NULL").
|
||||||
|
Exec(ctx)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func RevokePairOfTokens(p *types.PairTokens) error {
|
||||||
|
aut := AuthToken{
|
||||||
IsRevoked: true,
|
IsRevoked: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
_, err := database.PG.NewUpdate().
|
_, err := PG.NewUpdate().
|
||||||
Model(&aut).
|
Model(&aut).
|
||||||
Column("is_revoked").
|
Column("is_revoked").
|
||||||
Where("access_token = ?", p.AccessToken).
|
Where("access_token = ?", p.AccessToken).
|
||||||
@ -35,19 +57,3 @@ func RevokePair(p *PairTokens) error {
|
|||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertPair(id int32, at, rt string) error {
|
|
||||||
p := entities.AuthToken{
|
|
||||||
UserID: id,
|
|
||||||
AccessToken: at,
|
|
||||||
RefreshToken: rt,
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
_, err := database.PG.NewInsert().
|
|
||||||
Model(&p).
|
|
||||||
Returning("NULL").
|
|
||||||
Exec(ctx)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
@ -6,7 +6,6 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"system-trace/core/database/entities"
|
|
||||||
"system-trace/core/environment"
|
"system-trace/core/environment"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -41,7 +40,6 @@ func Connect() {
|
|||||||
if environment.IsDebug() {
|
if environment.IsDebug() {
|
||||||
db.AddQueryHook(bundebug.NewQueryHook(
|
db.AddQueryHook(bundebug.NewQueryHook(
|
||||||
bundebug.WithVerbose(true),
|
bundebug.WithVerbose(true),
|
||||||
bundebug.FromEnv("BUNDEBUG"),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,12 +55,12 @@ func Connect() {
|
|||||||
|
|
||||||
func createSchema(db *bun.DB) error {
|
func createSchema(db *bun.DB) error {
|
||||||
models := []interface{}{
|
models := []interface{}{
|
||||||
(*entities.Group)(nil),
|
(*Group)(nil),
|
||||||
(*entities.GroupPermission)(nil),
|
(*GroupPermission)(nil),
|
||||||
(*entities.User)(nil),
|
(*User)(nil),
|
||||||
(*entities.Session)(nil),
|
(*Session)(nil),
|
||||||
(*entities.Server)(nil),
|
(*Server)(nil),
|
||||||
(*entities.AuthToken)(nil),
|
(*AuthToken)(nil),
|
||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +0,0 @@
|
|||||||
package entities
|
|
||||||
|
|
||||||
type AuthToken struct {
|
|
||||||
UserID int32
|
|
||||||
AccessToken string `bun:"type:varchar"`
|
|
||||||
RefreshToken string `bun:"type:varchar"`
|
|
||||||
IsRevoked bool `bun:",default:false"`
|
|
||||||
}
|
|
||||||
@ -1,16 +0,0 @@
|
|||||||
package entities
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type Group struct {
|
|
||||||
ID int32 `bun:",pk,autoincrement"`
|
|
||||||
IssuerID int32 `bun:",notnull"`
|
|
||||||
Issuer *User `bun:"rel:belongs-to,join:issuer_id=id"`
|
|
||||||
Name string `bun:",notnull,unique"`
|
|
||||||
GroupID int32 `bun:",notnull"`
|
|
||||||
Users []*User `bun:"rel:has-many,join:id=group_id"`
|
|
||||||
Permissions []*GroupPermission `bun:"rel:has-many,join:id=group_id"`
|
|
||||||
CreatedAt time.Time `bun:",notnull,default:current_timestamp"`
|
|
||||||
UpdatedAt time.Time
|
|
||||||
DeletedAt time.Time `bun:",soft_delete,nullzero"`
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
package entities
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/uptrace/bun"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
ID int64 `bun:",pk,autoincrement"`
|
|
||||||
Hostname string `bun:",notnull"`
|
|
||||||
IP string `bun:",notnull"`
|
|
||||||
IsOnline bool `bun:",notnull,default:true"`
|
|
||||||
LastOnline time.Time
|
|
||||||
CreatedAt time.Time `bun:",notnull,default:current_timestamp"`
|
|
||||||
UpdatedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ bun.BeforeAppendModelHook = (*Server)(nil)
|
|
||||||
|
|
||||||
func (s *Server) BeforeAppendModel(ctx context.Context, query bun.Query) error {
|
|
||||||
switch query.(type) {
|
|
||||||
case *bun.InsertQuery:
|
|
||||||
s.LastOnline = time.Now()
|
|
||||||
case *bun.UpdateQuery:
|
|
||||||
s.UpdatedAt = time.Now()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package entities
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/uptrace/bun"
|
|
||||||
)
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
ID int32 `bun:",pk,autoincrement"`
|
|
||||||
Email string `bun:",notnull,unique"`
|
|
||||||
PasswordHash string `bun:",notnull,type:varchar(64)"`
|
|
||||||
PasswordLength int8 `bun:",notnull"`
|
|
||||||
RealName string `bun:",notnull"`
|
|
||||||
GroupID int32 `bun:",notnull"`
|
|
||||||
Group *Group `bun:"rel:belongs-to,join:group_id=id"`
|
|
||||||
IsRequiredToSetPassword bool `bun:",notnull,default:true"`
|
|
||||||
IsActive bool `bun:",notnull,default:true"`
|
|
||||||
LastLogin time.Time
|
|
||||||
CreatedAt time.Time `bun:",notnull,default:current_timestamp"`
|
|
||||||
UpdatedAt time.Time
|
|
||||||
DeletedAt time.Time `bun:",soft_delete,nullzero"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ bun.BeforeAppendModelHook = (*User)(nil)
|
|
||||||
|
|
||||||
func (u *User) BeforeAppendModel(ctx context.Context, query bun.Query) error {
|
|
||||||
switch query.(type) {
|
|
||||||
case *bun.UpdateQuery:
|
|
||||||
u.UpdatedAt = time.Now()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
95
database/group.go
Normal file
95
database/group.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"system-trace/core/types"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Group struct {
|
||||||
|
ID int32 `bun:",pk,autoincrement"`
|
||||||
|
IssuerID int32 `bun:",notnull" json:"issuerId"`
|
||||||
|
Issuer *User `bun:"rel:belongs-to,join:issuer_id=id" json:"issuer"`
|
||||||
|
Name string `bun:",notnull,unique" json:"name"`
|
||||||
|
Users []*User `bun:"rel:has-many,join:id=group_id,array" json:"users"`
|
||||||
|
Permissions []*GroupPermission `bun:"rel:has-many,join:id=group_id,array" json:"permissions"`
|
||||||
|
CreatedAt time.Time `bun:",notnull,default:current_timestamp" json:"createdAt"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
|
DeletedAt time.Time `bun:",soft_delete,nullzero" json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ bun.BeforeAppendModelHook = (*Group)(nil)
|
||||||
|
|
||||||
|
func (g *Group) BeforeAppendModel(ctx context.Context, query bun.Query) error {
|
||||||
|
switch query.(type) {
|
||||||
|
case *bun.UpdateQuery:
|
||||||
|
g.UpdatedAt = time.Now()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindGroups(p *types.Pagination, ob *types.OrderBy) (groups *[]Group, cursor *types.Cursor, err error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
groups = new([]Group)
|
||||||
|
count, err := PG.NewSelect().
|
||||||
|
Model(groups).
|
||||||
|
Relation("Users").
|
||||||
|
Relation("Permissions").
|
||||||
|
Offset(p.Page*p.Count - p.Count).
|
||||||
|
Limit(p.Count).
|
||||||
|
Order(fmt.Sprintf("%s %s", ob.Key, ob.Order)).
|
||||||
|
ScanAndCount(ctx)
|
||||||
|
|
||||||
|
return groups, &types.Cursor{
|
||||||
|
Count: len(*groups),
|
||||||
|
CurrentPage: p.Page,
|
||||||
|
TotalPages: math.Ceil(float64(count) / float64(p.Count)),
|
||||||
|
TotalRows: float64(count),
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindGroupByID(id int) (group *Group, err error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
group = new(Group)
|
||||||
|
err = PG.NewSelect().
|
||||||
|
Model(group).
|
||||||
|
Where("id = ?", id).
|
||||||
|
Scan(ctx)
|
||||||
|
|
||||||
|
return group, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertGroup(g *Group) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err := PG.NewInsert().
|
||||||
|
Model(g).
|
||||||
|
Returning("NULL").
|
||||||
|
Exec(ctx)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateGroup(g *Group, cols []string) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err := PG.NewUpdate().
|
||||||
|
Model(g).
|
||||||
|
Column(cols...).
|
||||||
|
WherePK().
|
||||||
|
Exec(ctx)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteGroup(id int) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err := PG.NewDelete().
|
||||||
|
Model(new(Group)).
|
||||||
|
Where("id = ?", id).
|
||||||
|
Exec(ctx)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package entities
|
package database
|
||||||
|
|
||||||
type GroupPermission struct {
|
type GroupPermission struct {
|
||||||
GroupID int32 `bun:",notnull" json:"-"`
|
GroupID int32 `bun:",notnull" json:"-"`
|
||||||
Value int8 `bun:",notnull"`
|
Value int8 `bun:",notnull" json:"value"`
|
||||||
}
|
}
|
||||||
30
database/server.go
Normal file
30
database/server.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
ID int64 `bun:",pk,autoincrement"`
|
||||||
|
Hostname string `bun:",notnull" json:"hostname"`
|
||||||
|
IP string `bun:",notnull"`
|
||||||
|
IsOnline bool `bun:",notnull,default:true" json:"isOnline"`
|
||||||
|
LastOnline time.Time `json:"lastOnline"`
|
||||||
|
CreatedAt time.Time `bun:",notnull,default:current_timestamp" json:"createdAt"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ bun.BeforeAppendModelHook = (*Server)(nil)
|
||||||
|
|
||||||
|
func (s *Server) BeforeAppendModel(ctx context.Context, query bun.Query) error {
|
||||||
|
switch query.(type) {
|
||||||
|
case *bun.InsertQuery:
|
||||||
|
s.LastOnline = time.Now()
|
||||||
|
case *bun.UpdateQuery:
|
||||||
|
s.UpdatedAt = time.Now()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package entities
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -9,13 +9,13 @@ import (
|
|||||||
|
|
||||||
type Session struct {
|
type Session struct {
|
||||||
ID int64 `bun:",pk,autoincrement"`
|
ID int64 `bun:",pk,autoincrement"`
|
||||||
IssuerID int32 `bun:",notnull"`
|
IssuerID int32 `bun:",notnull" json:"issuerId"`
|
||||||
Issuer *User `bun:"rel:belongs-to,join:issuer_id=id"`
|
Issuer *User `bun:"rel:belongs-to,join:issuer_id=id" json:"issuer"`
|
||||||
Configuration map[string]interface{} `bun:"type:jsonb"`
|
Configuration map[string]interface{} `bun:"type:jsonb" json:"configuration"`
|
||||||
CreatedAt time.Time `bun:",notnull,default:current_timestamp"`
|
CreatedAt time.Time `bun:",notnull,default:current_timestamp" json:"createdAt"`
|
||||||
FinishedAt time.Time
|
FinishedAt time.Time `json:"finishedAt"`
|
||||||
UpdatedAt time.Time
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
DeletedAt time.Time `bun:",soft_delete,nullzero"`
|
DeletedAt time.Time `bun:",soft_delete,nullzero" json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ bun.BeforeAppendModelHook = (*Session)(nil)
|
var _ bun.BeforeAppendModelHook = (*Session)(nil)
|
||||||
112
database/user.go
Normal file
112
database/user.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"system-trace/core/types"
|
||||||
|
"system-trace/core/utils"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/uptrace/bun"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID int32 `bun:",pk,autoincrement"`
|
||||||
|
Email string `bun:",notnull,unique" json:"email"`
|
||||||
|
PasswordHash string `bun:",notnull,type:varchar(64)" json:"-"`
|
||||||
|
PasswordLength int8 `bun:",notnull" json:"passwordLength"`
|
||||||
|
RealName string `bun:",notnull" json:"realName"`
|
||||||
|
GroupID int32 `bun:",notnull" json:"groupId"`
|
||||||
|
Group *Group `bun:"rel:belongs-to,join:group_id=id" json:"group"`
|
||||||
|
IsRequiredToSetPassword bool `bun:",notnull,default:true" json:"isRequiredToSetPassword"`
|
||||||
|
IsActive bool `bun:",notnull,default:true" json:"isActive"`
|
||||||
|
LastLogin time.Time `json:"lastLogin"`
|
||||||
|
CreatedAt time.Time `bun:",notnull,default:current_timestamp" json:"createdAt"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
|
DeletedAt time.Time `bun:",soft_delete,nullzero" json:"deletedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ bun.BeforeAppendModelHook = (*User)(nil)
|
||||||
|
|
||||||
|
func (u *User) BeforeAppendModel(ctx context.Context, query bun.Query) error {
|
||||||
|
switch query.(type) {
|
||||||
|
case *bun.UpdateQuery:
|
||||||
|
u.UpdatedAt = time.Now()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindByEmailAndPassword(email, password string) (*User, error) {
|
||||||
|
passwordHash := utils.SHA256(password)
|
||||||
|
ctx := context.Background()
|
||||||
|
u := new(User)
|
||||||
|
err := PG.NewSelect().
|
||||||
|
Model(u).
|
||||||
|
Where("email = ?", email).
|
||||||
|
Where("password_hash = ?", passwordHash).
|
||||||
|
Scan(ctx)
|
||||||
|
|
||||||
|
return u, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindUsers(p *types.Pagination, ob *types.OrderBy) (users *[]User, cursor *types.Cursor, err error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
users = new([]User)
|
||||||
|
count, err := PG.NewSelect().
|
||||||
|
Model(users).
|
||||||
|
Relation("Group").
|
||||||
|
Offset(p.Page*p.Count - p.Count).
|
||||||
|
Limit(p.Count).
|
||||||
|
Order(fmt.Sprintf("%s %s", ob.Key, ob.Order)).
|
||||||
|
ScanAndCount(ctx)
|
||||||
|
|
||||||
|
return users, &types.Cursor{
|
||||||
|
Count: len(*users),
|
||||||
|
CurrentPage: p.Page,
|
||||||
|
TotalPages: math.Ceil(float64(count) / float64(p.Count)),
|
||||||
|
TotalRows: float64(count),
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindUserByID(id int) (user *User, err error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
user = new(User)
|
||||||
|
err = PG.NewSelect().
|
||||||
|
Model(user).
|
||||||
|
Where("id = ?", id).
|
||||||
|
Scan(ctx)
|
||||||
|
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertUser(u *User) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err := PG.NewInsert().
|
||||||
|
Model(u).
|
||||||
|
Returning("NULL").
|
||||||
|
Exec(ctx)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateUser(u *User, cols []string) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err := PG.NewUpdate().
|
||||||
|
Model(u).
|
||||||
|
Column(cols...).
|
||||||
|
WherePK().
|
||||||
|
Exec(ctx)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteUser(id int) error {
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err := PG.NewDelete().
|
||||||
|
Model(new(User)).
|
||||||
|
Where("id = ?", id).
|
||||||
|
Exec(ctx)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
433
docs/docs.go
433
docs/docs.go
@ -34,7 +34,7 @@ const docTemplate = `{
|
|||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/auth.AuthBody"
|
"$ref": "#/definitions/types.AuthBody"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -44,10 +44,410 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/groups": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns array of groups and count",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"groups"
|
||||||
|
],
|
||||||
|
"summary": "Get groups (with pagination)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"maximum": 100,
|
||||||
|
"minimum": 10,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Count of rows",
|
||||||
|
"name": "count",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Rows to skip",
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/types.JSONPagination"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"description": "Create group with specified data",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"groups"
|
||||||
|
],
|
||||||
|
"summary": "Create group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Request body",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"description": "Update group with specified data",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"groups"
|
||||||
|
],
|
||||||
|
"summary": "Update group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Request body",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/groups/:id": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns group instance",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"groups"
|
||||||
|
],
|
||||||
|
"summary": "Get group by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Group ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"description": "Delete group by ID",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"groups"
|
||||||
|
],
|
||||||
|
"summary": "Delete group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Group ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/permissions": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns key-value map with permissions",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"summary": "Get list of permissions",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/users": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns array of users and count",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"summary": "Get users (with pagination)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"maximum": 100,
|
||||||
|
"minimum": 10,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Count of rows",
|
||||||
|
"name": "count",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Rows to skip",
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/types.JSONPagination"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"description": "Create user with specified data",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"summary": "Create user",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Request body",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"description": "Update user with specified data",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"summary": "Update user",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Request body",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/users/:id": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns user instance",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"summary": "Get user by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"description": "Delete user by ID",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"summary": "Delete user",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"auth.AuthBody": {
|
"database.Group": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"deletedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"issuer": {
|
||||||
|
"$ref": "#/definitions/database.User"
|
||||||
|
},
|
||||||
|
"issuerID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"permissions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/database.GroupPermission"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/database.User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database.GroupPermission": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"value": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database.User": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"deletedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"$ref": "#/definitions/database.Group"
|
||||||
|
},
|
||||||
|
"groupID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"isActive": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"isRequiredToSetPassword": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"lastLogin": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"passwordHash": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"passwordLength": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"realName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"types.AuthBody": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"email",
|
"email",
|
||||||
@ -60,15 +460,38 @@ const docTemplate = `{
|
|||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "Aasdfgh1!"
|
"example": "Aasdfg1!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"types.Cursor": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"count": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"currentPage": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"totalPages": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"types.JSONPagination": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"cursor": {
|
||||||
|
"$ref": "#/definitions/types.Cursor"
|
||||||
|
},
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securityDefinitions": {
|
"securityDefinitions": {
|
||||||
"Bearer": {
|
"accessToken=...;refreshToken=...": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"name": "Authorization",
|
"name": "Cookie",
|
||||||
"in": "header"
|
"in": "header"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/auth.AuthBody"
|
"$ref": "#/definitions/types.AuthBody"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -36,10 +36,410 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"/groups": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns array of groups and count",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"groups"
|
||||||
|
],
|
||||||
|
"summary": "Get groups (with pagination)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"maximum": 100,
|
||||||
|
"minimum": 10,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Count of rows",
|
||||||
|
"name": "count",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Rows to skip",
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/types.JSONPagination"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"description": "Create group with specified data",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"groups"
|
||||||
|
],
|
||||||
|
"summary": "Create group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Request body",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"description": "Update group with specified data",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"groups"
|
||||||
|
],
|
||||||
|
"summary": "Update group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Request body",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/groups/:id": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns group instance",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"groups"
|
||||||
|
],
|
||||||
|
"summary": "Get group by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Group ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.Group"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"description": "Delete group by ID",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"groups"
|
||||||
|
],
|
||||||
|
"summary": "Delete group",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Group ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/permissions": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns key-value map with permissions",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"summary": "Get list of permissions",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/users": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns array of users and count",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"summary": "Get users (with pagination)",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"maximum": 100,
|
||||||
|
"minimum": 10,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Count of rows",
|
||||||
|
"name": "count",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Rows to skip",
|
||||||
|
"name": "offset",
|
||||||
|
"in": "query",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/types.JSONPagination"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
"description": "Create user with specified data",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"summary": "Create user",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Request body",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"description": "Update user with specified data",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"summary": "Update user",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Request body",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/users/:id": {
|
||||||
|
"get": {
|
||||||
|
"description": "Returns user instance",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"summary": "Get user by ID",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/database.User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"description": "Delete user by ID",
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"users"
|
||||||
|
],
|
||||||
|
"summary": "Delete user",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"minimum": 1,
|
||||||
|
"type": "integer",
|
||||||
|
"description": "User ID",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"auth.AuthBody": {
|
"database.Group": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"deletedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"issuer": {
|
||||||
|
"$ref": "#/definitions/database.User"
|
||||||
|
},
|
||||||
|
"issuerID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"permissions": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/database.GroupPermission"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/database.User"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database.GroupPermission": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"value": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database.User": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"createdAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"deletedAt": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"$ref": "#/definitions/database.Group"
|
||||||
|
},
|
||||||
|
"groupID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"isActive": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"isRequiredToSetPassword": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"lastLogin": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"passwordHash": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"passwordLength": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"realName": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"updatedAt": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"types.AuthBody": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"email",
|
"email",
|
||||||
@ -52,15 +452,38 @@
|
|||||||
},
|
},
|
||||||
"password": {
|
"password": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"example": "Aasdfgh1!"
|
"example": "Aasdfg1!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"types.Cursor": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"count": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"currentPage": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"totalPages": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"types.JSONPagination": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"cursor": {
|
||||||
|
"$ref": "#/definitions/types.Cursor"
|
||||||
|
},
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"securityDefinitions": {
|
"securityDefinitions": {
|
||||||
"Bearer": {
|
"accessToken=...;refreshToken=...": {
|
||||||
"type": "apiKey",
|
"type": "apiKey",
|
||||||
"name": "Authorization",
|
"name": "Cookie",
|
||||||
"in": "header"
|
"in": "header"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,91 @@
|
|||||||
basePath: /v1
|
basePath: /v1
|
||||||
definitions:
|
definitions:
|
||||||
auth.AuthBody:
|
database.Group:
|
||||||
|
properties:
|
||||||
|
createdAt:
|
||||||
|
type: string
|
||||||
|
deletedAt:
|
||||||
|
type: string
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
issuer:
|
||||||
|
$ref: '#/definitions/database.User'
|
||||||
|
issuerID:
|
||||||
|
type: integer
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
permissions:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/database.GroupPermission'
|
||||||
|
type: array
|
||||||
|
updatedAt:
|
||||||
|
type: string
|
||||||
|
users:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/database.User'
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
database.GroupPermission:
|
||||||
|
properties:
|
||||||
|
value:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
database.User:
|
||||||
|
properties:
|
||||||
|
createdAt:
|
||||||
|
type: string
|
||||||
|
deletedAt:
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
group:
|
||||||
|
$ref: '#/definitions/database.Group'
|
||||||
|
groupID:
|
||||||
|
type: integer
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
isActive:
|
||||||
|
type: boolean
|
||||||
|
isRequiredToSetPassword:
|
||||||
|
type: boolean
|
||||||
|
lastLogin:
|
||||||
|
type: string
|
||||||
|
passwordHash:
|
||||||
|
type: string
|
||||||
|
passwordLength:
|
||||||
|
type: integer
|
||||||
|
realName:
|
||||||
|
type: string
|
||||||
|
updatedAt:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
types.AuthBody:
|
||||||
properties:
|
properties:
|
||||||
email:
|
email:
|
||||||
example: john@proton.mail
|
example: john@proton.mail
|
||||||
type: string
|
type: string
|
||||||
password:
|
password:
|
||||||
example: Aasdfgh1!
|
example: Aasdfg1!
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- email
|
- email
|
||||||
- password
|
- password
|
||||||
type: object
|
type: object
|
||||||
|
types.Cursor:
|
||||||
|
properties:
|
||||||
|
count:
|
||||||
|
type: integer
|
||||||
|
currentPage:
|
||||||
|
type: integer
|
||||||
|
totalPages:
|
||||||
|
type: number
|
||||||
|
type: object
|
||||||
|
types.JSONPagination:
|
||||||
|
properties:
|
||||||
|
cursor:
|
||||||
|
$ref: '#/definitions/types.Cursor'
|
||||||
|
data: {}
|
||||||
|
type: object
|
||||||
info:
|
info:
|
||||||
contact:
|
contact:
|
||||||
name: https://peresvet.it
|
name: https://peresvet.it
|
||||||
@ -27,7 +101,7 @@ paths:
|
|||||||
name: request
|
name: request
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/auth.AuthBody'
|
$ref: '#/definitions/types.AuthBody'
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
@ -36,9 +110,216 @@ paths:
|
|||||||
summary: Request pair of tokens
|
summary: Request pair of tokens
|
||||||
tags:
|
tags:
|
||||||
- auth
|
- auth
|
||||||
|
/groups:
|
||||||
|
get:
|
||||||
|
description: Returns array of groups and count
|
||||||
|
parameters:
|
||||||
|
- description: Count of rows
|
||||||
|
in: query
|
||||||
|
maximum: 100
|
||||||
|
minimum: 10
|
||||||
|
name: count
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- description: Rows to skip
|
||||||
|
in: query
|
||||||
|
name: offset
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/types.JSONPagination'
|
||||||
|
summary: Get groups (with pagination)
|
||||||
|
tags:
|
||||||
|
- groups
|
||||||
|
patch:
|
||||||
|
description: Update group with specified data
|
||||||
|
parameters:
|
||||||
|
- description: Request body
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/database.Group'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
summary: Update group
|
||||||
|
tags:
|
||||||
|
- groups
|
||||||
|
post:
|
||||||
|
description: Create group with specified data
|
||||||
|
parameters:
|
||||||
|
- description: Request body
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/database.Group'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
summary: Create group
|
||||||
|
tags:
|
||||||
|
- groups
|
||||||
|
/groups/:id:
|
||||||
|
delete:
|
||||||
|
description: Delete group by ID
|
||||||
|
parameters:
|
||||||
|
- description: Group ID
|
||||||
|
in: path
|
||||||
|
minimum: 1
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
summary: Delete group
|
||||||
|
tags:
|
||||||
|
- groups
|
||||||
|
get:
|
||||||
|
description: Returns group instance
|
||||||
|
parameters:
|
||||||
|
- description: Group ID
|
||||||
|
in: path
|
||||||
|
minimum: 1
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/database.Group'
|
||||||
|
summary: Get group by ID
|
||||||
|
tags:
|
||||||
|
- groups
|
||||||
|
/permissions:
|
||||||
|
get:
|
||||||
|
description: Returns key-value map with permissions
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
additionalProperties:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
summary: Get list of permissions
|
||||||
|
/users:
|
||||||
|
get:
|
||||||
|
description: Returns array of users and count
|
||||||
|
parameters:
|
||||||
|
- description: Count of rows
|
||||||
|
in: query
|
||||||
|
maximum: 100
|
||||||
|
minimum: 10
|
||||||
|
name: count
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
- description: Rows to skip
|
||||||
|
in: query
|
||||||
|
name: offset
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/types.JSONPagination'
|
||||||
|
summary: Get users (with pagination)
|
||||||
|
tags:
|
||||||
|
- users
|
||||||
|
patch:
|
||||||
|
description: Update user with specified data
|
||||||
|
parameters:
|
||||||
|
- description: Request body
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/database.User'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
summary: Update user
|
||||||
|
tags:
|
||||||
|
- users
|
||||||
|
post:
|
||||||
|
description: Create user with specified data
|
||||||
|
parameters:
|
||||||
|
- description: Request body
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/database.User'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
summary: Create user
|
||||||
|
tags:
|
||||||
|
- users
|
||||||
|
/users/:id:
|
||||||
|
delete:
|
||||||
|
description: Delete user by ID
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: path
|
||||||
|
minimum: 1
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
summary: Delete user
|
||||||
|
tags:
|
||||||
|
- users
|
||||||
|
get:
|
||||||
|
description: Returns user instance
|
||||||
|
parameters:
|
||||||
|
- description: User ID
|
||||||
|
in: path
|
||||||
|
minimum: 1
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
type: integer
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/database.User'
|
||||||
|
summary: Get user by ID
|
||||||
|
tags:
|
||||||
|
- users
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
Bearer:
|
accessToken=...;refreshToken=...:
|
||||||
in: header
|
in: header
|
||||||
name: Authorization
|
name: Cookie
|
||||||
type: apiKey
|
type: apiKey
|
||||||
swagger: "2.0"
|
swagger: "2.0"
|
||||||
|
|||||||
2
go.mod
2
go.mod
@ -3,13 +3,11 @@ module system-trace/core
|
|||||||
go 1.22.3
|
go 1.22.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-playground/validator v9.31.0+incompatible
|
|
||||||
github.com/go-playground/validator/v10 v10.20.0
|
github.com/go-playground/validator/v10 v10.20.0
|
||||||
github.com/goccy/go-json v0.10.2
|
github.com/goccy/go-json v0.10.2
|
||||||
github.com/gofiber/fiber v1.14.6
|
github.com/gofiber/fiber v1.14.6
|
||||||
github.com/gofiber/fiber/v2 v2.52.4
|
github.com/gofiber/fiber/v2 v2.52.4
|
||||||
github.com/gofiber/swagger v1.0.0
|
github.com/gofiber/swagger v1.0.0
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/swaggo/swag v1.16.3
|
github.com/swaggo/swag v1.16.3
|
||||||
|
|||||||
16
go.sum
16
go.sum
@ -27,13 +27,12 @@ github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7
|
|||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
|
||||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator v9.31.0+incompatible h1:UA72EPEogEnq76ehGdEDp4Mit+3FDh548oRqwVgNsHA=
|
|
||||||
github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig=
|
|
||||||
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
@ -46,8 +45,6 @@ github.com/gofiber/swagger v1.0.0 h1:BzUzDS9ZT6fDUa692kxmfOjc1DZiloLiPK/W5z1H1tc
|
|||||||
github.com/gofiber/swagger v1.0.0/go.mod h1:QrYNF1Yrc7ggGK6ATsJ6yfH/8Zi5bu9lA7wB8TmCecg=
|
github.com/gofiber/swagger v1.0.0/go.mod h1:QrYNF1Yrc7ggGK6ATsJ6yfH/8Zi5bu9lA7wB8TmCecg=
|
||||||
github.com/gofiber/utils v0.0.10 h1:3Mr7X7JdCUo7CWf/i5sajSaDmArEDtti8bM1JUVso2U=
|
github.com/gofiber/utils v0.0.10 h1:3Mr7X7JdCUo7CWf/i5sajSaDmArEDtti8bM1JUVso2U=
|
||||||
github.com/gofiber/utils v0.0.10/go.mod h1:9J5aHFUIjq0XfknT4+hdSMG6/jzfaAgCu4HEbWDeBlo=
|
github.com/gofiber/utils v0.0.10/go.mod h1:9J5aHFUIjq0XfknT4+hdSMG6/jzfaAgCu4HEbWDeBlo=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
@ -66,6 +63,7 @@ github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ib
|
|||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
@ -84,13 +82,16 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
|||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@ -105,6 +106,7 @@ github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
|||||||
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||||
github.com/tetratelabs/wazero v1.7.0 h1:jg5qPydno59wqjpGrHph81lbtHzTrWzwwtD4cD88+hQ=
|
github.com/tetratelabs/wazero v1.7.0 h1:jg5qPydno59wqjpGrHph81lbtHzTrWzwwtD4cD88+hQ=
|
||||||
github.com/tetratelabs/wazero v1.7.0/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=
|
github.com/tetratelabs/wazero v1.7.0/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=
|
||||||
|
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
|
||||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
|
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
|
||||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
|
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
|
||||||
github.com/uptrace/bun v1.2.1 h1:2ENAcfeCfaY5+2e7z5pXrzFKy3vS8VXvkCag6N2Yzfk=
|
github.com/uptrace/bun v1.2.1 h1:2ENAcfeCfaY5+2e7z5pXrzFKy3vS8VXvkCag6N2Yzfk=
|
||||||
@ -130,10 +132,14 @@ github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAh
|
|||||||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
|
||||||
github.com/wasilibs/go-re2 v1.5.2 h1:fDO2TJrRzRrv3jD0gzOvmZ2UM4Yt9YXOEdLrlNc/Ies=
|
github.com/wasilibs/go-re2 v1.5.2 h1:fDO2TJrRzRrv3jD0gzOvmZ2UM4Yt9YXOEdLrlNc/Ies=
|
||||||
github.com/wasilibs/go-re2 v1.5.2/go.mod h1:UqqxQ1O99boQUm1r61H/IYGiGQOS/P88K7hU5nLNkEg=
|
github.com/wasilibs/go-re2 v1.5.2/go.mod h1:UqqxQ1O99boQUm1r61H/IYGiGQOS/P88K7hU5nLNkEg=
|
||||||
|
github.com/wasilibs/nottinygc v0.4.0 h1:h1TJMihMC4neN6Zq+WKpLxgd9xCFMw7O9ETLwY2exJQ=
|
||||||
|
github.com/wasilibs/nottinygc v0.4.0/go.mod h1:oDcIotskuYNMpqMF23l7Z8uzD4TC0WXHK8jetlB3HIo=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||||
|
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
|
||||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||||
@ -151,6 +157,7 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
@ -161,6 +168,7 @@ golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
|||||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
|||||||
7
main.go
7
main.go
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"system-trace/core/app"
|
|
||||||
"system-trace/core/database"
|
"system-trace/core/database"
|
||||||
"system-trace/core/environment"
|
"system-trace/core/environment"
|
||||||
"system-trace/core/validators"
|
"system-trace/core/validators"
|
||||||
@ -11,13 +10,13 @@ import (
|
|||||||
// @version 1.0
|
// @version 1.0
|
||||||
// @contact.name https://peresvet.it
|
// @contact.name https://peresvet.it
|
||||||
// @BasePath /v1
|
// @BasePath /v1
|
||||||
// @securityDefinitions.apikey Bearer
|
// @securityDefinitions.apikey accessToken=...;refreshToken=...
|
||||||
// @in header
|
// @in header
|
||||||
// @name Authorization
|
// @name Cookie
|
||||||
// @externalDocs.description OpenAPI
|
// @externalDocs.description OpenAPI
|
||||||
func main() {
|
func main() {
|
||||||
environment.Load()
|
environment.Load()
|
||||||
validators.RegisterValidators()
|
validators.RegisterValidators()
|
||||||
database.Connect()
|
database.Connect()
|
||||||
app.Serve()
|
serveApp()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,15 +3,17 @@ package middlewares
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"system-trace/core/app/constants"
|
"system-trace/core/constants"
|
||||||
"system-trace/core/auth"
|
"system-trace/core/database"
|
||||||
|
"system-trace/core/modules/auth"
|
||||||
|
"system-trace/core/types"
|
||||||
"system-trace/core/utils"
|
"system-trace/core/utils"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidateSession(c *fiber.Ctx) error {
|
func ValidateSession(c *fiber.Ctx) error {
|
||||||
p := new(auth.PairTokens)
|
p := new(types.PairTokens)
|
||||||
if err := c.CookieParser(p); err != nil {
|
if err := c.CookieParser(p); err != nil {
|
||||||
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
return c.Status(http.StatusBadRequest).JSON(fiber.Map{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
@ -26,7 +28,7 @@ func ValidateSession(c *fiber.Ctx) error {
|
|||||||
return c.Next()
|
return c.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
func validatePair(c *fiber.Ctx, p *auth.PairTokens) bool {
|
func validatePair(c *fiber.Ctx, p *types.PairTokens) bool {
|
||||||
if len(p.AccessToken) <= 0 || len(p.RefreshToken) <= 0 {
|
if len(p.AccessToken) <= 0 || len(p.RefreshToken) <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -39,12 +41,12 @@ func validatePair(c *fiber.Ctx, p *auth.PairTokens) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
pt, err := auth.GetPair(p)
|
pt, err := database.GetPairOfTokens(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
err = auth.RevokePair(p)
|
err = database.RevokePairOfTokens(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
21
parsers/order_by.go
Normal file
21
parsers/order_by.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package parsers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"system-trace/core/types"
|
||||||
|
"system-trace/core/validators"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseOrder(c *fiber.Ctx) (*types.OrderBy, error) {
|
||||||
|
ob := new(types.OrderBy)
|
||||||
|
if err := c.QueryParser(ob); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validators.Validate(c, ob); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ob, nil
|
||||||
|
}
|
||||||
21
parsers/pagination.go
Normal file
21
parsers/pagination.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package parsers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"system-trace/core/types"
|
||||||
|
"system-trace/core/validators"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParsePagination(c *fiber.Ctx) (*types.Pagination, error) {
|
||||||
|
p := new(types.Pagination)
|
||||||
|
if err := c.QueryParser(p); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validators.Validate(c, p); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
44
router.go
Normal file
44
router.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "system-trace/core/docs"
|
||||||
|
"system-trace/core/services"
|
||||||
|
"system-trace/core/services/auth"
|
||||||
|
"system-trace/core/services/groups"
|
||||||
|
"system-trace/core/services/users"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/swagger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initRouter(app *fiber.App) {
|
||||||
|
app.Get("/swagger/*", swagger.HandlerDefault)
|
||||||
|
v1 := app.Group("/v1")
|
||||||
|
{
|
||||||
|
|
||||||
|
v1.Get("/permissions", services.GetPermissions)
|
||||||
|
|
||||||
|
ag := v1.Group("/auth")
|
||||||
|
{
|
||||||
|
ag.Post("/login", auth.ReqTokensHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
gg := v1.Group("/groups")
|
||||||
|
{
|
||||||
|
gg.Get("", groups.GetGroupsHandler)
|
||||||
|
gg.Get("/:id", groups.GetGroupByIDHandler)
|
||||||
|
gg.Post("", groups.CreateGroupHandler)
|
||||||
|
gg.Patch("", groups.UpdateGroupHandler)
|
||||||
|
gg.Delete("/:id", groups.DeleteGroupHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
ug := v1.Group("/users")
|
||||||
|
{
|
||||||
|
ug.Get("", users.GetUsersHandler)
|
||||||
|
ug.Get("/:id", users.GetUserByIDHandler)
|
||||||
|
ug.Post("", users.CreateUserHandler)
|
||||||
|
ug.Patch("", users.UpdateUserHandler)
|
||||||
|
ug.Delete("/:id", users.DeleteUserHandler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
server.go
Normal file
58
server.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"system-trace/core/constants"
|
||||||
|
"system-trace/core/environment"
|
||||||
|
"system-trace/core/types"
|
||||||
|
|
||||||
|
"github.com/goccy/go-json"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/fiber/v2/middleware/cors"
|
||||||
|
"github.com/gofiber/fiber/v2/middleware/recover"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Instance *fiber.App
|
||||||
|
|
||||||
|
func serveApp() {
|
||||||
|
Instance = initServer()
|
||||||
|
Instance.Use(recover.New())
|
||||||
|
Instance.Use(cors.New())
|
||||||
|
// Instance.Use(middlewares.ValidateSession)
|
||||||
|
initRouter(Instance)
|
||||||
|
Instance.Use(func(c *fiber.Ctx) error {
|
||||||
|
return c.
|
||||||
|
Status(fiber.StatusNotFound).
|
||||||
|
JSON(types.JSONError{
|
||||||
|
Error: constants.NOT_FOUND,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
printRoutes(Instance)
|
||||||
|
Instance.Listen(":" + os.Getenv("APP_PORT"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func initServer() *fiber.App {
|
||||||
|
return fiber.New(fiber.Config{
|
||||||
|
JSONEncoder: json.Marshal,
|
||||||
|
JSONDecoder: json.Unmarshal,
|
||||||
|
CaseSensitive: true,
|
||||||
|
Prefork: true,
|
||||||
|
AppName: "System Trace API",
|
||||||
|
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func printRoutes(app *fiber.App) {
|
||||||
|
debug := environment.IsDebug()
|
||||||
|
|
||||||
|
if !fiber.IsChild() && debug {
|
||||||
|
data, _ := json.MarshalIndent(app.GetRoutes(true), "", " ")
|
||||||
|
fmt.Print(string(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,34 +2,41 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"system-trace/core/app/constants"
|
"system-trace/core/constants"
|
||||||
"system-trace/core/users"
|
"system-trace/core/database"
|
||||||
|
"system-trace/core/services/users"
|
||||||
|
"system-trace/core/types"
|
||||||
"system-trace/core/validators"
|
"system-trace/core/validators"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReqTokens godoc
|
// MARK: ReqTokens godoc
|
||||||
// @Summary Request pair of tokens
|
// @Summary Request pair of tokens
|
||||||
// @Description Returns pair of access and refresh tokens
|
// @Description Returns pair of access and refresh tokens
|
||||||
// @Tags auth
|
// @Tags auth
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param request body AuthBody true "Request body"
|
// @Param request body types.AuthBody true "Request body"
|
||||||
// @Header 200 {string} Token "accessToken=..."
|
// @Header 200 {string} Set-Cookie "accessToken=..."
|
||||||
// @Header 200 {string} Set-Cookie "refreshToken=..."
|
// @Header 200 {string} Set-Cookie "refreshToken=..."
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Router /auth/login [post]
|
// @Router /auth/login [post]
|
||||||
func ReqTokens(c *fiber.Ctx) error {
|
func ReqTokensHandler(c *fiber.Ctx) error {
|
||||||
ab := new(AuthBody)
|
ab := new(types.AuthBody)
|
||||||
if err := c.BodyParser(ab); err != nil {
|
if err := c.BodyParser(ab); err != nil {
|
||||||
return err
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
}
|
Error: err.Error(),
|
||||||
if err := validators.Validate(c, ab); err != nil {
|
})
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u, err := users.FindByEmailAndPassword(ab.Email, ab.Password)
|
if err := validators.Validate(c, ab); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := database.FindByEmailAndPassword(ab.Email, ab.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e := err.Error()
|
e := err.Error()
|
||||||
if e == "sql: no rows in result set" {
|
if e == "sql: no rows in result set" {
|
||||||
@ -37,17 +44,18 @@ func ReqTokens(c *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
return c.
|
return c.
|
||||||
Status(fiber.StatusBadRequest).
|
Status(fiber.StatusBadRequest).
|
||||||
JSON(fiber.Map{
|
JSON(types.JSONError{
|
||||||
"error": e,
|
Error: e,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if u != nil {
|
if u != nil {
|
||||||
err = GeneratePairAndSetCookie(c, u.ID)
|
err = GeneratePairAndSetCookie(c, u.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.
|
return c.
|
||||||
Status(fiber.StatusBadRequest).
|
Status(fiber.StatusBadRequest).
|
||||||
JSON(fiber.Map{
|
JSON(types.JSONError{
|
||||||
"error": err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,8 +63,8 @@ func ReqTokens(c *fiber.Ctx) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return c.
|
return c.
|
||||||
Status(fiber.StatusBadRequest).
|
Status(fiber.StatusBadRequest).
|
||||||
JSON(fiber.Map{
|
JSON(types.JSONError{
|
||||||
"error": err.Error(),
|
Error: err.Error(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return c.SendStatus(fiber.StatusOK)
|
return c.SendStatus(fiber.StatusOK)
|
||||||
@ -75,7 +83,7 @@ func GeneratePairAndSetCookie(c *fiber.Ctx, id int32) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setCookie(c *fiber.Ctx, p *PairTokens) {
|
func setCookie(c *fiber.Ctx, p *types.PairTokens) {
|
||||||
// Access token
|
// Access token
|
||||||
atc := new(fiber.Cookie)
|
atc := new(fiber.Cookie)
|
||||||
atc.Name = "accessToken"
|
atc.Name = "accessToken"
|
||||||
@ -2,7 +2,9 @@ package auth
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"system-trace/core/app/constants"
|
"system-trace/core/constants"
|
||||||
|
"system-trace/core/database"
|
||||||
|
"system-trace/core/types"
|
||||||
"system-trace/core/utils"
|
"system-trace/core/utils"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -14,18 +16,18 @@ const (
|
|||||||
RefreshTokenLifetime int8 = 24
|
RefreshTokenLifetime int8 = 24
|
||||||
)
|
)
|
||||||
|
|
||||||
func genPair(id int32) (*PairTokens, error) {
|
func genPair(id int32) (*types.PairTokens, error) {
|
||||||
at, rt, err := genTokens(id)
|
at, rt, err := genTokens(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = insertPair(id, at, rt)
|
err = database.InsertPairOfTokens(id, at, rt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
p := PairTokens{
|
p := types.PairTokens{
|
||||||
AccessToken: at,
|
AccessToken: at,
|
||||||
RefreshToken: rt,
|
RefreshToken: rt,
|
||||||
}
|
}
|
||||||
160
services/groups/groups.go
Normal file
160
services/groups/groups.go
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
package groups
|
||||||
|
|
||||||
|
import (
|
||||||
|
"system-trace/core/database"
|
||||||
|
"system-trace/core/parsers"
|
||||||
|
"system-trace/core/types"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MARK: GetGroups godoc
|
||||||
|
// @Summary Get groups (with pagination)
|
||||||
|
// @Description Returns array of groups and count
|
||||||
|
// @Tags groups
|
||||||
|
// @Produce json
|
||||||
|
// @Param count query int true "Count of rows" minimum(10) maximum(100)
|
||||||
|
// @Param offset query int true "Rows to skip" minumum(0)
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200 {object} types.JSONPagination
|
||||||
|
// @Router /groups [get]
|
||||||
|
func GetGroupsHandler(c *fiber.Ctx) error {
|
||||||
|
// TODO permission validate
|
||||||
|
p, err := parsers.ParsePagination(c)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ob, err := parsers.ParseOrder(c)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
groups, cursor, err := database.FindGroups(p, ob)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(types.JSONPagination{
|
||||||
|
Data: groups,
|
||||||
|
Cursor: cursor,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: GetGroupByID godoc
|
||||||
|
// @Summary Get group by ID
|
||||||
|
// @Description Returns group instance
|
||||||
|
// @Tags groups
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Group ID" minimum(1)
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200 {object} database.Group
|
||||||
|
// @Router /groups/:id [get]
|
||||||
|
func GetGroupByIDHandler(c *fiber.Ctx) error {
|
||||||
|
// TODO permission validate
|
||||||
|
id, err := c.ParamsInt("id")
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
group, err := database.FindGroupByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(group)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: CreateGroup godoc
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description Create group with specified data
|
||||||
|
// @Tags groups
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body database.Group true "Request body"
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200
|
||||||
|
// @Router /groups [post]
|
||||||
|
func CreateGroupHandler(c *fiber.Ctx) error {
|
||||||
|
// TODO permission validate
|
||||||
|
g := new(database.Group)
|
||||||
|
if err := c.BodyParser(g); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
err := database.InsertGroup(g)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: UpdateGroup godoc
|
||||||
|
// @Summary Update group
|
||||||
|
// @Description Update group with specified data
|
||||||
|
// @Tags groups
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body database.Group true "Request body"
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200
|
||||||
|
// @Router /groups [patch]
|
||||||
|
func UpdateGroupHandler(c *fiber.Ctx) error {
|
||||||
|
// TODO permission validate
|
||||||
|
g := new(database.Group)
|
||||||
|
if err := c.BodyParser(g); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
err := database.UpdateGroup(g, []string{"*"})
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: DeleteGroup godoc
|
||||||
|
// @Summary Delete group
|
||||||
|
// @Description Delete group by ID
|
||||||
|
// @Tags groups
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "Group ID" minimum(1)
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200
|
||||||
|
// @Router /groups/:id [delete]
|
||||||
|
func DeleteGroupHandler(c *fiber.Ctx) error {
|
||||||
|
// TODO permission validate
|
||||||
|
id, err := c.ParamsInt("id")
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
err = database.DeleteGroup(id)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
||||||
18
services/misc.go
Normal file
18
services/misc.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"system-trace/core/constants/permissions"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MARK: GetPermissions godoc
|
||||||
|
// @Summary Get list of permissions
|
||||||
|
// @Description Returns key-value map with permissions
|
||||||
|
// @Produce json
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200 {object} map[string]int8
|
||||||
|
// @Router /permissions [get]
|
||||||
|
func GetPermissions(c *fiber.Ctx) error {
|
||||||
|
return c.Status(fiber.StatusOK).JSON(permissions.All)
|
||||||
|
}
|
||||||
166
services/users/users.go
Normal file
166
services/users/users.go
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
package users
|
||||||
|
|
||||||
|
import (
|
||||||
|
"system-trace/core/database"
|
||||||
|
"system-trace/core/parsers"
|
||||||
|
"system-trace/core/types"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MARK: GetUsers godoc
|
||||||
|
// @Summary Get users (with pagination)
|
||||||
|
// @Description Returns array of users and count
|
||||||
|
// @Tags users
|
||||||
|
// @Produce json
|
||||||
|
// @Param count query int true "Count of rows" minimum(10) maximum(100)
|
||||||
|
// @Param offset query int true "Rows to skip" minumum(0)
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200 {object} types.JSONPagination
|
||||||
|
// @Router /users [get]
|
||||||
|
func GetUsersHandler(c *fiber.Ctx) error {
|
||||||
|
// TODO permission validate
|
||||||
|
p, err := parsers.ParsePagination(c)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ob, err := parsers.ParseOrder(c)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
users, cursor, err := database.FindUsers(p, ob)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(types.JSONPagination{
|
||||||
|
Data: users,
|
||||||
|
Cursor: cursor,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: GetUserByID godoc
|
||||||
|
// @Summary Get user by ID
|
||||||
|
// @Description Returns user instance
|
||||||
|
// @Tags users
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "User ID" minimum(1)
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200 {object} database.User
|
||||||
|
// @Router /users/:id [get]
|
||||||
|
func GetUserByIDHandler(c *fiber.Ctx) error {
|
||||||
|
// TODO permission validate
|
||||||
|
id, err := c.ParamsInt("id")
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := database.FindUserByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Status(fiber.StatusOK).JSON(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: CreateUser godoc
|
||||||
|
// @Summary Create user
|
||||||
|
// @Description Create user with specified data
|
||||||
|
// @Tags users
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body database.User true "Request body"
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200
|
||||||
|
// @Router /users [post]
|
||||||
|
func CreateUserHandler(c *fiber.Ctx) error {
|
||||||
|
// TODO permission validate
|
||||||
|
u := new(database.User)
|
||||||
|
if err := c.BodyParser(u); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
err := database.InsertUser(u)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: UpdateUser godoc
|
||||||
|
// @Summary Update user
|
||||||
|
// @Description Update user with specified data
|
||||||
|
// @Tags users
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body database.User true "Request body"
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200
|
||||||
|
// @Router /users [patch]
|
||||||
|
func UpdateUserHandler(c *fiber.Ctx) error {
|
||||||
|
// TODO permission validate
|
||||||
|
u := new(database.User)
|
||||||
|
if err := c.BodyParser(u); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
err := database.UpdateUser(u, []string{"*"})
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: DeleteUser godoc
|
||||||
|
// @Summary Delete user
|
||||||
|
// @Description Delete user by ID
|
||||||
|
// @Tags users
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int true "User ID" minimum(1)
|
||||||
|
// @Header 200 {string} Token "accessToken=...;refreshToken=..."
|
||||||
|
// @Success 200
|
||||||
|
// @Router /users/:id [delete]
|
||||||
|
func DeleteUserHandler(c *fiber.Ctx) error {
|
||||||
|
// TODO permission validate
|
||||||
|
id, err := c.ParamsInt("id")
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
err = database.DeleteUser(id)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(types.JSONError{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetLoginTime(u *database.User) error {
|
||||||
|
u.LastLogin = time.Now()
|
||||||
|
return database.UpdateUser(u, []string{"last_login"})
|
||||||
|
}
|
||||||
6
types/order_by.go
Normal file
6
types/order_by.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type OrderBy struct {
|
||||||
|
Key string `validate:"required"`
|
||||||
|
Order string `validate:"required,endswith=sc"`
|
||||||
|
}
|
||||||
13
types/pagination.go
Normal file
13
types/pagination.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type Pagination struct {
|
||||||
|
Count int `query:"count" validate:"required,min=10,max=100"`
|
||||||
|
Page int `query:"page" validate:"required,min=1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cursor struct {
|
||||||
|
Count int `json:"count"`
|
||||||
|
CurrentPage int `json:"currentPage"`
|
||||||
|
TotalPages float64 `json:"totalPages"`
|
||||||
|
TotalRows float64 `json:"totalRows"`
|
||||||
|
}
|
||||||
10
types/response.go
Normal file
10
types/response.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
type JSONPagination struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
Cursor *Cursor `json:"cursor"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type JSONError struct {
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package auth
|
package types
|
||||||
|
|
||||||
type PairTokens struct {
|
type PairTokens struct {
|
||||||
AccessToken string `json:"accessToken" cookie:"accessToken"`
|
AccessToken string `json:"accessToken" cookie:"accessToken"`
|
||||||
32
users/sql.go
32
users/sql.go
@ -1,32 +0,0 @@
|
|||||||
package users
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"system-trace/core/database"
|
|
||||||
"system-trace/core/database/entities"
|
|
||||||
"system-trace/core/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func FindByEmailAndPassword(email, password string) (*entities.User, error) {
|
|
||||||
passwordHash := utils.SHA256(password)
|
|
||||||
ctx := context.Background()
|
|
||||||
u := new(entities.User)
|
|
||||||
err := database.PG.NewSelect().
|
|
||||||
Model(u).
|
|
||||||
Where("email = ?", email).
|
|
||||||
Where("password_hash = ?", passwordHash).
|
|
||||||
Scan(ctx)
|
|
||||||
|
|
||||||
return u, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateUser(u *entities.User, cols []string) error {
|
|
||||||
ctx := context.Background()
|
|
||||||
_, err := database.PG.NewUpdate().
|
|
||||||
Model(u).
|
|
||||||
Column(cols...).
|
|
||||||
WherePK().
|
|
||||||
Exec(ctx)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
package users
|
|
||||||
|
|
||||||
import (
|
|
||||||
"system-trace/core/database/entities"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Get(c *fiber.Ctx) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetLoginTime(u *entities.User) error {
|
|
||||||
u.LastLogin = time.Now()
|
|
||||||
return UpdateUser(u, []string{"last_login"})
|
|
||||||
}
|
|
||||||
@ -36,7 +36,7 @@ func Validate(c *fiber.Ctx, data interface{}) error {
|
|||||||
|
|
||||||
for _, err := range errs {
|
for _, err := range errs {
|
||||||
errMsgs = append(errMsgs, fmt.Sprintf(
|
errMsgs = append(errMsgs, fmt.Sprintf(
|
||||||
"field '%s' needs to implement '%s' rule",
|
"validator:'%s'/'%s'",
|
||||||
err.FailedField,
|
err.FailedField,
|
||||||
err.Tag,
|
err.Tag,
|
||||||
))
|
))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user