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/config"
|
||||||
"github.com/hay-kot/content/backend/internal/repo"
|
"github.com/hay-kot/content/backend/internal/repo"
|
||||||
"github.com/hay-kot/content/backend/internal/services"
|
"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/mailer"
|
||||||
"github.com/hay-kot/content/backend/pkgs/server"
|
"github.com/hay-kot/content/backend/pkgs/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
type app struct {
|
type app struct {
|
||||||
conf *config.Config
|
conf *config.Config
|
||||||
logger *logger.Logger
|
|
||||||
mailer mailer.Mailer
|
mailer mailer.Mailer
|
||||||
db *ent.Client
|
db *ent.Client
|
||||||
server *server.Server
|
server *server.Server
|
||||||
|
|
|
@ -4,20 +4,17 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/hay-kot/content/backend/internal/types"
|
"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/hay-kot/content/backend/pkgs/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReadyFunc func() bool
|
type ReadyFunc func() bool
|
||||||
|
|
||||||
type BaseController struct {
|
type BaseController struct {
|
||||||
log *logger.Logger
|
|
||||||
svr *server.Server
|
svr *server.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBaseController(log *logger.Logger, svr *server.Server) *BaseController {
|
func NewBaseController(svr *server.Server) *BaseController {
|
||||||
h := &BaseController{
|
h := &BaseController{
|
||||||
log: log,
|
|
||||||
svr: svr,
|
svr: svr,
|
||||||
}
|
}
|
||||||
return h
|
return h
|
||||||
|
|
|
@ -4,12 +4,10 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hay-kot/content/backend/internal/mocks"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetTestHandler(t *testing.T) *BaseController {
|
func GetTestHandler(t *testing.T) *BaseController {
|
||||||
return NewBaseController(mocks.GetStructLogger(), nil)
|
return NewBaseController(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHandlersv1_HandleBase(t *testing.T) {
|
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": {
|
"/v1/items": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -1643,9 +1434,6 @@ const docTemplate = `{
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -1680,9 +1468,6 @@ const docTemplate = `{
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -1709,9 +1494,6 @@ const docTemplate = `{
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"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": {
|
"types.UserIn": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"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": {
|
"/v1/items": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -1635,9 +1426,6 @@
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -1672,9 +1460,6 @@
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -1701,9 +1486,6 @@
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"groupId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"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": {
|
"types.UserIn": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
|
@ -493,8 +493,6 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
description:
|
description:
|
||||||
type: string
|
type: string
|
||||||
groupId:
|
|
||||||
type: string
|
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
itemCount:
|
itemCount:
|
||||||
|
@ -517,8 +515,6 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
description:
|
description:
|
||||||
type: string
|
type: string
|
||||||
groupId:
|
|
||||||
type: string
|
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
items:
|
items:
|
||||||
|
@ -536,8 +532,6 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
description:
|
description:
|
||||||
type: string
|
type: string
|
||||||
groupId:
|
|
||||||
type: string
|
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
name:
|
name:
|
||||||
|
@ -552,19 +546,6 @@ definitions:
|
||||||
token:
|
token:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
types.UserCreate:
|
|
||||||
properties:
|
|
||||||
email:
|
|
||||||
type: string
|
|
||||||
groupID:
|
|
||||||
type: string
|
|
||||||
isSuperuser:
|
|
||||||
type: boolean
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
password:
|
|
||||||
type: string
|
|
||||||
type: object
|
|
||||||
types.UserIn:
|
types.UserIn:
|
||||||
properties:
|
properties:
|
||||||
email:
|
email:
|
||||||
|
@ -616,124 +597,6 @@ paths:
|
||||||
summary: Retrieves the basic information about the API
|
summary: Retrieves the basic information about the API
|
||||||
tags:
|
tags:
|
||||||
- Base
|
- 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:
|
/v1/items:
|
||||||
get:
|
get:
|
||||||
produces:
|
produces:
|
||||||
|
|
|
@ -2,8 +2,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -12,9 +10,10 @@ import (
|
||||||
"github.com/hay-kot/content/backend/internal/config"
|
"github.com/hay-kot/content/backend/internal/config"
|
||||||
"github.com/hay-kot/content/backend/internal/repo"
|
"github.com/hay-kot/content/backend/internal/repo"
|
||||||
"github.com/hay-kot/content/backend/internal/services"
|
"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/hay-kot/content/backend/pkgs/server"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @title Go API Templates
|
// @title Go API Templates
|
||||||
|
@ -28,6 +27,10 @@ import (
|
||||||
// @name Authorization
|
// @name Authorization
|
||||||
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
|
// @description "Type 'Bearer TOKEN' to correctly set the API Key"
|
||||||
func main() {
|
func main() {
|
||||||
|
// Logger Init
|
||||||
|
// zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
|
||||||
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||||
|
|
||||||
cfgFile := "config.yml"
|
cfgFile := "config.yml"
|
||||||
|
|
||||||
cfg, err := config.NewConfig(cfgFile)
|
cfg, err := config.NewConfig(cfgFile)
|
||||||
|
@ -45,42 +48,24 @@ func main() {
|
||||||
func run(cfg *config.Config) error {
|
func run(cfg *config.Config) error {
|
||||||
app := NewApp(cfg)
|
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
|
// Initialize Database & Repos
|
||||||
|
|
||||||
c, err := ent.Open(cfg.Database.GetDriver(), cfg.Database.GetUrl())
|
c, err := ent.Open(cfg.Database.GetDriver(), cfg.Database.GetUrl())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.logger.Fatal(err, logger.Props{
|
log.Fatal().
|
||||||
"details": "failed to connect to database",
|
Err(err).
|
||||||
"database": cfg.Database.GetDriver(),
|
Str("driver", cfg.Database.GetDriver()).
|
||||||
"url": cfg.Database.GetUrl(),
|
Str("url", cfg.Database.GetUrl()).
|
||||||
})
|
Msg("failed opening connection to sqlite")
|
||||||
}
|
}
|
||||||
defer func(c *ent.Client) {
|
defer func(c *ent.Client) {
|
||||||
_ = c.Close()
|
_ = c.Close()
|
||||||
}(c)
|
}(c)
|
||||||
if err := c.Schema.Create(context.Background()); err != nil {
|
if err := c.Schema.Create(context.Background()); err != nil {
|
||||||
app.logger.Fatal(err, logger.Props{
|
log.Fatal().
|
||||||
"details": "failed to create schema",
|
Err(err).
|
||||||
})
|
Msg("failed creating schema resources")
|
||||||
}
|
}
|
||||||
|
|
||||||
app.db = c
|
app.db = c
|
||||||
|
@ -99,10 +84,7 @@ func run(cfg *config.Config) error {
|
||||||
|
|
||||||
app.SeedDatabase(app.repos)
|
app.SeedDatabase(app.repos)
|
||||||
|
|
||||||
app.logger.Info("Starting HTTP Server", logger.Props{
|
log.Info().Msgf("Starting HTTP Server on %s:%s", app.server.Host, app.server.Port)
|
||||||
"host": app.server.Host,
|
|
||||||
"port": app.server.Port,
|
|
||||||
})
|
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Start Reoccurring Tasks
|
// Start Reoccurring Tasks
|
||||||
|
@ -110,9 +92,9 @@ func run(cfg *config.Config) error {
|
||||||
go app.StartReoccurringTasks(time.Duration(24)*time.Hour, func() {
|
go app.StartReoccurringTasks(time.Duration(24)*time.Hour, func() {
|
||||||
_, err := app.repos.AuthTokens.PurgeExpiredTokens(context.Background())
|
_, err := app.repos.AuthTokens.PurgeExpiredTokens(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
app.logger.Error(err, logger.Props{
|
log.Error().
|
||||||
"details": "failed to purge expired tokens",
|
Err(err).
|
||||||
})
|
Msg("failed to purge expired tokens")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
"github.com/hay-kot/content/backend/internal/config"
|
"github.com/hay-kot/content/backend/internal/config"
|
||||||
"github.com/hay-kot/content/backend/internal/services"
|
"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/hay-kot/content/backend/pkgs/server"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *app) setGlobalMiddleware(r *chi.Mux) {
|
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
|
// Use struct logger in production for requests, but use
|
||||||
// pretty console logger in development.
|
// pretty console logger in development.
|
||||||
if a.conf.Mode == config.ModeDevelopment {
|
if a.conf.Mode == config.ModeDevelopment {
|
||||||
r.Use(middleware.Logger)
|
r.Use(a.mwSummaryLogger)
|
||||||
} else {
|
} else {
|
||||||
r.Use(a.mwStructLogger)
|
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)
|
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{
|
log.Info().
|
||||||
"id": middleware.GetReqID(r.Context()),
|
Str("id", middleware.GetReqID(r.Context())).
|
||||||
"method": r.Method,
|
Str("url", url).
|
||||||
"url": url,
|
Str("method", r.Method).
|
||||||
"remote": r.RemoteAddr,
|
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)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux {
|
||||||
http.ServeFile(w, r, "static/favicon.ico")
|
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"))
|
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)
|
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/register"), v1Handlers.HandleUserRegistration())
|
||||||
r.Post(v1Base("/users/login"), v1Handlers.HandleAuthLogin())
|
r.Post(v1Base("/users/login"), v1Handlers.HandleAuthLogin())
|
||||||
r.Group(func(r chi.Router) {
|
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.Put(v1Base("/items/{id}"), v1Handlers.HandleItemUpdate())
|
||||||
r.Delete(v1Base("/items/{id}"), v1Handlers.HandleItemDelete())
|
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
|
return r
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/hay-kot/content/backend/internal/repo"
|
"github.com/hay-kot/content/backend/internal/repo"
|
||||||
"github.com/hay-kot/content/backend/internal/types"
|
"github.com/hay-kot/content/backend/internal/types"
|
||||||
"github.com/hay-kot/content/backend/pkgs/hasher"
|
"github.com/hay-kot/content/backend/pkgs/hasher"
|
||||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -23,7 +23,7 @@ func (a *app) EnsureAdministrator() {
|
||||||
superusers, err := a.repos.Users.GetSuperusers(context.Background())
|
superusers, err := a.repos.Users.GetSuperusers(context.Background())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.logger.Fatal(err, nil)
|
log.Fatal().Err(err).Msg("failed to get superusers")
|
||||||
}
|
}
|
||||||
if len(superusers) > 0 {
|
if len(superusers) > 0 {
|
||||||
return
|
return
|
||||||
|
@ -37,15 +37,15 @@ func (a *app) EnsureAdministrator() {
|
||||||
Password: pw,
|
Password: pw,
|
||||||
}
|
}
|
||||||
|
|
||||||
a.logger.Info("creating default superuser", logger.Props{
|
log.Info().
|
||||||
"name": newSuperUser.Name,
|
Str("name", newSuperUser.Name).
|
||||||
"email": newSuperUser.Email,
|
Str("email", newSuperUser.Email).
|
||||||
})
|
Msg("no superusers found, creating default superuser")
|
||||||
|
|
||||||
_, err = a.repos.Users.Create(context.Background(), newSuperUser)
|
_, err = a.repos.Users.Create(context.Background(), newSuperUser)
|
||||||
|
|
||||||
if err != nil {
|
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)
|
group, err := repos.Groups.Create(context.Background(), DefaultGroup)
|
||||||
if err != nil {
|
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 {
|
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)
|
usr, _ := repos.Users.GetOneEmail(context.Background(), user.Email)
|
||||||
|
|
||||||
if usr.ID != uuid.Nil {
|
if usr.ID != uuid.Nil {
|
||||||
a.logger.Info("seed user already exists", logger.Props{
|
log.Info().Str("email", user.Email).Msg("user already exists, skipping")
|
||||||
"user": user.Name,
|
|
||||||
})
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
hashedPw, err := hasher.HashPassword(user.Password)
|
hashedPw, err := hasher.HashPassword(user.Password)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.logger.Error(err, logger.Props{
|
log.Fatal().Err(err).Msg("failed to hash password")
|
||||||
"details": "failed to hash password",
|
|
||||||
"user": user.Name,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = repos.Users.Create(context.Background(), types.UserCreate{
|
_, err = repos.Users.Create(context.Background(), types.UserCreate{
|
||||||
|
@ -90,14 +84,9 @@ func (a *app) SeedDatabase(repos *repo.AllRepos) {
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.logger.Error(err, logger.Props{
|
log.Fatal().Err(err).Msg("failed to create user")
|
||||||
"details": "failed to create seed user",
|
|
||||||
"name": user.Name,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a.logger.Info("creating seed user", logger.Props{
|
log.Info().Str("email", user.Email).Msg("created user")
|
||||||
"name": user.Name,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,9 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hay-kot/content/backend/internal/services"
|
"github.com/hay-kot/content/backend/internal/services"
|
||||||
"github.com/hay-kot/content/backend/pkgs/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type V1Controller struct {
|
type V1Controller struct {
|
||||||
log *logger.Logger
|
|
||||||
svc *services.AllServices
|
svc *services.AllServices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,9 +17,8 @@ func BaseUrlFunc(prefix string) func(s string) string {
|
||||||
return prefixFunc
|
return prefixFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewControllerV1(log *logger.Logger, svc *services.AllServices) *V1Controller {
|
func NewControllerV1(svc *services.AllServices) *V1Controller {
|
||||||
ctrl := &V1Controller{
|
ctrl := &V1Controller{
|
||||||
log: log,
|
|
||||||
svc: svc,
|
svc: svc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,10 @@ import (
|
||||||
func Test_NewHandlerV1(t *testing.T) {
|
func Test_NewHandlerV1(t *testing.T) {
|
||||||
|
|
||||||
v1Base := BaseUrlFunc("/testing/v1")
|
v1Base := BaseUrlFunc("/testing/v1")
|
||||||
ctrl := NewControllerV1(mockHandler.log, mockHandler.svc)
|
ctrl := NewControllerV1(mockHandler.svc)
|
||||||
|
|
||||||
assert.NotNil(t, ctrl)
|
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"))
|
||||||
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) {
|
func TestMain(m *testing.M) {
|
||||||
// Set Handler Vars
|
// Set Handler Vars
|
||||||
mockHandler.log = mocks.GetStructLogger()
|
|
||||||
repos, closeDb := mocks.GetEntRepos()
|
repos, closeDb := mocks.GetEntRepos()
|
||||||
mockHandler.svc = mocks.GetMockServices(repos)
|
mockHandler.svc = mocks.GetMockServices(repos)
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/content/backend/internal/services"
|
"github.com/hay-kot/content/backend/internal/services"
|
||||||
"github.com/hay-kot/content/backend/internal/types"
|
"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/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) {
|
func (ctrl *V1Controller) partialParseIdAndUser(w http.ResponseWriter, r *http.Request) (uuid.UUID, *types.UserOut, error) {
|
||||||
uid, err := uuid.Parse(chi.URLParam(r, "id"))
|
uid, err := uuid.Parse(chi.URLParam(r, "id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Debug(err.Error(), logger.Props{
|
log.Err(err).Msg("failed to parse id")
|
||||||
"details": "failed to convert id to valid UUID",
|
|
||||||
})
|
|
||||||
server.RespondError(w, http.StatusBadRequest, err)
|
server.RespondError(w, http.StatusBadRequest, err)
|
||||||
return uuid.Nil, nil, 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/services"
|
||||||
"github.com/hay-kot/content/backend/internal/types"
|
"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/hay-kot/content/backend/pkgs/server"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleAuthLogin godoc
|
// HandleAuthLogin godoc
|
||||||
|
@ -28,7 +28,7 @@ func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc {
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
server.Respond(w, http.StatusBadRequest, server.Wrap(err))
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,9 +38,7 @@ func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc {
|
||||||
err := server.Decode(r, loginForm)
|
err := server.Decode(r, loginForm)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(errors.New("failed to decode login form (JSON)"), logger.Props{
|
log.Err(err).Msg("failed to decode login form")
|
||||||
"error": err.Error(),
|
|
||||||
})
|
|
||||||
server.Respond(w, http.StatusBadRequest, server.Wrap(err))
|
server.Respond(w, http.StatusBadRequest, server.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/hay-kot/content/backend/internal/services"
|
"github.com/hay-kot/content/backend/internal/services"
|
||||||
"github.com/hay-kot/content/backend/internal/types"
|
"github.com/hay-kot/content/backend/internal/types"
|
||||||
"github.com/hay-kot/content/backend/pkgs/server"
|
"github.com/hay-kot/content/backend/pkgs/server"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleItemsGetAll godoc
|
// HandleItemsGetAll godoc
|
||||||
|
@ -20,7 +21,7 @@ func (ctrl *V1Controller) HandleItemsGetAll() http.HandlerFunc {
|
||||||
user := services.UseUserCtx(r.Context())
|
user := services.UseUserCtx(r.Context())
|
||||||
items, err := ctrl.svc.Items.GetAll(r.Context(), user.GroupID)
|
items, err := ctrl.svc.Items.GetAll(r.Context(), user.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("failed to get items")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,7 @@ func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
createData := types.ItemCreate{}
|
createData := types.ItemCreate{}
|
||||||
if err := server.Decode(r, &createData); err != nil {
|
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)
|
server.RespondError(w, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -48,7 +49,7 @@ func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc {
|
||||||
user := services.UseUserCtx(r.Context())
|
user := services.UseUserCtx(r.Context())
|
||||||
item, err := ctrl.svc.Items.Create(r.Context(), user.GroupID, createData)
|
item, err := ctrl.svc.Items.Create(r.Context(), user.GroupID, createData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("failed to create item")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -75,7 +76,7 @@ func (ctrl *V1Controller) HandleItemDelete() http.HandlerFunc {
|
||||||
|
|
||||||
err = ctrl.svc.Items.Delete(r.Context(), user.GroupID, uid)
|
err = ctrl.svc.Items.Delete(r.Context(), user.GroupID, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("failed to delete item")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,7 @@ func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc {
|
||||||
|
|
||||||
items, err := ctrl.svc.Items.GetOne(r.Context(), user.GroupID, uid)
|
items, err := ctrl.svc.Items.GetOne(r.Context(), user.GroupID, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("failed to get item")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -120,7 +121,7 @@ func (ctrl *V1Controller) HandleItemUpdate() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
body := types.ItemUpdate{}
|
body := types.ItemUpdate{}
|
||||||
if err := server.Decode(r, &body); err != nil {
|
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)
|
server.RespondError(w, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -132,7 +133,7 @@ func (ctrl *V1Controller) HandleItemUpdate() http.HandlerFunc {
|
||||||
body.ID = uid
|
body.ID = uid
|
||||||
result, err := ctrl.svc.Items.Update(r.Context(), user.GroupID, body)
|
result, err := ctrl.svc.Items.Update(r.Context(), user.GroupID, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("failed to update item")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/hay-kot/content/backend/internal/services"
|
"github.com/hay-kot/content/backend/internal/services"
|
||||||
"github.com/hay-kot/content/backend/internal/types"
|
"github.com/hay-kot/content/backend/internal/types"
|
||||||
"github.com/hay-kot/content/backend/pkgs/server"
|
"github.com/hay-kot/content/backend/pkgs/server"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleLabelsGetAll godoc
|
// HandleLabelsGetAll godoc
|
||||||
|
@ -20,7 +21,7 @@ func (ctrl *V1Controller) HandleLabelsGetAll() http.HandlerFunc {
|
||||||
user := services.UseUserCtx(r.Context())
|
user := services.UseUserCtx(r.Context())
|
||||||
labels, err := ctrl.svc.Labels.GetAll(r.Context(), user.GroupID)
|
labels, err := ctrl.svc.Labels.GetAll(r.Context(), user.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("error getting labels")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,7 @@ func (ctrl *V1Controller) HandleLabelsCreate() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
createData := types.LabelCreate{}
|
createData := types.LabelCreate{}
|
||||||
if err := server.Decode(r, &createData); err != nil {
|
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)
|
server.RespondError(w, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -48,7 +49,7 @@ func (ctrl *V1Controller) HandleLabelsCreate() http.HandlerFunc {
|
||||||
user := services.UseUserCtx(r.Context())
|
user := services.UseUserCtx(r.Context())
|
||||||
label, err := ctrl.svc.Labels.Create(r.Context(), user.GroupID, createData)
|
label, err := ctrl.svc.Labels.Create(r.Context(), user.GroupID, createData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("error creating label")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -75,7 +76,7 @@ func (ctrl *V1Controller) HandleLabelDelete() http.HandlerFunc {
|
||||||
|
|
||||||
err = ctrl.svc.Labels.Delete(r.Context(), user.GroupID, uid)
|
err = ctrl.svc.Labels.Delete(r.Context(), user.GroupID, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("error deleting label")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,7 @@ func (ctrl *V1Controller) HandleLabelGet() http.HandlerFunc {
|
||||||
|
|
||||||
labels, err := ctrl.svc.Labels.Get(r.Context(), user.GroupID, uid)
|
labels, err := ctrl.svc.Labels.Get(r.Context(), user.GroupID, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("error getting label")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -120,7 +121,7 @@ func (ctrl *V1Controller) HandleLabelUpdate() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
body := types.LabelUpdate{}
|
body := types.LabelUpdate{}
|
||||||
if err := server.Decode(r, &body); err != nil {
|
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)
|
server.RespondError(w, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -132,7 +133,7 @@ func (ctrl *V1Controller) HandleLabelUpdate() http.HandlerFunc {
|
||||||
body.ID = uid
|
body.ID = uid
|
||||||
result, err := ctrl.svc.Labels.Update(r.Context(), user.GroupID, body)
|
result, err := ctrl.svc.Labels.Update(r.Context(), user.GroupID, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("error updating label")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/hay-kot/content/backend/internal/services"
|
"github.com/hay-kot/content/backend/internal/services"
|
||||||
"github.com/hay-kot/content/backend/internal/types"
|
"github.com/hay-kot/content/backend/internal/types"
|
||||||
"github.com/hay-kot/content/backend/pkgs/server"
|
"github.com/hay-kot/content/backend/pkgs/server"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleLocationGetAll godoc
|
// HandleLocationGetAll godoc
|
||||||
|
@ -20,7 +21,7 @@ func (ctrl *V1Controller) HandleLocationGetAll() http.HandlerFunc {
|
||||||
user := services.UseUserCtx(r.Context())
|
user := services.UseUserCtx(r.Context())
|
||||||
locations, err := ctrl.svc.Location.GetAll(r.Context(), user.GroupID)
|
locations, err := ctrl.svc.Location.GetAll(r.Context(), user.GroupID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("failed to get locations")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -41,7 +42,7 @@ func (ctrl *V1Controller) HandleLocationCreate() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
createData := types.LocationCreate{}
|
createData := types.LocationCreate{}
|
||||||
if err := server.Decode(r, &createData); err != nil {
|
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)
|
server.RespondError(w, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -49,7 +50,7 @@ func (ctrl *V1Controller) HandleLocationCreate() http.HandlerFunc {
|
||||||
user := services.UseUserCtx(r.Context())
|
user := services.UseUserCtx(r.Context())
|
||||||
location, err := ctrl.svc.Location.Create(r.Context(), user.GroupID, createData)
|
location, err := ctrl.svc.Location.Create(r.Context(), user.GroupID, createData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("failed to create location")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -75,7 +76,7 @@ func (ctrl *V1Controller) HandleLocationDelete() http.HandlerFunc {
|
||||||
|
|
||||||
err = ctrl.svc.Location.Delete(r.Context(), user.GroupID, uid)
|
err = ctrl.svc.Location.Delete(r.Context(), user.GroupID, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("failed to delete location")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,7 @@ func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc {
|
||||||
|
|
||||||
location, err := ctrl.svc.Location.GetOne(r.Context(), user.GroupID, uid)
|
location, err := ctrl.svc.Location.GetOne(r.Context(), user.GroupID, uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("failed to get location")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -120,7 +121,7 @@ func (ctrl *V1Controller) HandleLocationUpdate() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
body := types.LocationUpdate{}
|
body := types.LocationUpdate{}
|
||||||
if err := server.Decode(r, &body); err != nil {
|
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)
|
server.RespondError(w, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -134,7 +135,7 @@ func (ctrl *V1Controller) HandleLocationUpdate() http.HandlerFunc {
|
||||||
|
|
||||||
result, err := ctrl.svc.Location.Update(r.Context(), user.GroupID, body)
|
result, err := ctrl.svc.Location.Update(r.Context(), user.GroupID, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
log.Err(err).Msg("failed to update location")
|
||||||
server.RespondServerError(w)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/content/backend/internal/services"
|
"github.com/hay-kot/content/backend/internal/services"
|
||||||
"github.com/hay-kot/content/backend/internal/types"
|
"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/hay-kot/content/backend/pkgs/server"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HandleUserSelf godoc
|
// HandleUserSelf godoc
|
||||||
|
@ -23,14 +22,13 @@ func (ctrl *V1Controller) HandleUserRegistration() http.HandlerFunc {
|
||||||
regData := types.UserRegistration{}
|
regData := types.UserRegistration{}
|
||||||
|
|
||||||
if err := server.Decode(r, ®Data); err != nil {
|
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)
|
server.RespondError(w, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := ctrl.svc.User.RegisterUser(r.Context(), regData)
|
_, err := ctrl.svc.User.RegisterUser(r.Context(), regData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, nil)
|
|
||||||
server.RespondError(w, http.StatusInternalServerError, err)
|
server.RespondError(w, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -51,7 +49,7 @@ func (ctrl *V1Controller) HandleUserSelf() http.HandlerFunc {
|
||||||
token := services.UseTokenCtx(r.Context())
|
token := services.UseTokenCtx(r.Context())
|
||||||
usr, err := ctrl.svc.User.GetSelf(r.Context(), token)
|
usr, err := ctrl.svc.User.GetSelf(r.Context(), token)
|
||||||
if usr.ID == uuid.Nil || err != nil {
|
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)
|
server.RespondServerError(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -72,10 +70,7 @@ func (ctrl *V1Controller) HandleUserUpdate() http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
updateData := types.UserUpdate{}
|
updateData := types.UserUpdate{}
|
||||||
if err := server.Decode(r, &updateData); err != nil {
|
if err := server.Decode(r, &updateData); err != nil {
|
||||||
ctrl.log.Error(err, logger.Props{
|
log.Err(err).Msg("failed to decode user update data")
|
||||||
"scope": "user",
|
|
||||||
"details": "failed to decode user update data",
|
|
||||||
})
|
|
||||||
server.RespondError(w, http.StatusBadRequest, err)
|
server.RespondError(w, http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -84,10 +79,7 @@ func (ctrl *V1Controller) HandleUserUpdate() http.HandlerFunc {
|
||||||
newData, err := ctrl.svc.User.UpdateSelf(r.Context(), actor.ID, updateData)
|
newData, err := ctrl.svc.User.UpdateSelf(r.Context(), actor.ID, updateData)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctrl.log.Error(err, logger.Props{
|
|
||||||
"scope": "user",
|
|
||||||
"details": "failed to update user",
|
|
||||||
})
|
|
||||||
server.RespondError(w, http.StatusInternalServerError, err)
|
server.RespondError(w, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,8 +31,11 @@ require (
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/kr/pretty v0.2.0 // indirect
|
github.com/kr/pretty v0.2.0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // 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/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // 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/swaggo/files v0.0.0-20220728132757-551d4a08d97a // indirect
|
||||||
github.com/tkrajina/go-reflector v0.5.6 // indirect
|
github.com/tkrajina/go-reflector v0.5.6 // indirect
|
||||||
github.com/zclconf/go-cty v1.11.0 // 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/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 h1:ar1+TYIYAh2Tdeg2DQroh7ruR56/vJR8BDfzDIrXgtk=
|
||||||
github.com/ardanlabs/conf/v2 v2.2.0/go.mod h1:m37ZKdW9jwMUEhGX36jRNt8VzSQ/HVmSziLZH2p33nY=
|
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/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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
|
||||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
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/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.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 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
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.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
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-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 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||||
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
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/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/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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
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/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/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||||
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
|
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=
|
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/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-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-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 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
|
||||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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=
|
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