forked from mirrors/homebox
switch to zero log
This commit is contained in:
parent
9351b3fd42
commit
68204a4f22
26 changed files with 122 additions and 1335 deletions
|
@ -7,14 +7,12 @@ import (
|
|||
"github.com/hay-kot/content/backend/internal/config"
|
||||
"github.com/hay-kot/content/backend/internal/repo"
|
||||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
"github.com/hay-kot/content/backend/pkgs/mailer"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
)
|
||||
|
||||
type app struct {
|
||||
conf *config.Config
|
||||
logger *logger.Logger
|
||||
mailer mailer.Mailer
|
||||
db *ent.Client
|
||||
server *server.Server
|
||||
|
|
|
@ -4,20 +4,17 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/hay-kot/content/backend/internal/types"
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
)
|
||||
|
||||
type ReadyFunc func() bool
|
||||
|
||||
type BaseController struct {
|
||||
log *logger.Logger
|
||||
svr *server.Server
|
||||
}
|
||||
|
||||
func NewBaseController(log *logger.Logger, svr *server.Server) *BaseController {
|
||||
func NewBaseController(svr *server.Server) *BaseController {
|
||||
h := &BaseController{
|
||||
log: log,
|
||||
svr: svr,
|
||||
}
|
||||
return h
|
||||
|
|
|
@ -4,12 +4,10 @@ import (
|
|||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/hay-kot/content/backend/internal/mocks"
|
||||
)
|
||||
|
||||
func GetTestHandler(t *testing.T) *BaseController {
|
||||
return NewBaseController(mocks.GetStructLogger(), nil)
|
||||
return NewBaseController(nil)
|
||||
}
|
||||
|
||||
func TestHandlersv1_HandleBase(t *testing.T) {
|
||||
|
|
|
@ -52,215 +52,6 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/v1/admin/users": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Admin: Users"
|
||||
],
|
||||
"summary": "Gets all users from the database",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/server.Result"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ent.User"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Admin: Users"
|
||||
],
|
||||
"summary": "Create a new user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "User Data",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.UserCreate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/server.Result"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"$ref": "#/definitions/ent.User"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/admin/users/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Admin: Users"
|
||||
],
|
||||
"summary": "Get a user from the database",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/server.Result"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"$ref": "#/definitions/ent.User"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Admin: Users"
|
||||
],
|
||||
"summary": "Update a User",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "User Data",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.UserUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/server.Result"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"$ref": "#/definitions/ent.User"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Admin: Users"
|
||||
],
|
||||
"summary": "Delete a User",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/items": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
@ -1643,9 +1434,6 @@ const docTemplate = `{
|
|||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"groupId": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -1680,9 +1468,6 @@ const docTemplate = `{
|
|||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"groupId": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -1709,9 +1494,6 @@ const docTemplate = `{
|
|||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"groupId": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -1734,26 +1516,6 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"types.UserCreate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"groupID": {
|
||||
"type": "string"
|
||||
},
|
||||
"isSuperuser": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.UserIn": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -44,215 +44,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/v1/admin/users": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Admin: Users"
|
||||
],
|
||||
"summary": "Gets all users from the database",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/server.Result"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ent.User"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Admin: Users"
|
||||
],
|
||||
"summary": "Create a new user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "User Data",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.UserCreate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/server.Result"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"$ref": "#/definitions/ent.User"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/admin/users/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Admin: Users"
|
||||
],
|
||||
"summary": "Get a user from the database",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/server.Result"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"$ref": "#/definitions/ent.User"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Admin: Users"
|
||||
],
|
||||
"summary": "Update a User",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "User Data",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/types.UserUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/server.Result"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"item": {
|
||||
"$ref": "#/definitions/ent.User"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Admin: Users"
|
||||
],
|
||||
"summary": "Delete a User",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"204": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/items": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
@ -1635,9 +1426,6 @@
|
|||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"groupId": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -1672,9 +1460,6 @@
|
|||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"groupId": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -1701,9 +1486,6 @@
|
|||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"groupId": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -1726,26 +1508,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"types.UserCreate": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"groupID": {
|
||||
"type": "string"
|
||||
},
|
||||
"isSuperuser": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types.UserIn": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
|
@ -493,8 +493,6 @@ definitions:
|
|||
type: string
|
||||
description:
|
||||
type: string
|
||||
groupId:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
itemCount:
|
||||
|
@ -517,8 +515,6 @@ definitions:
|
|||
type: string
|
||||
description:
|
||||
type: string
|
||||
groupId:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
items:
|
||||
|
@ -536,8 +532,6 @@ definitions:
|
|||
type: string
|
||||
description:
|
||||
type: string
|
||||
groupId:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
|
@ -552,19 +546,6 @@ definitions:
|
|||
token:
|
||||
type: string
|
||||
type: object
|
||||
types.UserCreate:
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
groupID:
|
||||
type: string
|
||||
isSuperuser:
|
||||
type: boolean
|
||||
name:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
type: object
|
||||
types.UserIn:
|
||||
properties:
|
||||
email:
|
||||
|
@ -616,124 +597,6 @@ paths:
|
|||
summary: Retrieves the basic information about the API
|
||||
tags:
|
||||
- Base
|
||||
/v1/admin/users:
|
||||
get:
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/server.Result'
|
||||
- properties:
|
||||
item:
|
||||
items:
|
||||
$ref: '#/definitions/ent.User'
|
||||
type: array
|
||||
type: object
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Gets all users from the database
|
||||
tags:
|
||||
- 'Admin: Users'
|
||||
post:
|
||||
parameters:
|
||||
- description: User Data
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/types.UserCreate'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/server.Result'
|
||||
- properties:
|
||||
item:
|
||||
$ref: '#/definitions/ent.User'
|
||||
type: object
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Create a new user
|
||||
tags:
|
||||
- 'Admin: Users'
|
||||
/v1/admin/users/{id}:
|
||||
delete:
|
||||
parameters:
|
||||
- description: User ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"204":
|
||||
description: ""
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Delete a User
|
||||
tags:
|
||||
- 'Admin: Users'
|
||||
get:
|
||||
parameters:
|
||||
- description: User ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/server.Result'
|
||||
- properties:
|
||||
item:
|
||||
$ref: '#/definitions/ent.User'
|
||||
type: object
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Get a user from the database
|
||||
tags:
|
||||
- 'Admin: Users'
|
||||
put:
|
||||
parameters:
|
||||
- description: User ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: User Data
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/types.UserUpdate'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/server.Result'
|
||||
- properties:
|
||||
item:
|
||||
$ref: '#/definitions/ent.User'
|
||||
type: object
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Update a User
|
||||
tags:
|
||||
- 'Admin: Users'
|
||||
/v1/items:
|
||||
get:
|
||||
produces:
|
||||
|
|
|
@ -2,8 +2,6 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
|
@ -12,9 +10,10 @@ import (
|
|||
"github.com/hay-kot/content/backend/internal/config"
|
||||
"github.com/hay-kot/content/backend/internal/repo"
|
||||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// @title Go API Templates
|
||||
|
@ -28,6 +27,10 @@ import (
|
|||
// @name Authorization
|
||||
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
|
||||
func main() {
|
||||
// Logger Init
|
||||
// zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
||||
cfgFile := "config.yml"
|
||||
|
||||
cfg, err := config.NewConfig(cfgFile)
|
||||
|
@ -45,42 +48,24 @@ func main() {
|
|||
func run(cfg *config.Config) error {
|
||||
app := NewApp(cfg)
|
||||
|
||||
// =========================================================================
|
||||
// Setup Logger
|
||||
|
||||
var wrt io.Writer
|
||||
wrt = os.Stdout
|
||||
if app.conf.Log.File != "" {
|
||||
f, err := os.OpenFile(app.conf.Log.File, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||
if err != nil {
|
||||
log.Fatalf("error opening file: %v", err)
|
||||
}
|
||||
defer func(f *os.File) {
|
||||
_ = f.Close()
|
||||
}(f)
|
||||
wrt = io.MultiWriter(wrt, f)
|
||||
}
|
||||
|
||||
app.logger = logger.New(wrt, logger.LevelDebug)
|
||||
|
||||
// =========================================================================
|
||||
// Initialize Database & Repos
|
||||
|
||||
c, err := ent.Open(cfg.Database.GetDriver(), cfg.Database.GetUrl())
|
||||
if err != nil {
|
||||
app.logger.Fatal(err, logger.Props{
|
||||
"details": "failed to connect to database",
|
||||
"database": cfg.Database.GetDriver(),
|
||||
"url": cfg.Database.GetUrl(),
|
||||
})
|
||||
log.Fatal().
|
||||
Err(err).
|
||||
Str("driver", cfg.Database.GetDriver()).
|
||||
Str("url", cfg.Database.GetUrl()).
|
||||
Msg("failed opening connection to sqlite")
|
||||
}
|
||||
defer func(c *ent.Client) {
|
||||
_ = c.Close()
|
||||
}(c)
|
||||
if err := c.Schema.Create(context.Background()); err != nil {
|
||||
app.logger.Fatal(err, logger.Props{
|
||||
"details": "failed to create schema",
|
||||
})
|
||||
log.Fatal().
|
||||
Err(err).
|
||||
Msg("failed creating schema resources")
|
||||
}
|
||||
|
||||
app.db = c
|
||||
|
@ -99,10 +84,7 @@ func run(cfg *config.Config) error {
|
|||
|
||||
app.SeedDatabase(app.repos)
|
||||
|
||||
app.logger.Info("Starting HTTP Server", logger.Props{
|
||||
"host": app.server.Host,
|
||||
"port": app.server.Port,
|
||||
})
|
||||
log.Info().Msgf("Starting HTTP Server on %s:%s", app.server.Host, app.server.Port)
|
||||
|
||||
// =========================================================================
|
||||
// Start Reoccurring Tasks
|
||||
|
@ -110,9 +92,9 @@ func run(cfg *config.Config) error {
|
|||
go app.StartReoccurringTasks(time.Duration(24)*time.Hour, func() {
|
||||
_, err := app.repos.AuthTokens.PurgeExpiredTokens(context.Background())
|
||||
if err != nil {
|
||||
app.logger.Error(err, logger.Props{
|
||||
"details": "failed to purge expired tokens",
|
||||
})
|
||||
log.Error().
|
||||
Err(err).
|
||||
Msg("failed to purge expired tokens")
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ import (
|
|||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/hay-kot/content/backend/internal/config"
|
||||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (a *app) setGlobalMiddleware(r *chi.Mux) {
|
||||
|
@ -24,7 +24,7 @@ func (a *app) setGlobalMiddleware(r *chi.Mux) {
|
|||
// Use struct logger in production for requests, but use
|
||||
// pretty console logger in development.
|
||||
if a.conf.Mode == config.ModeDevelopment {
|
||||
r.Use(middleware.Logger)
|
||||
r.Use(a.mwSummaryLogger)
|
||||
} else {
|
||||
r.Use(a.mwStructLogger)
|
||||
}
|
||||
|
@ -98,13 +98,38 @@ func (a *app) mwStructLogger(next http.Handler) http.Handler {
|
|||
|
||||
url := fmt.Sprintf("%s://%s%s %s", scheme, r.Host, r.RequestURI, r.Proto)
|
||||
|
||||
a.logger.Info(fmt.Sprintf("[%s] %s", r.Method, url), logger.Props{
|
||||
"id": middleware.GetReqID(r.Context()),
|
||||
"method": r.Method,
|
||||
"url": url,
|
||||
"remote": r.RemoteAddr,
|
||||
})
|
||||
|
||||
log.Info().
|
||||
Str("id", middleware.GetReqID(r.Context())).
|
||||
Str("url", url).
|
||||
Str("method", r.Method).
|
||||
Str("remote_addr", r.RemoteAddr).
|
||||
Msgf("[%s] %s", r.Method, url)
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *app) mwSummaryLogger(next http.Handler) http.Handler {
|
||||
bold := func(s string) string {
|
||||
return "\033[1m" + s + "\033[0m"
|
||||
}
|
||||
|
||||
pink := func(s string) string {
|
||||
return "\033[35m" + s + "\033[0m"
|
||||
}
|
||||
|
||||
aqua := func(s string) string {
|
||||
return "\033[36m" + s + "\033[0m"
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("%s://%s%s %s", scheme, r.Host, r.RequestURI, r.Proto)
|
||||
|
||||
log.Info().Msgf("%s %s", bold(pink("["+r.Method+"]")), aqua(url))
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux {
|
|||
http.ServeFile(w, r, "static/favicon.ico")
|
||||
})
|
||||
|
||||
baseHandler := base.NewBaseController(a.logger, a.server)
|
||||
baseHandler := base.NewBaseController(a.server)
|
||||
r.Get(prefix+"/status", baseHandler.HandleBase(func() bool { return true }, "v1"))
|
||||
|
||||
// =========================================================================
|
||||
|
@ -39,7 +39,7 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux {
|
|||
|
||||
v1Base := v1.BaseUrlFunc(prefix)
|
||||
{
|
||||
v1Handlers := v1.NewControllerV1(a.logger, a.services)
|
||||
v1Handlers := v1.NewControllerV1(a.services)
|
||||
r.Post(v1Base("/users/register"), v1Handlers.HandleUserRegistration())
|
||||
r.Post(v1Base("/users/login"), v1Handlers.HandleAuthLogin())
|
||||
r.Group(func(r chi.Router) {
|
||||
|
@ -68,15 +68,6 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux {
|
|||
r.Put(v1Base("/items/{id}"), v1Handlers.HandleItemUpdate())
|
||||
r.Delete(v1Base("/items/{id}"), v1Handlers.HandleItemDelete())
|
||||
})
|
||||
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(a.mwAdminOnly)
|
||||
r.Get(v1Base("/admin/users"), v1Handlers.HandleAdminUserGetAll())
|
||||
r.Post(v1Base("/admin/users"), v1Handlers.HandleAdminUserCreate())
|
||||
r.Get(v1Base("/admin/users/{id}"), v1Handlers.HandleAdminUserGet())
|
||||
r.Put(v1Base("/admin/users/{id}"), v1Handlers.HandleAdminUserUpdate())
|
||||
r.Delete(v1Base("/admin/users/{id}"), v1Handlers.HandleAdminUserDelete())
|
||||
})
|
||||
}
|
||||
|
||||
return r
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/hay-kot/content/backend/internal/repo"
|
||||
"github.com/hay-kot/content/backend/internal/types"
|
||||
"github.com/hay-kot/content/backend/pkgs/hasher"
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -23,7 +23,7 @@ func (a *app) EnsureAdministrator() {
|
|||
superusers, err := a.repos.Users.GetSuperusers(context.Background())
|
||||
|
||||
if err != nil {
|
||||
a.logger.Fatal(err, nil)
|
||||
log.Fatal().Err(err).Msg("failed to get superusers")
|
||||
}
|
||||
if len(superusers) > 0 {
|
||||
return
|
||||
|
@ -37,15 +37,15 @@ func (a *app) EnsureAdministrator() {
|
|||
Password: pw,
|
||||
}
|
||||
|
||||
a.logger.Info("creating default superuser", logger.Props{
|
||||
"name": newSuperUser.Name,
|
||||
"email": newSuperUser.Email,
|
||||
})
|
||||
log.Info().
|
||||
Str("name", newSuperUser.Name).
|
||||
Str("email", newSuperUser.Email).
|
||||
Msg("no superusers found, creating default superuser")
|
||||
|
||||
_, err = a.repos.Users.Create(context.Background(), newSuperUser)
|
||||
|
||||
if err != nil {
|
||||
a.logger.Fatal(err, nil)
|
||||
log.Fatal().Err(err).Msg("failed to create default superuser")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ func (a *app) SeedDatabase(repos *repo.AllRepos) {
|
|||
|
||||
group, err := repos.Groups.Create(context.Background(), DefaultGroup)
|
||||
if err != nil {
|
||||
a.logger.Fatal(err, nil)
|
||||
log.Fatal().Err(err).Msg("failed to create default group")
|
||||
}
|
||||
|
||||
for _, user := range a.conf.Seed.Users {
|
||||
|
@ -66,19 +66,13 @@ func (a *app) SeedDatabase(repos *repo.AllRepos) {
|
|||
usr, _ := repos.Users.GetOneEmail(context.Background(), user.Email)
|
||||
|
||||
if usr.ID != uuid.Nil {
|
||||
a.logger.Info("seed user already exists", logger.Props{
|
||||
"user": user.Name,
|
||||
})
|
||||
log.Info().Str("email", user.Email).Msg("user already exists, skipping")
|
||||
continue
|
||||
}
|
||||
|
||||
hashedPw, err := hasher.HashPassword(user.Password)
|
||||
|
||||
if err != nil {
|
||||
a.logger.Error(err, logger.Props{
|
||||
"details": "failed to hash password",
|
||||
"user": user.Name,
|
||||
})
|
||||
log.Fatal().Err(err).Msg("failed to hash password")
|
||||
}
|
||||
|
||||
_, err = repos.Users.Create(context.Background(), types.UserCreate{
|
||||
|
@ -90,14 +84,9 @@ func (a *app) SeedDatabase(repos *repo.AllRepos) {
|
|||
})
|
||||
|
||||
if err != nil {
|
||||
a.logger.Error(err, logger.Props{
|
||||
"details": "failed to create seed user",
|
||||
"name": user.Name,
|
||||
})
|
||||
log.Fatal().Err(err).Msg("failed to create user")
|
||||
}
|
||||
|
||||
a.logger.Info("creating seed user", logger.Props{
|
||||
"name": user.Name,
|
||||
})
|
||||
log.Info().Str("email", user.Email).Msg("created user")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,9 @@ package v1
|
|||
|
||||
import (
|
||||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
)
|
||||
|
||||
type V1Controller struct {
|
||||
log *logger.Logger
|
||||
svc *services.AllServices
|
||||
}
|
||||
|
||||
|
@ -19,9 +17,8 @@ func BaseUrlFunc(prefix string) func(s string) string {
|
|||
return prefixFunc
|
||||
}
|
||||
|
||||
func NewControllerV1(log *logger.Logger, svc *services.AllServices) *V1Controller {
|
||||
func NewControllerV1(svc *services.AllServices) *V1Controller {
|
||||
ctrl := &V1Controller{
|
||||
log: log,
|
||||
svc: svc,
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,10 @@ import (
|
|||
func Test_NewHandlerV1(t *testing.T) {
|
||||
|
||||
v1Base := BaseUrlFunc("/testing/v1")
|
||||
ctrl := NewControllerV1(mockHandler.log, mockHandler.svc)
|
||||
ctrl := NewControllerV1(mockHandler.svc)
|
||||
|
||||
assert.NotNil(t, ctrl)
|
||||
|
||||
assert.Equal(t, ctrl.log, mockHandler.log)
|
||||
|
||||
assert.Equal(t, "/testing/v1/v1/abc123", v1Base("/abc123"))
|
||||
assert.Equal(t, "/testing/v1/v1/abc123", v1Base("/abc123"))
|
||||
}
|
||||
|
|
|
@ -39,7 +39,6 @@ func userPool() func() {
|
|||
|
||||
func TestMain(m *testing.M) {
|
||||
// Set Handler Vars
|
||||
mockHandler.log = mocks.GetStructLogger()
|
||||
repos, closeDb := mocks.GetEntRepos()
|
||||
mockHandler.svc = mocks.GetMockServices(repos)
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/internal/types"
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
/*
|
||||
|
@ -24,9 +24,7 @@ and makes it a little more consistent when error handling and logging.
|
|||
func (ctrl *V1Controller) partialParseIdAndUser(w http.ResponseWriter, r *http.Request) (uuid.UUID, *types.UserOut, error) {
|
||||
uid, err := uuid.Parse(chi.URLParam(r, "id"))
|
||||
if err != nil {
|
||||
ctrl.log.Debug(err.Error(), logger.Props{
|
||||
"details": "failed to convert id to valid UUID",
|
||||
})
|
||||
log.Err(err).Msg("failed to parse id")
|
||||
server.RespondError(w, http.StatusBadRequest, err)
|
||||
return uuid.Nil, nil, err
|
||||
}
|
||||
|
|
|
@ -1,207 +0,0 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/internal/types"
|
||||
"github.com/hay-kot/content/backend/pkgs/hasher"
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
)
|
||||
|
||||
// HandleAdminUserGetAll godoc
|
||||
// @Summary Gets all users from the database
|
||||
// @Tags Admin: Users
|
||||
// @Produce json
|
||||
// @Success 200 {object} server.Result{item=[]ent.User}
|
||||
// @Router /v1/admin/users [get]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAdminUserGetAll() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
users, err := ctrl.svc.Admin.GetAll(r.Context())
|
||||
|
||||
if err != nil {
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
server.Respond(w, http.StatusOK, server.Wrap(users))
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAdminUserGet godoc
|
||||
// @Summary Get a user from the database
|
||||
// @Tags Admin: Users
|
||||
// @Produce json
|
||||
// @Param id path string true "User ID"
|
||||
// @Success 200 {object} server.Result{item=ent.User}
|
||||
// @Router /v1/admin/users/{id} [get]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAdminUserGet() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
uid, err := uuid.Parse(chi.URLParam(r, "id"))
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Debug(err.Error(), logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to convert id to valid UUID",
|
||||
})
|
||||
server.RespondError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := ctrl.svc.Admin.GetByID(r.Context(), uid)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
server.Respond(w, http.StatusOK, server.Wrap(user))
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAdminUserCreate godoc
|
||||
// @Summary Create a new user
|
||||
// @Tags Admin: Users
|
||||
// @Produce json
|
||||
// @Param payload body types.UserCreate true "User Data"
|
||||
// @Success 200 {object} server.Result{item=ent.User}
|
||||
// @Router /v1/admin/users [POST]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAdminUserCreate() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
createData := types.UserCreate{}
|
||||
|
||||
if err := server.Decode(r, &createData); err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to decode user create data",
|
||||
})
|
||||
server.RespondError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
err := createData.Validate()
|
||||
|
||||
if err != nil {
|
||||
server.RespondError(w, http.StatusUnprocessableEntity, err)
|
||||
return
|
||||
}
|
||||
|
||||
hashedPw, err := hasher.HashPassword(createData.Password)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to hash password",
|
||||
})
|
||||
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
createData.Password = hashedPw
|
||||
userOut, err := ctrl.svc.Admin.Create(r.Context(), createData)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to create user",
|
||||
})
|
||||
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
server.Respond(w, http.StatusCreated, server.Wrap(userOut))
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAdminUserUpdate godoc
|
||||
// @Summary Update a User
|
||||
// @Tags Admin: Users
|
||||
// @Param id path string true "User ID"
|
||||
// @Param payload body types.UserUpdate true "User Data"
|
||||
// @Produce json
|
||||
// @Success 200 {object} server.Result{item=ent.User}
|
||||
// @Router /v1/admin/users/{id} [PUT]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAdminUserUpdate() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
uid, err := uuid.Parse(chi.URLParam(r, "id"))
|
||||
if err != nil {
|
||||
ctrl.log.Debug(err.Error(), logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to convert id to valid UUID",
|
||||
})
|
||||
}
|
||||
|
||||
updateData := types.UserUpdate{}
|
||||
|
||||
if err := server.Decode(r, &updateData); err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to decode user update data",
|
||||
})
|
||||
server.RespondError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
newData, err := ctrl.svc.Admin.UpdateProperties(r.Context(), uid, updateData)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to update user",
|
||||
})
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
server.Respond(w, http.StatusOK, server.Wrap(newData))
|
||||
}
|
||||
}
|
||||
|
||||
// HandleAdminUserDelete godoc
|
||||
// @Summary Delete a User
|
||||
// @Tags Admin: Users
|
||||
// @Param id path string true "User ID"
|
||||
// @Produce json
|
||||
// @Success 204
|
||||
// @Router /v1/admin/users/{id} [DELETE]
|
||||
// @Security Bearer
|
||||
func (ctrl *V1Controller) HandleAdminUserDelete() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
uid, err := uuid.Parse(chi.URLParam(r, "id"))
|
||||
if err != nil {
|
||||
ctrl.log.Debug(err.Error(), logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to convert id to valid UUID",
|
||||
})
|
||||
}
|
||||
|
||||
actor := services.UseUserCtx(r.Context())
|
||||
|
||||
if actor.ID == uid {
|
||||
server.RespondError(w, http.StatusBadRequest, errors.New("cannot delete yourself"))
|
||||
return
|
||||
}
|
||||
|
||||
err = ctrl.svc.Admin.Delete(r.Context(), uid)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "admin",
|
||||
"details": "failed to delete user",
|
||||
})
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/hay-kot/content/backend/ent"
|
||||
"github.com/hay-kot/content/backend/internal/mocks/chimocker"
|
||||
"github.com/hay-kot/content/backend/internal/mocks/factories"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
const (
|
||||
UrlUser = "/api/v1/admin/users"
|
||||
UrlUserId = "/api/v1/admin/users/%v"
|
||||
UrlUserIdChi = "/api/v1/admin/users/{id}"
|
||||
)
|
||||
|
||||
type usersResponse struct {
|
||||
Users []*ent.User `json:"item"`
|
||||
}
|
||||
|
||||
type userResponse struct {
|
||||
User *ent.User `json:"item"`
|
||||
}
|
||||
|
||||
func Test_HandleAdminUserGetAll_Success(t *testing.T) {
|
||||
r := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, UrlUser, nil)
|
||||
|
||||
mockHandler.HandleAdminUserGetAll()(r, req)
|
||||
|
||||
response := usersResponse{
|
||||
Users: []*ent.User{},
|
||||
}
|
||||
|
||||
_ = json.Unmarshal(r.Body.Bytes(), &response)
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
assert.Equal(t, len(users), len(response.Users))
|
||||
|
||||
knowEmail := []string{
|
||||
users[0].Email,
|
||||
users[1].Email,
|
||||
users[2].Email,
|
||||
users[3].Email,
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
assert.Contains(t, knowEmail, user.Email)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func Test_HandleAdminUserGet_Success(t *testing.T) {
|
||||
targetUser := users[2]
|
||||
res := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, fmt.Sprintf(UrlUserId, targetUser.ID), nil)
|
||||
|
||||
req = chimocker.WithUrlParam(req, "id", fmt.Sprintf("%v", targetUser.ID))
|
||||
|
||||
mockHandler.HandleAdminUserGet()(res, req)
|
||||
assert.Equal(t, http.StatusOK, res.Code)
|
||||
|
||||
response := userResponse{
|
||||
User: &ent.User{},
|
||||
}
|
||||
|
||||
_ = json.Unmarshal(res.Body.Bytes(), &response)
|
||||
assert.Equal(t, targetUser.ID, response.User.ID)
|
||||
}
|
||||
|
||||
func Test_HandleAdminUserCreate_Success(t *testing.T) {
|
||||
payload := factories.UserFactory()
|
||||
|
||||
r := httptest.NewRecorder()
|
||||
|
||||
body, err := json.Marshal(payload)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, UrlUser, bytes.NewBuffer(body))
|
||||
req.Header.Set(server.ContentType, server.ContentJSON)
|
||||
|
||||
mockHandler.HandleAdminUserCreate()(r, req)
|
||||
|
||||
assert.Equal(t, http.StatusCreated, r.Code)
|
||||
|
||||
usr, err := mockHandler.svc.Admin.GetByEmail(context.Background(), payload.Email)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, payload.Email, usr.Email)
|
||||
assert.Equal(t, payload.Name, usr.Name)
|
||||
assert.NotEqual(t, payload.Password, usr.Password) // smoke test - check password is hashed
|
||||
|
||||
_ = mockHandler.svc.Admin.Delete(context.Background(), usr.ID)
|
||||
}
|
||||
|
||||
func Test_HandleAdminUserUpdate_Success(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
||||
|
||||
func Test_HandleAdminUserUpdate_Delete(t *testing.T) {
|
||||
t.Skip()
|
||||
}
|
|
@ -6,8 +6,8 @@ import (
|
|||
|
||||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/internal/types"
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// HandleAuthLogin godoc
|
||||
|
@ -28,7 +28,7 @@ func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc {
|
|||
err := r.ParseForm()
|
||||
if err != nil {
|
||||
server.Respond(w, http.StatusBadRequest, server.Wrap(err))
|
||||
ctrl.log.Error(errors.New("failed to decode login form (FORM)"), logger.Props{"error": err.Error()})
|
||||
log.Error().Err(err).Msg("failed to parse form")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -38,9 +38,7 @@ func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc {
|
|||
err := server.Decode(r, loginForm)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(errors.New("failed to decode login form (JSON)"), logger.Props{
|
||||
"error": err.Error(),
|
||||
})
|
||||
log.Err(err).Msg("failed to decode login form")
|
||||
server.Respond(w, http.StatusBadRequest, server.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/internal/types"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// HandleItemsGetAll godoc
|
||||
|
@ -20,7 +21,7 @@ func (ctrl *V1Controller) HandleItemsGetAll() http.HandlerFunc {
|
|||
user := services.UseUserCtx(r.Context())
|
||||
items, err := ctrl.svc.Items.GetAll(r.Context(), user.GroupID)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to get items")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -40,7 +41,7 @@ func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
createData := types.ItemCreate{}
|
||||
if err := server.Decode(r, &createData); err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to decode request body")
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
@ -48,7 +49,7 @@ func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc {
|
|||
user := services.UseUserCtx(r.Context())
|
||||
item, err := ctrl.svc.Items.Create(r.Context(), user.GroupID, createData)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to create item")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ func (ctrl *V1Controller) HandleItemDelete() http.HandlerFunc {
|
|||
|
||||
err = ctrl.svc.Items.Delete(r.Context(), user.GroupID, uid)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to delete item")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -100,7 +101,7 @@ func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc {
|
|||
|
||||
items, err := ctrl.svc.Items.GetOne(r.Context(), user.GroupID, uid)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to get item")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -120,7 +121,7 @@ func (ctrl *V1Controller) HandleItemUpdate() http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
body := types.ItemUpdate{}
|
||||
if err := server.Decode(r, &body); err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to decode request body")
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
@ -132,7 +133,7 @@ func (ctrl *V1Controller) HandleItemUpdate() http.HandlerFunc {
|
|||
body.ID = uid
|
||||
result, err := ctrl.svc.Items.Update(r.Context(), user.GroupID, body)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to update item")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/internal/types"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// HandleLabelsGetAll godoc
|
||||
|
@ -20,7 +21,7 @@ func (ctrl *V1Controller) HandleLabelsGetAll() http.HandlerFunc {
|
|||
user := services.UseUserCtx(r.Context())
|
||||
labels, err := ctrl.svc.Labels.GetAll(r.Context(), user.GroupID)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("error getting labels")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -40,7 +41,7 @@ func (ctrl *V1Controller) HandleLabelsCreate() http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
createData := types.LabelCreate{}
|
||||
if err := server.Decode(r, &createData); err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("error decoding label create data")
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
@ -48,7 +49,7 @@ func (ctrl *V1Controller) HandleLabelsCreate() http.HandlerFunc {
|
|||
user := services.UseUserCtx(r.Context())
|
||||
label, err := ctrl.svc.Labels.Create(r.Context(), user.GroupID, createData)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("error creating label")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ func (ctrl *V1Controller) HandleLabelDelete() http.HandlerFunc {
|
|||
|
||||
err = ctrl.svc.Labels.Delete(r.Context(), user.GroupID, uid)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("error deleting label")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -100,7 +101,7 @@ func (ctrl *V1Controller) HandleLabelGet() http.HandlerFunc {
|
|||
|
||||
labels, err := ctrl.svc.Labels.Get(r.Context(), user.GroupID, uid)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("error getting label")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -120,7 +121,7 @@ func (ctrl *V1Controller) HandleLabelUpdate() http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
body := types.LabelUpdate{}
|
||||
if err := server.Decode(r, &body); err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("error decoding label update data")
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
@ -132,7 +133,7 @@ func (ctrl *V1Controller) HandleLabelUpdate() http.HandlerFunc {
|
|||
body.ID = uid
|
||||
result, err := ctrl.svc.Labels.Update(r.Context(), user.GroupID, body)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("error updating label")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/internal/types"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// HandleLocationGetAll godoc
|
||||
|
@ -20,7 +21,7 @@ func (ctrl *V1Controller) HandleLocationGetAll() http.HandlerFunc {
|
|||
user := services.UseUserCtx(r.Context())
|
||||
locations, err := ctrl.svc.Location.GetAll(r.Context(), user.GroupID)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to get locations")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ func (ctrl *V1Controller) HandleLocationCreate() http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
createData := types.LocationCreate{}
|
||||
if err := server.Decode(r, &createData); err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to decode location create data")
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
@ -49,7 +50,7 @@ func (ctrl *V1Controller) HandleLocationCreate() http.HandlerFunc {
|
|||
user := services.UseUserCtx(r.Context())
|
||||
location, err := ctrl.svc.Location.Create(r.Context(), user.GroupID, createData)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to create location")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ func (ctrl *V1Controller) HandleLocationDelete() http.HandlerFunc {
|
|||
|
||||
err = ctrl.svc.Location.Delete(r.Context(), user.GroupID, uid)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to delete location")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -100,7 +101,7 @@ func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc {
|
|||
|
||||
location, err := ctrl.svc.Location.GetOne(r.Context(), user.GroupID, uid)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to get location")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -120,7 +121,7 @@ func (ctrl *V1Controller) HandleLocationUpdate() http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
body := types.LocationUpdate{}
|
||||
if err := server.Decode(r, &body); err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to decode location update data")
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
@ -134,7 +135,7 @@ func (ctrl *V1Controller) HandleLocationUpdate() http.HandlerFunc {
|
|||
|
||||
result, err := ctrl.svc.Location.Update(r.Context(), user.GroupID, body)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to update location")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/hay-kot/content/backend/internal/services"
|
||||
"github.com/hay-kot/content/backend/internal/types"
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
"github.com/hay-kot/content/backend/pkgs/server"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// HandleUserSelf godoc
|
||||
|
@ -23,14 +22,13 @@ func (ctrl *V1Controller) HandleUserRegistration() http.HandlerFunc {
|
|||
regData := types.UserRegistration{}
|
||||
|
||||
if err := server.Decode(r, ®Data); err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
log.Err(err).Msg("failed to decode user registration data")
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := ctrl.svc.User.RegisterUser(r.Context(), regData)
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, nil)
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
@ -51,7 +49,7 @@ func (ctrl *V1Controller) HandleUserSelf() http.HandlerFunc {
|
|||
token := services.UseTokenCtx(r.Context())
|
||||
usr, err := ctrl.svc.User.GetSelf(r.Context(), token)
|
||||
if usr.ID == uuid.Nil || err != nil {
|
||||
ctrl.log.Error(errors.New("no user within request context"), nil)
|
||||
log.Err(err).Msg("failed to get user")
|
||||
server.RespondServerError(w)
|
||||
return
|
||||
}
|
||||
|
@ -72,10 +70,7 @@ func (ctrl *V1Controller) HandleUserUpdate() http.HandlerFunc {
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
updateData := types.UserUpdate{}
|
||||
if err := server.Decode(r, &updateData); err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "user",
|
||||
"details": "failed to decode user update data",
|
||||
})
|
||||
log.Err(err).Msg("failed to decode user update data")
|
||||
server.RespondError(w, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
@ -84,10 +79,7 @@ func (ctrl *V1Controller) HandleUserUpdate() http.HandlerFunc {
|
|||
newData, err := ctrl.svc.User.UpdateSelf(r.Context(), actor.ID, updateData)
|
||||
|
||||
if err != nil {
|
||||
ctrl.log.Error(err, logger.Props{
|
||||
"scope": "user",
|
||||
"details": "failed to update user",
|
||||
})
|
||||
|
||||
server.RespondError(w, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -31,8 +31,11 @@ require (
|
|||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/kr/pretty v0.2.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rs/zerolog v1.28.0 // indirect
|
||||
github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a // indirect
|
||||
github.com/tkrajina/go-reflector v0.5.6 // indirect
|
||||
github.com/zclconf/go-cty v1.11.0 // indirect
|
||||
|
|
|
@ -11,6 +11,7 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6
|
|||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
|
||||
github.com/ardanlabs/conf/v2 v2.2.0 h1:ar1+TYIYAh2Tdeg2DQroh7ruR56/vJR8BDfzDIrXgtk=
|
||||
github.com/ardanlabs/conf/v2 v2.2.0/go.mod h1:m37ZKdW9jwMUEhGX36jRNt8VzSQ/HVmSziLZH2p33nY=
|
||||
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
|
@ -31,6 +32,7 @@ github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/
|
|||
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
|
@ -53,6 +55,12 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN
|
|||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
|
@ -60,8 +68,12 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ
|
|||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY=
|
||||
github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
|
@ -95,6 +107,9 @@ golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWI
|
|||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
package mocks
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
||||
)
|
||||
|
||||
func GetStructLogger() *logger.Logger {
|
||||
return logger.New(os.Stdout, logger.LevelDebug)
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Level int8
|
||||
|
||||
var (
|
||||
IncludeTrace = false
|
||||
)
|
||||
|
||||
const (
|
||||
LevelDebug Level = iota
|
||||
LevelInfo
|
||||
LevelError
|
||||
LevelFatal
|
||||
LevelOff
|
||||
)
|
||||
|
||||
func (l Level) String() string {
|
||||
switch l {
|
||||
case LevelDebug:
|
||||
return "DEBUG"
|
||||
case LevelInfo:
|
||||
return "INFO"
|
||||
case LevelError:
|
||||
return "ERROR"
|
||||
case LevelFatal:
|
||||
return "FATAL"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type Props map[string]string
|
||||
|
||||
type Logger struct {
|
||||
out io.Writer
|
||||
minLevel Level
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func New(out io.Writer, minLevel Level) *Logger {
|
||||
return &Logger{
|
||||
out: out,
|
||||
minLevel: minLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Debug(message string, properties map[string]string) {
|
||||
l.print(LevelDebug, message, properties)
|
||||
}
|
||||
|
||||
func (l *Logger) Info(message string, properties map[string]string) {
|
||||
l.print(LevelInfo, message, properties)
|
||||
}
|
||||
|
||||
func (l *Logger) Error(err error, properties map[string]string) {
|
||||
l.print(LevelError, err.Error(), properties)
|
||||
}
|
||||
|
||||
func (l *Logger) Fatal(err error, properties map[string]string) {
|
||||
l.print(LevelFatal, err.Error(), properties)
|
||||
os.Exit(1) // For entries at the FATAL level, we also terminate the application.
|
||||
}
|
||||
|
||||
func (l *Logger) print(level Level, message string, properties map[string]string) (int, error) {
|
||||
// If the severity level of the log entry is below the minimum severity for the
|
||||
// logger, then return with no further action.
|
||||
if level < l.minLevel {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Declare an anonymous struct holding the data for the log entry.
|
||||
aux := struct {
|
||||
Level string `json:"level"`
|
||||
Time string `json:"time"`
|
||||
Message string `json:"message"`
|
||||
Properties map[string]string `json:"properties,omitempty"`
|
||||
Trace string `json:"trace,omitempty"`
|
||||
}{
|
||||
Level: level.String(),
|
||||
Time: time.Now().UTC().Format(time.RFC3339),
|
||||
Message: message,
|
||||
Properties: properties,
|
||||
}
|
||||
|
||||
// Include a stack trace for entries at the ERROR and FATAL levels.
|
||||
dumpTrace := false
|
||||
if level >= LevelError {
|
||||
dumpTrace = true
|
||||
if IncludeTrace {
|
||||
aux.Trace = string(debug.Stack())
|
||||
}
|
||||
}
|
||||
|
||||
// Declare a line variable for holding the actual log entry text.
|
||||
var line []byte
|
||||
|
||||
// Marshal the anonymous struct to JSON and store it in the line variable. If there
|
||||
// was a problem creating the JSON, set the contents of the log entry to be that
|
||||
// plain-text error message instead.”
|
||||
line, err := json.Marshal(aux)
|
||||
if err != nil {
|
||||
line = []byte(LevelError.String() + ": unable to marshal log message:" + err.Error())
|
||||
}
|
||||
|
||||
// Lock the mutex so that no two writes to the output destination cannot happen
|
||||
// concurrently. If we don't do this, it's possible that the text for two or more
|
||||
// log entries will be intermingled in the output.
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
n, err := l.out.Write(line)
|
||||
if dumpTrace {
|
||||
n, err = l.out.Write(debug.Stack())
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// We also implement a Write() method on our Logger type so that it satisfies the
|
||||
// io.Writer interface. This writes a log entry at the ERROR level with no additional
|
||||
// properties.
|
||||
func (l *Logger) Write(message []byte) (n int, err error) {
|
||||
return l.print(LevelError, string(message), nil)
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
package logger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func init() {
|
||||
IncludeTrace = true
|
||||
}
|
||||
|
||||
var lastWrite = []byte{}
|
||||
|
||||
type testLogRecorder struct {
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (tlr testLogRecorder) Write(p []byte) (n int, err error) {
|
||||
lastWrite = p
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
type logEntry struct {
|
||||
Level string `json:"level"`
|
||||
Message string `json:"message"`
|
||||
Props *Props `json:"properties"`
|
||||
}
|
||||
|
||||
func (lr *logEntry) Unmarshal(t *testing.T, jbytes []byte) {
|
||||
err := json.Unmarshal(jbytes, lr)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_LevelString(t *testing.T) {
|
||||
assert.Equal(t, "DEBUG", LevelDebug.String())
|
||||
assert.Equal(t, "INFO", LevelInfo.String())
|
||||
assert.Equal(t, "ERROR", LevelError.String())
|
||||
assert.Equal(t, "FATAL", LevelFatal.String())
|
||||
assert.Equal(t, "", LevelOff.String())
|
||||
}
|
||||
|
||||
func Test_NewLogger(t *testing.T) {
|
||||
logRecorder := testLogRecorder{t: t}
|
||||
|
||||
logger := New(logRecorder, LevelInfo)
|
||||
assert.NotNil(t, logger)
|
||||
}
|
||||
|
||||
func getTestLogger(t *testing.T, level Level) *Logger {
|
||||
logRecorder := testLogRecorder{t: t}
|
||||
|
||||
logger := New(logRecorder, level)
|
||||
assert.NotNil(t, logger)
|
||||
|
||||
return logger
|
||||
}
|
||||
|
||||
func checkLastEntry(t *testing.T, level Level, message string, props *Props) {
|
||||
t.Helper()
|
||||
entry := &logEntry{}
|
||||
entry.Unmarshal(t, lastWrite)
|
||||
|
||||
assert.Equal(t, level.String(), entry.Level)
|
||||
assert.Equal(t, message, entry.Message)
|
||||
assert.Equal(t, props, entry.Props)
|
||||
|
||||
}
|
||||
|
||||
func Test_LoggerDebug(t *testing.T) {
|
||||
lgr := getTestLogger(t, LevelDebug)
|
||||
|
||||
lgr.Debug("Test Debug", Props{"Hello": "World"})
|
||||
checkLastEntry(t, LevelDebug, "Test Debug", &Props{"Hello": "World"})
|
||||
|
||||
lastWrite = []byte{}
|
||||
}
|
||||
|
||||
func Test_LoggerInfo(t *testing.T) {
|
||||
lgr := getTestLogger(t, LevelInfo)
|
||||
|
||||
lgr.Info("Test Info", Props{"Hello": "World"})
|
||||
checkLastEntry(t, LevelInfo, "Test Info", &Props{"Hello": "World"})
|
||||
lastWrite = []byte{}
|
||||
|
||||
}
|
||||
|
||||
func Test_LoggerError(t *testing.T) {
|
||||
lgr := getTestLogger(t, LevelError)
|
||||
|
||||
myerror := errors.New("Test Error")
|
||||
|
||||
lgr.Error(myerror, Props{"Hello": "World"})
|
||||
checkLastEntry(t, LevelError, "Test Error", &Props{"Hello": "World"})
|
||||
lastWrite = []byte{}
|
||||
|
||||
}
|
||||
|
||||
func Test_LoggerLevelScale(t *testing.T) {
|
||||
lgr := getTestLogger(t, LevelInfo)
|
||||
lastWrite = []byte{}
|
||||
lgr.Debug("Test Debug", Props{"Hello": "World"})
|
||||
|
||||
assert.Equal(t, []byte{}, lastWrite)
|
||||
|
||||
lgr = getTestLogger(t, LevelError)
|
||||
lastWrite = []byte{}
|
||||
lgr.Info("Test Debug", Props{"Hello": "World"})
|
||||
lgr.Debug("Test Debug", Props{"Hello": "World"})
|
||||
|
||||
assert.Equal(t, []byte{}, lastWrite)
|
||||
|
||||
lgr = getTestLogger(t, LevelFatal)
|
||||
|
||||
lgr.Info("Test Debug", Props{"Hello": "World"})
|
||||
lgr.Debug("Test Debug", Props{"Hello": "World"})
|
||||
lgr.Error(errors.New("Test Error"), Props{"Hello": "World"})
|
||||
|
||||
assert.Equal(t, []byte{}, lastWrite)
|
||||
}
|
Loading…
Reference in a new issue