diff --git a/.gitignore b/.gitignore index 0aeaf71..b81b742 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Project Specific +backend/homebox-data/* config.yml homebox.db .idea diff --git a/Dockerfile b/Dockerfile index 6aff858..8be44f2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,8 +29,11 @@ RUN CGO_ENABLED=1 GOOS=linux go build \ # Production Stage FROM alpine:latest +ENV HBOX_MODE=production +ENV HBOX_STORAGE_DATA=/data/ +ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1 + RUN apk --no-cache add ca-certificates -COPY ./backend/config.template.yml /data/config.yml RUN mkdir /app COPY --from=builder /go/bin/api /app diff --git a/Taskfile.yml b/Taskfile.yml index 903fb2c..04aa8e1 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -2,6 +2,9 @@ version: "3" tasks: generate: + desc: | + Generates collateral files from the backend project + including swagger docs and typescripts type for the frontend cmds: - | cd backend && ent generate ./ent/schema \ @@ -11,16 +14,26 @@ tasks: - | npx swagger-typescript-api \ --no-client \ - --clean-output \ --modular \ --path ./backend/app/api/docs/swagger.json \ --output ./frontend/lib/api/types python3 ./scripts/process-types.py ./frontend/lib/api/types/data-contracts.ts + sources: + - "./backend/app/api/**/*" + - "./backend/app/internal/types/**/*" + - "./scripts/process-types.py" + generates: + - "./frontend/lib/api/types/data-contracts.ts" + - "./backend/app/api/docs/swagger.json" + - "./backend/app/api/docs/swagger.yaml" + api: + desc: Starts the backend api server (depends on generate task) + deps: + - generate cmds: - - task: generate - - cd backend && go run ./app/api/ {{.CLI_ARGS}} ./config.yml + - cd backend && go run ./app/api/ {{ .CLI_ARGS }} silent: false api:build: diff --git a/backend/app/api/app.go b/backend/app/api/app.go index 7176758..7f6b23f 100644 --- a/backend/app/api/app.go +++ b/backend/app/api/app.go @@ -3,12 +3,12 @@ package main import ( "time" - "github.com/hay-kot/content/backend/ent" - "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/mailer" - "github.com/hay-kot/content/backend/pkgs/server" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/config" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/pkgs/mailer" + "github.com/hay-kot/homebox/backend/pkgs/server" ) type app struct { diff --git a/backend/app/api/docs/docs.go b/backend/app/api/docs/docs.go index 90e77ce..17af262 100644 --- a/backend/app/api/docs/docs.go +++ b/backend/app/api/docs/docs.go @@ -224,6 +224,222 @@ const docTemplate = `{ } } }, + "/v1/items/{id}/attachments": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Items" + ], + "summary": "imports items into the database", + "parameters": [ + { + "type": "string", + "description": "Item ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "file", + "description": "File attachment", + "name": "file", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "Type of file", + "name": "type", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "name of the file including extension", + "name": "name", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ItemOut" + } + }, + "422": { + "description": "Unprocessable Entity", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/server.ValidationError" + } + } + } + } + } + }, + "/v1/items/{id}/attachments/download": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/octet-stream" + ], + "tags": [ + "Items" + ], + "summary": "retrieves an attachment for an item", + "parameters": [ + { + "type": "string", + "description": "Item ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Attachment token", + "name": "token", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/v1/items/{id}/attachments/{attachment_id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/octet-stream" + ], + "tags": [ + "Items" + ], + "summary": "retrieves an attachment for an item", + "parameters": [ + { + "type": "string", + "description": "Item ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Attachment ID", + "name": "attachment_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ItemAttachmentToken" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "tags": [ + "Items" + ], + "summary": "retrieves an attachment for an item", + "parameters": [ + { + "type": "string", + "description": "Item ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Attachment ID", + "name": "attachment_id", + "in": "path", + "required": true + }, + { + "description": "Attachment Update", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.ItemAttachmentUpdate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ItemOut" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "tags": [ + "Items" + ], + "summary": "retrieves an attachment for an item", + "parameters": [ + { + "type": "string", + "description": "Item ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Attachment ID", + "name": "attachment_id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "" + } + } + } + }, "/v1/labels": { "get": { "security": [ @@ -818,6 +1034,17 @@ const docTemplate = `{ } } }, + "server.ValidationError": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "reason": { + "type": "string" + } + } + }, "types.ApiSummary": { "type": "object", "properties": { @@ -881,11 +1108,33 @@ const docTemplate = `{ "id": { "type": "string" }, + "type": { + "type": "string" + }, "updatedAt": { "type": "string" } } }, + "types.ItemAttachmentToken": { + "type": "object", + "properties": { + "token": { + "type": "string" + } + } + }, + "types.ItemAttachmentUpdate": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, "types.ItemCreate": { "type": "object", "properties": { @@ -1185,9 +1434,6 @@ const docTemplate = `{ "description": { "type": "string" }, - "groupId": { - "type": "string" - }, "id": { "type": "string" }, @@ -1214,9 +1460,6 @@ const docTemplate = `{ "description": { "type": "string" }, - "groupId": { - "type": "string" - }, "id": { "type": "string" }, diff --git a/backend/app/api/docs/swagger.json b/backend/app/api/docs/swagger.json index 3d56184..87ae636 100644 --- a/backend/app/api/docs/swagger.json +++ b/backend/app/api/docs/swagger.json @@ -216,6 +216,222 @@ } } }, + "/v1/items/{id}/attachments": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Items" + ], + "summary": "imports items into the database", + "parameters": [ + { + "type": "string", + "description": "Item ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "file", + "description": "File attachment", + "name": "file", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "Type of file", + "name": "type", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "name of the file including extension", + "name": "name", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ItemOut" + } + }, + "422": { + "description": "Unprocessable Entity", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/server.ValidationError" + } + } + } + } + } + }, + "/v1/items/{id}/attachments/download": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/octet-stream" + ], + "tags": [ + "Items" + ], + "summary": "retrieves an attachment for an item", + "parameters": [ + { + "type": "string", + "description": "Item ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Attachment token", + "name": "token", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/v1/items/{id}/attachments/{attachment_id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/octet-stream" + ], + "tags": [ + "Items" + ], + "summary": "retrieves an attachment for an item", + "parameters": [ + { + "type": "string", + "description": "Item ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Attachment ID", + "name": "attachment_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ItemAttachmentToken" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "tags": [ + "Items" + ], + "summary": "retrieves an attachment for an item", + "parameters": [ + { + "type": "string", + "description": "Item ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Attachment ID", + "name": "attachment_id", + "in": "path", + "required": true + }, + { + "description": "Attachment Update", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/types.ItemAttachmentUpdate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/types.ItemOut" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "tags": [ + "Items" + ], + "summary": "retrieves an attachment for an item", + "parameters": [ + { + "type": "string", + "description": "Item ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Attachment ID", + "name": "attachment_id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "" + } + } + } + }, "/v1/labels": { "get": { "security": [ @@ -810,6 +1026,17 @@ } } }, + "server.ValidationError": { + "type": "object", + "properties": { + "field": { + "type": "string" + }, + "reason": { + "type": "string" + } + } + }, "types.ApiSummary": { "type": "object", "properties": { @@ -873,11 +1100,33 @@ "id": { "type": "string" }, + "type": { + "type": "string" + }, "updatedAt": { "type": "string" } } }, + "types.ItemAttachmentToken": { + "type": "object", + "properties": { + "token": { + "type": "string" + } + } + }, + "types.ItemAttachmentUpdate": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, "types.ItemCreate": { "type": "object", "properties": { @@ -1177,9 +1426,6 @@ "description": { "type": "string" }, - "groupId": { - "type": "string" - }, "id": { "type": "string" }, @@ -1206,9 +1452,6 @@ "description": { "type": "string" }, - "groupId": { - "type": "string" - }, "id": { "type": "string" }, diff --git a/backend/app/api/docs/swagger.yaml b/backend/app/api/docs/swagger.yaml index 10cb358..1749031 100644 --- a/backend/app/api/docs/swagger.yaml +++ b/backend/app/api/docs/swagger.yaml @@ -14,6 +14,13 @@ definitions: items: type: any type: object + server.ValidationError: + properties: + field: + type: string + reason: + type: string + type: object types.ApiSummary: properties: build: @@ -55,9 +62,23 @@ definitions: $ref: '#/definitions/types.DocumentOut' id: type: string + type: + type: string updatedAt: type: string type: object + types.ItemAttachmentToken: + properties: + token: + type: string + type: object + types.ItemAttachmentUpdate: + properties: + title: + type: string + type: + type: string + type: object types.ItemCreate: properties: description: @@ -264,8 +285,6 @@ definitions: type: string description: type: string - groupId: - type: string id: type: string items: @@ -283,8 +302,6 @@ definitions: type: string description: type: string - groupId: - type: string id: type: string name: @@ -503,6 +520,143 @@ paths: summary: updates a item tags: - Items + /v1/items/{id}/attachments: + post: + parameters: + - description: Item ID + in: path + name: id + required: true + type: string + - description: File attachment + in: formData + name: file + required: true + type: file + - description: Type of file + in: formData + name: type + required: true + type: string + - description: name of the file including extension + in: formData + name: name + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.ItemOut' + "422": + description: Unprocessable Entity + schema: + items: + $ref: '#/definitions/server.ValidationError' + type: array + security: + - Bearer: [] + summary: imports items into the database + tags: + - Items + /v1/items/{id}/attachments/{attachment_id}: + delete: + parameters: + - description: Item ID + in: path + name: id + required: true + type: string + - description: Attachment ID + in: path + name: attachment_id + required: true + type: string + responses: + "204": + description: "" + security: + - Bearer: [] + summary: retrieves an attachment for an item + tags: + - Items + get: + parameters: + - description: Item ID + in: path + name: id + required: true + type: string + - description: Attachment ID + in: path + name: attachment_id + required: true + type: string + produces: + - application/octet-stream + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.ItemAttachmentToken' + security: + - Bearer: [] + summary: retrieves an attachment for an item + tags: + - Items + put: + parameters: + - description: Item ID + in: path + name: id + required: true + type: string + - description: Attachment ID + in: path + name: attachment_id + required: true + type: string + - description: Attachment Update + in: body + name: payload + required: true + schema: + $ref: '#/definitions/types.ItemAttachmentUpdate' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/types.ItemOut' + security: + - Bearer: [] + summary: retrieves an attachment for an item + tags: + - Items + /v1/items/{id}/attachments/download: + get: + parameters: + - description: Item ID + in: path + name: id + required: true + type: string + - description: Attachment token + in: query + name: token + required: true + type: string + produces: + - application/octet-stream + responses: + "200": + description: "" + security: + - Bearer: [] + summary: retrieves an attachment for an item + tags: + - Items /v1/items/import: post: parameters: diff --git a/backend/app/api/logger.go b/backend/app/api/logger.go index f0cfee4..6756ffc 100644 --- a/backend/app/api/logger.go +++ b/backend/app/api/logger.go @@ -4,7 +4,7 @@ import ( "os" "strings" - "github.com/hay-kot/content/backend/internal/config" + "github.com/hay-kot/homebox/backend/internal/config" "github.com/rs/zerolog" "github.com/rs/zerolog/log" ) diff --git a/backend/app/api/main.go b/backend/app/api/main.go index b1b90eb..5d233e7 100644 --- a/backend/app/api/main.go +++ b/backend/app/api/main.go @@ -5,12 +5,12 @@ import ( "os" "time" - "github.com/hay-kot/content/backend/app/api/docs" - "github.com/hay-kot/content/backend/ent" - "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/server" + "github.com/hay-kot/homebox/backend/app/api/docs" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/config" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/pkgs/server" _ "github.com/mattn/go-sqlite3" "github.com/rs/zerolog/log" ) @@ -37,10 +37,6 @@ func main() { path = os.Args[1] } - if path == "" { - log.Warn().Msg("No configuration detected, using defaults") - } - cfg, err := config.NewConfig(path) if err != nil { panic(err) @@ -55,17 +51,22 @@ func main() { func run(cfg *config.Config) error { app := new(cfg) - app.setupLogger() + // ========================================================================= // Initialize Database & Repos - c, err := ent.Open(cfg.Database.GetDriver(), cfg.Database.GetUrl()) + err := os.MkdirAll(cfg.Storage.Data, 0755) + if err != nil { + log.Fatal().Err(err).Msg("failed to create data directory") + } + + c, err := ent.Open("sqlite3", cfg.Storage.SqliteUrl) if err != nil { log.Fatal(). Err(err). - Str("driver", cfg.Database.GetDriver()). - Str("url", cfg.Database.GetUrl()). + Str("driver", "sqlite"). + Str("url", cfg.Storage.SqliteUrl). Msg("failed opening connection to sqlite") } defer func(c *ent.Client) { @@ -74,12 +75,14 @@ func run(cfg *config.Config) error { if err := c.Schema.Create(context.Background()); err != nil { log.Fatal(). Err(err). + Str("driver", "sqlite"). + Str("url", cfg.Storage.SqliteUrl). Msg("failed creating schema resources") } app.db = c app.repos = repo.EntAllRepos(c) - app.services = services.NewServices(app.repos) + app.services = services.NewServices(app.repos, cfg.Storage.Data) // ========================================================================= // Start Server diff --git a/backend/app/api/middleware.go b/backend/app/api/middleware.go index aec4917..53f70bb 100644 --- a/backend/app/api/middleware.go +++ b/backend/app/api/middleware.go @@ -8,9 +8,9 @@ import ( "github.com/go-chi/chi/v5" "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/server" + "github.com/hay-kot/homebox/backend/internal/config" + "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index a82a383..1ed1668 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -11,10 +11,10 @@ import ( "path/filepath" "github.com/go-chi/chi/v5" - _ "github.com/hay-kot/content/backend/app/api/docs" - v1 "github.com/hay-kot/content/backend/app/api/v1" - "github.com/hay-kot/content/backend/internal/repo" - "github.com/hay-kot/content/backend/internal/types" + _ "github.com/hay-kot/homebox/backend/app/api/docs" + v1 "github.com/hay-kot/homebox/backend/app/api/v1" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/types" "github.com/rs/zerolog/log" httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware ) @@ -43,7 +43,7 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux { // API Version 1 v1Base := v1.BaseUrlFunc(prefix) - v1Ctrl := v1.NewControllerV1(a.services) + v1Ctrl := v1.NewControllerV1(a.services, v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize)) { r.Get(v1Base("/status"), v1Ctrl.HandleBase(func() bool { return true }, types.Build{ Version: Version, @@ -54,6 +54,10 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux { r.Post(v1Base("/users/register"), v1Ctrl.HandleUserRegistration()) r.Post(v1Base("/users/login"), v1Ctrl.HandleAuthLogin()) + // Attachment download URl needs a `token` query param to be passed in the request. + // and also needs to be outside of the `auth` middleware. + r.Get(v1Base("/items/{id}/attachments/download"), v1Ctrl.HandleItemAttachmentDownload()) + r.Group(func(r chi.Router) { r.Use(a.mwAuthToken) r.Get(v1Base("/users/self"), v1Ctrl.HandleUserSelf()) @@ -81,6 +85,11 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux { r.Get(v1Base("/items/{id}"), v1Ctrl.HandleItemGet()) r.Put(v1Base("/items/{id}"), v1Ctrl.HandleItemUpdate()) r.Delete(v1Base("/items/{id}"), v1Ctrl.HandleItemDelete()) + + r.Post(v1Base("/items/{id}/attachments"), v1Ctrl.HandleItemAttachmentCreate()) + r.Get(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentToken()) + r.Put(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentUpdate()) + r.Delete(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentDelete()) }) } diff --git a/backend/app/api/v1/controller.go b/backend/app/api/v1/controller.go index dda2e20..ac135ef 100644 --- a/backend/app/api/v1/controller.go +++ b/backend/app/api/v1/controller.go @@ -3,13 +3,20 @@ package v1 import ( "net/http" - "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/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/server" ) +func WithMaxUploadSize(maxUploadSize int64) func(*V1Controller) { + return func(ctrl *V1Controller) { + ctrl.maxUploadSize = maxUploadSize + } +} + type V1Controller struct { - svc *services.AllServices + svc *services.AllServices + maxUploadSize int64 } func BaseUrlFunc(prefix string) func(s string) string { @@ -21,7 +28,7 @@ func BaseUrlFunc(prefix string) func(s string) string { return prefixFunc } -func NewControllerV1(svc *services.AllServices) *V1Controller { +func NewControllerV1(svc *services.AllServices, options ...func(*V1Controller)) *V1Controller { ctrl := &V1Controller{ svc: svc, } diff --git a/backend/app/api/v1/controller_test.go b/backend/app/api/v1/controller_test.go index de8a73e..6f555bb 100644 --- a/backend/app/api/v1/controller_test.go +++ b/backend/app/api/v1/controller_test.go @@ -5,7 +5,7 @@ import ( "net/http/httptest" "testing" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/internal/types" "github.com/stretchr/testify/assert" ) diff --git a/backend/app/api/v1/main_test.go b/backend/app/api/v1/main_test.go index 408a641..ee08ccd 100644 --- a/backend/app/api/v1/main_test.go +++ b/backend/app/api/v1/main_test.go @@ -4,10 +4,10 @@ import ( "context" "testing" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/mocks" - "github.com/hay-kot/content/backend/internal/mocks/factories" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/mocks" + "github.com/hay-kot/homebox/backend/internal/mocks/factories" + "github.com/hay-kot/homebox/backend/internal/types" ) var mockHandler = &V1Controller{} diff --git a/backend/app/api/v1/partials.go b/backend/app/api/v1/partials.go index 7fe0cbf..195ce8b 100644 --- a/backend/app/api/v1/partials.go +++ b/backend/app/api/v1/partials.go @@ -5,9 +5,9 @@ import ( "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/server" + "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) diff --git a/backend/app/api/v1/v1_ctrl_auth.go b/backend/app/api/v1/v1_ctrl_auth.go index 851a638..2a44664 100644 --- a/backend/app/api/v1/v1_ctrl_auth.go +++ b/backend/app/api/v1/v1_ctrl_auth.go @@ -4,9 +4,9 @@ import ( "errors" "net/http" - "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/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) diff --git a/backend/app/api/v1/v1_ctrl_items.go b/backend/app/api/v1/v1_ctrl_items.go index 23a0d92..7de278e 100644 --- a/backend/app/api/v1/v1_ctrl_items.go +++ b/backend/app/api/v1/v1_ctrl_items.go @@ -4,9 +4,9 @@ import ( "encoding/csv" "net/http" - "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/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) @@ -64,7 +64,7 @@ func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc { // @Summary deletes a item // @Tags Items // @Produce json -// @Param id path string true "Item ID" +// @Param id path string true "Item ID" // @Success 204 // @Router /v1/items/{id} [DELETE] // @Security Bearer @@ -114,7 +114,7 @@ func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc { // @Summary updates a item // @Tags Items // @Produce json -// @Param id path string true "Item ID" +// @Param id path string true "Item ID" // @Param payload body types.ItemUpdate true "Item Data" // @Success 200 {object} types.ItemOut // @Router /v1/items/{id} [PUT] diff --git a/backend/app/api/v1/v1_ctrl_items_attachments.go b/backend/app/api/v1/v1_ctrl_items_attachments.go new file mode 100644 index 0000000..b373ead --- /dev/null +++ b/backend/app/api/v1/v1_ctrl_items_attachments.go @@ -0,0 +1,237 @@ +package v1 + +import ( + "errors" + "fmt" + "net/http" + "path/filepath" + + "github.com/go-chi/chi/v5" + "github.com/google/uuid" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/server" + "github.com/rs/zerolog/log" +) + +// HandleItemsImport godocs +// @Summary imports items into the database +// @Tags Items +// @Produce json +// @Param id path string true "Item ID" +// @Param file formData file true "File attachment" +// @Param type formData string true "Type of file" +// @Param name formData string true "name of the file including extension" +// @Success 200 {object} types.ItemOut +// @Failure 422 {object} []server.ValidationError +// @Router /v1/items/{id}/attachments [POST] +// @Security Bearer +func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + err := r.ParseMultipartForm(ctrl.maxUploadSize << 20) + if err != nil { + log.Err(err).Msg("failed to parse multipart form") + server.RespondError(w, http.StatusBadRequest, errors.New("failed to parse multipart form")) + return + } + + errs := make(server.ValidationErrors, 0) + + file, _, err := r.FormFile("file") + if err != nil { + switch { + case errors.Is(err, http.ErrMissingFile): + log.Debug().Msg("file for attachment is missing") + errs = errs.Append("file", "file is required") + default: + log.Err(err).Msg("failed to get file from form") + server.RespondServerError(w) + return + } + } + + attachmentName := r.FormValue("name") + if attachmentName == "" { + log.Debug().Msg("failed to get name from form") + errs = errs.Append("name", "name is required") + } + + if errs.HasErrors() { + server.Respond(w, http.StatusUnprocessableEntity, errs) + return + } + + attachmentType := r.FormValue("type") + if attachmentType == "" { + attachmentType = attachment.TypeAttachment.String() + } + + id, _, err := ctrl.partialParseIdAndUser(w, r) + if err != nil { + return + } + + ctx := services.NewContext(r.Context()) + + item, err := ctrl.svc.Items.AttachmentAdd( + ctx, + id, + attachmentName, + attachment.Type(attachmentType), + file, + ) + + if err != nil { + log.Err(err).Msg("failed to add attachment") + server.RespondServerError(w) + return + } + + server.Respond(w, http.StatusCreated, item) + } +} + +// HandleItemAttachmentGet godocs +// @Summary retrieves an attachment for an item +// @Tags Items +// @Produce application/octet-stream +// @Param id path string true "Item ID" +// @Param token query string true "Attachment token" +// @Success 200 +// @Router /v1/items/{id}/attachments/download [GET] +// @Security Bearer +func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + token := server.GetParam(r, "token", "") + + path, err := ctrl.svc.Items.AttachmentPath(r.Context(), token) + + if err != nil { + log.Err(err).Msg("failed to get attachment") + server.RespondServerError(w) + return + } + + w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filepath.Base(path))) + w.Header().Set("Content-Type", "application/octet-stream") + http.ServeFile(w, r, path) + } +} + +// HandleItemAttachmentToken godocs +// @Summary retrieves an attachment for an item +// @Tags Items +// @Produce application/octet-stream +// @Param id path string true "Item ID" +// @Param attachment_id path string true "Attachment ID" +// @Success 200 {object} types.ItemAttachmentToken +// @Router /v1/items/{id}/attachments/{attachment_id} [GET] +// @Security Bearer +func (ctrl *V1Controller) HandleItemAttachmentToken() http.HandlerFunc { + return ctrl.handleItemAttachmentsHandler +} + +// HandleItemAttachmentDelete godocs +// @Summary retrieves an attachment for an item +// @Tags Items +// @Param id path string true "Item ID" +// @Param attachment_id path string true "Attachment ID" +// @Success 204 +// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE] +// @Security Bearer +func (ctrl *V1Controller) HandleItemAttachmentDelete() http.HandlerFunc { + return ctrl.handleItemAttachmentsHandler +} + +// HandleItemAttachmentUpdate godocs +// @Summary retrieves an attachment for an item +// @Tags Items +// @Param id path string true "Item ID" +// @Param attachment_id path string true "Attachment ID" +// @Param payload body types.ItemAttachmentUpdate true "Attachment Update" +// @Success 200 {object} types.ItemOut +// @Router /v1/items/{id}/attachments/{attachment_id} [PUT] +// @Security Bearer +func (ctrl *V1Controller) HandleItemAttachmentUpdate() http.HandlerFunc { + return ctrl.handleItemAttachmentsHandler +} + +func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r *http.Request) { + uid, user, err := ctrl.partialParseIdAndUser(w, r) + if err != nil { + return + } + + attachmentId, err := uuid.Parse(chi.URLParam(r, "attachment_id")) + if err != nil { + log.Err(err).Msg("failed to parse attachment_id param") + server.RespondError(w, http.StatusBadRequest, err) + return + } + + ctx := services.NewContext(r.Context()) + + switch r.Method { + + // Token Handler + case http.MethodGet: + token, err := ctrl.svc.Items.AttachmentToken(ctx, uid, attachmentId) + if err != nil { + switch err { + case services.ErrNotFound: + log.Err(err). + Str("id", attachmentId.String()). + Msg("failed to find attachment with id") + + server.RespondError(w, http.StatusNotFound, err) + + case services.ErrFileNotFound: + log.Err(err). + Str("id", attachmentId.String()). + Msg("failed to find file path for attachment with id") + log.Warn().Msg("attachment with no file path removed from database") + + server.RespondError(w, http.StatusNotFound, err) + + default: + log.Err(err).Msg("failed to get attachment") + server.RespondServerError(w) + return + } + } + + server.Respond(w, http.StatusOK, types.ItemAttachmentToken{Token: token}) + + // Delete Attachment Handler + case http.MethodDelete: + err = ctrl.svc.Items.AttachmentDelete(r.Context(), user.GroupID, uid, attachmentId) + if err != nil { + log.Err(err).Msg("failed to delete attachment") + server.RespondServerError(w) + return + } + + server.Respond(w, http.StatusNoContent, nil) + + // Update Attachment Handler + case http.MethodPut: + var attachment types.ItemAttachmentUpdate + err = server.Decode(r, &attachment) + if err != nil { + log.Err(err).Msg("failed to decode attachment") + server.RespondError(w, http.StatusBadRequest, err) + return + } + + attachment.ID = attachmentId + val, err := ctrl.svc.Items.AttachmentUpdate(ctx, uid, &attachment) + if err != nil { + log.Err(err).Msg("failed to delete attachment") + server.RespondServerError(w) + return + } + + server.Respond(w, http.StatusOK, val) + } +} diff --git a/backend/app/api/v1/v1_ctrl_labels.go b/backend/app/api/v1/v1_ctrl_labels.go index 359d385..38bd666 100644 --- a/backend/app/api/v1/v1_ctrl_labels.go +++ b/backend/app/api/v1/v1_ctrl_labels.go @@ -3,10 +3,10 @@ package v1 import ( "net/http" - "github.com/hay-kot/content/backend/ent" - "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/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) diff --git a/backend/app/api/v1/v1_ctrl_locations.go b/backend/app/api/v1/v1_ctrl_locations.go index 38de872..6126d3d 100644 --- a/backend/app/api/v1/v1_ctrl_locations.go +++ b/backend/app/api/v1/v1_ctrl_locations.go @@ -3,10 +3,10 @@ package v1 import ( "net/http" - "github.com/hay-kot/content/backend/ent" - "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/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) diff --git a/backend/app/api/v1/v1_ctrl_user.go b/backend/app/api/v1/v1_ctrl_user.go index f7c4de6..0a4b7c7 100644 --- a/backend/app/api/v1/v1_ctrl_user.go +++ b/backend/app/api/v1/v1_ctrl_user.go @@ -4,9 +4,9 @@ import ( "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/server" + "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) diff --git a/backend/config.template.yml b/backend/config.template.yml deleted file mode 100644 index 7ee50a6..0000000 --- a/backend/config.template.yml +++ /dev/null @@ -1,19 +0,0 @@ ---- -mode: development -swagger: - host: localhost:7745 - scheme: http -web: - port: 7745 - host: "" -database: - driver: sqlite3 - sqlite-url: ./homebox.db?_fk=1 -logger: - level: debug -mailer: - host: smtp.example.com - port: 465 - username: - password: - from: example@email.com diff --git a/backend/ent/attachment.go b/backend/ent/attachment.go index b22b8db..8e70341 100644 --- a/backend/ent/attachment.go +++ b/backend/ent/attachment.go @@ -9,9 +9,9 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/item" ) // Attachment is the model entity for the Attachment schema. diff --git a/backend/ent/attachment/where.go b/backend/ent/attachment/where.go index c601949..e898d49 100644 --- a/backend/ent/attachment/where.go +++ b/backend/ent/attachment/where.go @@ -8,7 +8,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/attachment_create.go b/backend/ent/attachment_create.go index fdce24b..75d6cec 100644 --- a/backend/ent/attachment_create.go +++ b/backend/ent/attachment_create.go @@ -11,9 +11,9 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/item" ) // AttachmentCreate is the builder for creating a Attachment entity. diff --git a/backend/ent/attachment_delete.go b/backend/ent/attachment_delete.go index 0b858cc..a1cda49 100644 --- a/backend/ent/attachment_delete.go +++ b/backend/ent/attachment_delete.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // AttachmentDelete is the builder for deleting a Attachment entity. diff --git a/backend/ent/attachment_query.go b/backend/ent/attachment_query.go index f657057..d088cce 100644 --- a/backend/ent/attachment_query.go +++ b/backend/ent/attachment_query.go @@ -11,10 +11,10 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // AttachmentQuery is the builder for querying Attachment entities. diff --git a/backend/ent/attachment_update.go b/backend/ent/attachment_update.go index 53b5feb..1801c22 100644 --- a/backend/ent/attachment_update.go +++ b/backend/ent/attachment_update.go @@ -12,10 +12,10 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // AttachmentUpdate is the builder for updating Attachment entities. diff --git a/backend/ent/authtokens.go b/backend/ent/authtokens.go index 94784d8..24731d5 100644 --- a/backend/ent/authtokens.go +++ b/backend/ent/authtokens.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/user" ) // AuthTokens is the model entity for the AuthTokens schema. diff --git a/backend/ent/authtokens/where.go b/backend/ent/authtokens/where.go index 015b4af..edb237b 100644 --- a/backend/ent/authtokens/where.go +++ b/backend/ent/authtokens/where.go @@ -8,7 +8,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/authtokens_create.go b/backend/ent/authtokens_create.go index 4336c2b..491711a 100644 --- a/backend/ent/authtokens_create.go +++ b/backend/ent/authtokens_create.go @@ -11,8 +11,8 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/user" ) // AuthTokensCreate is the builder for creating a AuthTokens entity. diff --git a/backend/ent/authtokens_delete.go b/backend/ent/authtokens_delete.go index 682f0d5..7b86122 100644 --- a/backend/ent/authtokens_delete.go +++ b/backend/ent/authtokens_delete.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // AuthTokensDelete is the builder for deleting a AuthTokens entity. diff --git a/backend/ent/authtokens_query.go b/backend/ent/authtokens_query.go index 38fa9c5..d1484e6 100644 --- a/backend/ent/authtokens_query.go +++ b/backend/ent/authtokens_query.go @@ -11,9 +11,9 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/predicate" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/user" ) // AuthTokensQuery is the builder for querying AuthTokens entities. diff --git a/backend/ent/authtokens_update.go b/backend/ent/authtokens_update.go index 0c64f16..11e06f2 100644 --- a/backend/ent/authtokens_update.go +++ b/backend/ent/authtokens_update.go @@ -12,9 +12,9 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/predicate" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/user" ) // AuthTokensUpdate is the builder for updating AuthTokens entities. diff --git a/backend/ent/client.go b/backend/ent/client.go index fd39792..63c91ac 100644 --- a/backend/ent/client.go +++ b/backend/ent/client.go @@ -9,18 +9,18 @@ import ( "log" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/migrate" + "github.com/hay-kot/homebox/backend/ent/migrate" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/user" "entgo.io/ent/dialect" "entgo.io/ent/dialect/sql" diff --git a/backend/ent/document.go b/backend/ent/document.go index 14a33ca..aef3bc2 100644 --- a/backend/ent/document.go +++ b/backend/ent/document.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/group" ) // Document is the model entity for the Document schema. diff --git a/backend/ent/document/where.go b/backend/ent/document/where.go index f859293..c4efce5 100644 --- a/backend/ent/document/where.go +++ b/backend/ent/document/where.go @@ -8,7 +8,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/document_create.go b/backend/ent/document_create.go index ea98c1e..4411e16 100644 --- a/backend/ent/document_create.go +++ b/backend/ent/document_create.go @@ -11,10 +11,10 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/group" ) // DocumentCreate is the builder for creating a Document entity. diff --git a/backend/ent/document_delete.go b/backend/ent/document_delete.go index 2b5f19a..06ccaf1 100644 --- a/backend/ent/document_delete.go +++ b/backend/ent/document_delete.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // DocumentDelete is the builder for deleting a Document entity. diff --git a/backend/ent/document_query.go b/backend/ent/document_query.go index 0739e02..1f43079 100644 --- a/backend/ent/document_query.go +++ b/backend/ent/document_query.go @@ -12,11 +12,11 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // DocumentQuery is the builder for querying Document entities. diff --git a/backend/ent/document_update.go b/backend/ent/document_update.go index 6aab168..fb1b971 100644 --- a/backend/ent/document_update.go +++ b/backend/ent/document_update.go @@ -12,11 +12,11 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // DocumentUpdate is the builder for updating Document entities. diff --git a/backend/ent/documenttoken.go b/backend/ent/documenttoken.go index c3b0a9e..c4de9a5 100644 --- a/backend/ent/documenttoken.go +++ b/backend/ent/documenttoken.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" ) // DocumentToken is the model entity for the DocumentToken schema. diff --git a/backend/ent/documenttoken/where.go b/backend/ent/documenttoken/where.go index 918b975..9975a33 100644 --- a/backend/ent/documenttoken/where.go +++ b/backend/ent/documenttoken/where.go @@ -8,7 +8,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/documenttoken_create.go b/backend/ent/documenttoken_create.go index 65908b6..b4585d5 100644 --- a/backend/ent/documenttoken_create.go +++ b/backend/ent/documenttoken_create.go @@ -11,8 +11,8 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" ) // DocumentTokenCreate is the builder for creating a DocumentToken entity. diff --git a/backend/ent/documenttoken_delete.go b/backend/ent/documenttoken_delete.go index bc8f488..fa9b7a1 100644 --- a/backend/ent/documenttoken_delete.go +++ b/backend/ent/documenttoken_delete.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // DocumentTokenDelete is the builder for deleting a DocumentToken entity. diff --git a/backend/ent/documenttoken_query.go b/backend/ent/documenttoken_query.go index bd48c10..f0c2198 100644 --- a/backend/ent/documenttoken_query.go +++ b/backend/ent/documenttoken_query.go @@ -11,9 +11,9 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // DocumentTokenQuery is the builder for querying DocumentToken entities. diff --git a/backend/ent/documenttoken_update.go b/backend/ent/documenttoken_update.go index e4586be..dc77dcc 100644 --- a/backend/ent/documenttoken_update.go +++ b/backend/ent/documenttoken_update.go @@ -12,9 +12,9 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // DocumentTokenUpdate is the builder for updating DocumentToken entities. diff --git a/backend/ent/ent.go b/backend/ent/ent.go index 997c25e..0364759 100644 --- a/backend/ent/ent.go +++ b/backend/ent/ent.go @@ -10,16 +10,16 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/user" ) // ent aliases to avoid import conflicts in user's code. diff --git a/backend/ent/enttest/enttest.go b/backend/ent/enttest/enttest.go index b14ee60..ee46d3d 100644 --- a/backend/ent/enttest/enttest.go +++ b/backend/ent/enttest/enttest.go @@ -5,12 +5,12 @@ package enttest import ( "context" - "github.com/hay-kot/content/backend/ent" + "github.com/hay-kot/homebox/backend/ent" // required by schema hooks. - _ "github.com/hay-kot/content/backend/ent/runtime" + _ "github.com/hay-kot/homebox/backend/ent/runtime" "entgo.io/ent/dialect/sql/schema" - "github.com/hay-kot/content/backend/ent/migrate" + "github.com/hay-kot/homebox/backend/ent/migrate" ) type ( diff --git a/backend/ent/group.go b/backend/ent/group.go index 39f38ca..65d956a 100644 --- a/backend/ent/group.go +++ b/backend/ent/group.go @@ -9,7 +9,7 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/group" ) // Group is the model entity for the Group schema. diff --git a/backend/ent/group/where.go b/backend/ent/group/where.go index f6c759d..04f7ec8 100644 --- a/backend/ent/group/where.go +++ b/backend/ent/group/where.go @@ -8,7 +8,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/group_create.go b/backend/ent/group_create.go index a72eefe..86080f2 100644 --- a/backend/ent/group_create.go +++ b/backend/ent/group_create.go @@ -11,12 +11,12 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/user" ) // GroupCreate is the builder for creating a Group entity. diff --git a/backend/ent/group_delete.go b/backend/ent/group_delete.go index a15128f..23dfa0c 100644 --- a/backend/ent/group_delete.go +++ b/backend/ent/group_delete.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // GroupDelete is the builder for deleting a Group entity. diff --git a/backend/ent/group_query.go b/backend/ent/group_query.go index cb3a1c6..e82f725 100644 --- a/backend/ent/group_query.go +++ b/backend/ent/group_query.go @@ -12,13 +12,13 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/predicate" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/user" ) // GroupQuery is the builder for querying Group entities. diff --git a/backend/ent/group_update.go b/backend/ent/group_update.go index 4ebf709..0c60708 100644 --- a/backend/ent/group_update.go +++ b/backend/ent/group_update.go @@ -12,13 +12,13 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/predicate" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/user" ) // GroupUpdate is the builder for updating Group entities. diff --git a/backend/ent/hook/hook.go b/backend/ent/hook/hook.go index 095e929..fe2ec6d 100644 --- a/backend/ent/hook/hook.go +++ b/backend/ent/hook/hook.go @@ -6,7 +6,7 @@ import ( "context" "fmt" - "github.com/hay-kot/content/backend/ent" + "github.com/hay-kot/homebox/backend/ent" ) // The AttachmentFunc type is an adapter to allow the use of ordinary diff --git a/backend/ent/item.go b/backend/ent/item.go index d2d6a6a..b58cbd2 100644 --- a/backend/ent/item.go +++ b/backend/ent/item.go @@ -9,9 +9,9 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/location" ) // Item is the model entity for the Item schema. diff --git a/backend/ent/item/where.go b/backend/ent/item/where.go index 258af9b..6cec831 100644 --- a/backend/ent/item/where.go +++ b/backend/ent/item/where.go @@ -8,7 +8,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/item_create.go b/backend/ent/item_create.go index e229099..1ad1837 100644 --- a/backend/ent/item_create.go +++ b/backend/ent/item_create.go @@ -11,12 +11,12 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/location" ) // ItemCreate is the builder for creating a Item entity. diff --git a/backend/ent/item_delete.go b/backend/ent/item_delete.go index 9fea485..1f8b6f8 100644 --- a/backend/ent/item_delete.go +++ b/backend/ent/item_delete.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ItemDelete is the builder for deleting a Item entity. diff --git a/backend/ent/item_query.go b/backend/ent/item_query.go index a922b5b..70ea7d4 100644 --- a/backend/ent/item_query.go +++ b/backend/ent/item_query.go @@ -12,13 +12,13 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ItemQuery is the builder for querying Item entities. diff --git a/backend/ent/item_update.go b/backend/ent/item_update.go index d2a691d..ef31b2a 100644 --- a/backend/ent/item_update.go +++ b/backend/ent/item_update.go @@ -12,13 +12,13 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ItemUpdate is the builder for updating Item entities. diff --git a/backend/ent/itemfield.go b/backend/ent/itemfield.go index 9dfbf65..d252ec9 100644 --- a/backend/ent/itemfield.go +++ b/backend/ent/itemfield.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" ) // ItemField is the model entity for the ItemField schema. diff --git a/backend/ent/itemfield/where.go b/backend/ent/itemfield/where.go index e319aa6..ebe4b61 100644 --- a/backend/ent/itemfield/where.go +++ b/backend/ent/itemfield/where.go @@ -8,7 +8,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/itemfield_create.go b/backend/ent/itemfield_create.go index 3e01a89..ad9fd96 100644 --- a/backend/ent/itemfield_create.go +++ b/backend/ent/itemfield_create.go @@ -11,8 +11,8 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" ) // ItemFieldCreate is the builder for creating a ItemField entity. diff --git a/backend/ent/itemfield_delete.go b/backend/ent/itemfield_delete.go index 2db4de3..e5ba38f 100644 --- a/backend/ent/itemfield_delete.go +++ b/backend/ent/itemfield_delete.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/itemfield" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ItemFieldDelete is the builder for deleting a ItemField entity. diff --git a/backend/ent/itemfield_query.go b/backend/ent/itemfield_query.go index d26cfcf..ac1b9e3 100644 --- a/backend/ent/itemfield_query.go +++ b/backend/ent/itemfield_query.go @@ -11,9 +11,9 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ItemFieldQuery is the builder for querying ItemField entities. diff --git a/backend/ent/itemfield_update.go b/backend/ent/itemfield_update.go index 1ba66df..cac8fed 100644 --- a/backend/ent/itemfield_update.go +++ b/backend/ent/itemfield_update.go @@ -12,9 +12,9 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ItemFieldUpdate is the builder for updating ItemField entities. diff --git a/backend/ent/label.go b/backend/ent/label.go index a010753..39420f4 100644 --- a/backend/ent/label.go +++ b/backend/ent/label.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/label" ) // Label is the model entity for the Label schema. diff --git a/backend/ent/label/where.go b/backend/ent/label/where.go index 01d0f2d..e01eea7 100644 --- a/backend/ent/label/where.go +++ b/backend/ent/label/where.go @@ -8,7 +8,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/label_create.go b/backend/ent/label_create.go index 65db3c6..7330747 100644 --- a/backend/ent/label_create.go +++ b/backend/ent/label_create.go @@ -11,9 +11,9 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/label" ) // LabelCreate is the builder for creating a Label entity. diff --git a/backend/ent/label_delete.go b/backend/ent/label_delete.go index e9eb6bc..aef8be0 100644 --- a/backend/ent/label_delete.go +++ b/backend/ent/label_delete.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // LabelDelete is the builder for deleting a Label entity. diff --git a/backend/ent/label_query.go b/backend/ent/label_query.go index b54aa58..80b4af5 100644 --- a/backend/ent/label_query.go +++ b/backend/ent/label_query.go @@ -12,10 +12,10 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // LabelQuery is the builder for querying Label entities. diff --git a/backend/ent/label_update.go b/backend/ent/label_update.go index 8135a56..ef0af15 100644 --- a/backend/ent/label_update.go +++ b/backend/ent/label_update.go @@ -12,10 +12,10 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // LabelUpdate is the builder for updating Label entities. diff --git a/backend/ent/location.go b/backend/ent/location.go index 4222152..e0c9517 100644 --- a/backend/ent/location.go +++ b/backend/ent/location.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/location" ) // Location is the model entity for the Location schema. diff --git a/backend/ent/location/where.go b/backend/ent/location/where.go index 625a038..f72c16d 100644 --- a/backend/ent/location/where.go +++ b/backend/ent/location/where.go @@ -8,7 +8,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/location_create.go b/backend/ent/location_create.go index a468ce9..df6a88e 100644 --- a/backend/ent/location_create.go +++ b/backend/ent/location_create.go @@ -11,9 +11,9 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/location" ) // LocationCreate is the builder for creating a Location entity. diff --git a/backend/ent/location_delete.go b/backend/ent/location_delete.go index 5ec513b..8bc6db3 100644 --- a/backend/ent/location_delete.go +++ b/backend/ent/location_delete.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // LocationDelete is the builder for deleting a Location entity. diff --git a/backend/ent/location_query.go b/backend/ent/location_query.go index 447ed9f..5edd2d2 100644 --- a/backend/ent/location_query.go +++ b/backend/ent/location_query.go @@ -12,10 +12,10 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // LocationQuery is the builder for querying Location entities. diff --git a/backend/ent/location_update.go b/backend/ent/location_update.go index 0506558..064634c 100644 --- a/backend/ent/location_update.go +++ b/backend/ent/location_update.go @@ -12,10 +12,10 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // LocationUpdate is the builder for updating Location entities. diff --git a/backend/ent/mutation.go b/backend/ent/mutation.go index ed69d15..bbd71a5 100644 --- a/backend/ent/mutation.go +++ b/backend/ent/mutation.go @@ -10,17 +10,17 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/predicate" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/user" "entgo.io/ent" ) diff --git a/backend/ent/runtime.go b/backend/ent/runtime.go index a82fb10..6414b69 100644 --- a/backend/ent/runtime.go +++ b/backend/ent/runtime.go @@ -6,17 +6,17 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/ent/itemfield" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/ent/schema" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/ent/schema" + "github.com/hay-kot/homebox/backend/ent/user" ) // The init function reads all schema descriptors with runtime code diff --git a/backend/ent/runtime/runtime.go b/backend/ent/runtime/runtime.go index f07467e..e0a5718 100644 --- a/backend/ent/runtime/runtime.go +++ b/backend/ent/runtime/runtime.go @@ -2,7 +2,7 @@ package runtime -// The schema-stitching logic is generated in github.com/hay-kot/content/backend/ent/runtime.go +// The schema-stitching logic is generated in github.com/hay-kot/homebox/backend/ent/runtime.go const ( Version = "v0.11.2" // Version of ent codegen. diff --git a/backend/ent/schema/attachment.go b/backend/ent/schema/attachment.go index b0adb8c..4a13ba8 100644 --- a/backend/ent/schema/attachment.go +++ b/backend/ent/schema/attachment.go @@ -4,7 +4,7 @@ import ( "entgo.io/ent" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/ent/schema/mixins" ) // Attachment holds the schema definition for the Attachment entity. diff --git a/backend/ent/schema/auth_tokens.go b/backend/ent/schema/auth_tokens.go index 9063581..41beafa 100644 --- a/backend/ent/schema/auth_tokens.go +++ b/backend/ent/schema/auth_tokens.go @@ -7,7 +7,7 @@ import ( "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" "entgo.io/ent/schema/index" - "github.com/hay-kot/content/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/ent/schema/mixins" ) // AuthTokens holds the schema definition for the AuthTokens entity. diff --git a/backend/ent/schema/document.go b/backend/ent/schema/document.go index 9797b0f..f6b2c57 100644 --- a/backend/ent/schema/document.go +++ b/backend/ent/schema/document.go @@ -5,7 +5,7 @@ import ( "entgo.io/ent/dialect/entsql" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/ent/schema/mixins" ) // Document holds the schema definition for the Document entity. diff --git a/backend/ent/schema/document_token.go b/backend/ent/schema/document_token.go index 8a4d10a..7423996 100644 --- a/backend/ent/schema/document_token.go +++ b/backend/ent/schema/document_token.go @@ -7,7 +7,7 @@ import ( "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" "entgo.io/ent/schema/index" - "github.com/hay-kot/content/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/ent/schema/mixins" ) // DocumentToken holds the schema definition for the DocumentToken entity. diff --git a/backend/ent/schema/group.go b/backend/ent/schema/group.go index a5c863e..97237ca 100644 --- a/backend/ent/schema/group.go +++ b/backend/ent/schema/group.go @@ -5,7 +5,7 @@ import ( "entgo.io/ent/dialect/entsql" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/ent/schema/mixins" ) // Group holds the schema definition for the Group entity. diff --git a/backend/ent/schema/item.go b/backend/ent/schema/item.go index 127f8d8..9728fd8 100644 --- a/backend/ent/schema/item.go +++ b/backend/ent/schema/item.go @@ -6,7 +6,7 @@ import ( "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" "entgo.io/ent/schema/index" - "github.com/hay-kot/content/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/ent/schema/mixins" ) // Item holds the schema definition for the Item entity. diff --git a/backend/ent/schema/item_field.go b/backend/ent/schema/item_field.go index e5d157c..56be98a 100644 --- a/backend/ent/schema/item_field.go +++ b/backend/ent/schema/item_field.go @@ -6,7 +6,7 @@ import ( "entgo.io/ent" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/ent/schema/mixins" ) // ItemField holds the schema definition for the ItemField entity. diff --git a/backend/ent/schema/label.go b/backend/ent/schema/label.go index 7f60552..7f65d55 100644 --- a/backend/ent/schema/label.go +++ b/backend/ent/schema/label.go @@ -5,7 +5,7 @@ import ( "entgo.io/ent/dialect/entsql" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/ent/schema/mixins" ) // Label holds the schema definition for the Label entity. diff --git a/backend/ent/schema/location.go b/backend/ent/schema/location.go index 4206983..74e0abb 100644 --- a/backend/ent/schema/location.go +++ b/backend/ent/schema/location.go @@ -4,7 +4,7 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/entsql" "entgo.io/ent/schema/edge" - "github.com/hay-kot/content/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/ent/schema/mixins" ) // Location holds the schema definition for the Location entity. diff --git a/backend/ent/schema/user.go b/backend/ent/schema/user.go index 6fe72b6..b058b20 100644 --- a/backend/ent/schema/user.go +++ b/backend/ent/schema/user.go @@ -5,7 +5,7 @@ import ( "entgo.io/ent/dialect/entsql" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/ent/schema/mixins" ) // User holds the schema definition for the User entity. diff --git a/backend/ent/user.go b/backend/ent/user.go index b3387f4..ff21fa1 100644 --- a/backend/ent/user.go +++ b/backend/ent/user.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/user" ) // User is the model entity for the User schema. diff --git a/backend/ent/user/where.go b/backend/ent/user/where.go index b7b468c..d020d3b 100644 --- a/backend/ent/user/where.go +++ b/backend/ent/user/where.go @@ -8,7 +8,7 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/user_create.go b/backend/ent/user_create.go index c0f4c25..51c8151 100644 --- a/backend/ent/user_create.go +++ b/backend/ent/user_create.go @@ -11,9 +11,9 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/user" ) // UserCreate is the builder for creating a User entity. diff --git a/backend/ent/user_delete.go b/backend/ent/user_delete.go index cb23cc3..6d8b949 100644 --- a/backend/ent/user_delete.go +++ b/backend/ent/user_delete.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" - "github.com/hay-kot/content/backend/ent/predicate" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/user" ) // UserDelete is the builder for deleting a User entity. diff --git a/backend/ent/user_query.go b/backend/ent/user_query.go index 8dc2461..f83e90f 100644 --- a/backend/ent/user_query.go +++ b/backend/ent/user_query.go @@ -12,10 +12,10 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/predicate" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/user" ) // UserQuery is the builder for querying User entities. diff --git a/backend/ent/user_update.go b/backend/ent/user_update.go index 1cccc6f..7d9bbad 100644 --- a/backend/ent/user_update.go +++ b/backend/ent/user_update.go @@ -12,10 +12,10 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/predicate" - "github.com/hay-kot/content/backend/ent/user" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/ent/user" ) // UserUpdate is the builder for updating User entities. diff --git a/backend/go.mod b/backend/go.mod index 0d9d4eb..18f63b6 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -1,4 +1,4 @@ -module github.com/hay-kot/content/backend +module github.com/hay-kot/homebox/backend go 1.19 diff --git a/backend/internal/config/conf.go b/backend/internal/config/conf.go index d9ffe0c..7d63ea8 100644 --- a/backend/internal/config/conf.go +++ b/backend/internal/config/conf.go @@ -17,12 +17,12 @@ const ( ) type Config struct { - Mode string `yaml:"mode" conf:"default:development"` // development or production - Web WebConfig `yaml:"web"` - Database Database `yaml:"database"` - Log LoggerConf `yaml:"logger"` - Mailer MailerConf `yaml:"mailer"` - Swagger SwaggerConf `yaml:"swagger"` + Mode string `yaml:"mode" conf:"default:development"` // development or production + Web WebConfig `yaml:"web"` + Storage Storage `yaml:"storage"` + Log LoggerConf `yaml:"logger"` + Mailer MailerConf `yaml:"mailer"` + Swagger SwaggerConf `yaml:"swagger"` } type SwaggerConf struct { @@ -31,8 +31,9 @@ type SwaggerConf struct { } type WebConfig struct { - Port string `yaml:"port" conf:"default:7745"` - Host string `yaml:"host"` + Port string `yaml:"port" conf:"default:7745"` + Host string `yaml:"host"` + MaxUploadSize int64 `yaml:"max_file_upload" conf:"default:10"` } // NewConfig parses the CLI/Config file and returns a Config struct. If the file argument is an empty string, the diff --git a/backend/internal/config/conf_database.go b/backend/internal/config/conf_database.go index 7b396bd..047d5d2 100644 --- a/backend/internal/config/conf_database.go +++ b/backend/internal/config/conf_database.go @@ -4,20 +4,8 @@ const ( DriverSqlite3 = "sqlite3" ) -type Database struct { - Driver string `yaml:"driver" conf:"default:sqlite3"` - SqliteUrl string `yaml:"sqlite-url" conf:"default:file:ent?mode=memory&cache=shared&_fk=1"` -} - -func (d *Database) GetDriver() string { - return d.Driver -} - -func (d *Database) GetUrl() string { - switch d.Driver { - case DriverSqlite3: - return d.SqliteUrl - default: - panic("unknown database driver") - } +type Storage struct { + // Data is the path to the root directory + Data string `yaml:"data" conf:"default:./homebox-data"` + SqliteUrl string `yaml:"sqlite-url" conf:"default:./homebox-data/homebox.db?_fk=1"` } diff --git a/backend/internal/config/conf_database_test.go b/backend/internal/config/conf_database_test.go deleted file mode 100644 index f11c21c..0000000 --- a/backend/internal/config/conf_database_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package config - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func Test_DatabaseConfig_Sqlite(t *testing.T) { - dbConf := &Database{ - Driver: DriverSqlite3, - SqliteUrl: "file:ent?mode=memory&cache=shared&_fk=1", - } - - assert.Equal(t, "sqlite3", dbConf.GetDriver()) - assert.Equal(t, "file:ent?mode=memory&cache=shared&_fk=1", dbConf.GetUrl()) -} - -func Test_DatabaseConfig_Unknown(t *testing.T) { - dbConf := &Database{ - Driver: "null", - } - - assert.Panics(t, func() { dbConf.GetUrl() }) - -} diff --git a/backend/internal/mocks/factories/users.go b/backend/internal/mocks/factories/users.go index 1265768..4f9389d 100644 --- a/backend/internal/mocks/factories/users.go +++ b/backend/internal/mocks/factories/users.go @@ -1,8 +1,8 @@ package factories import ( - "github.com/hay-kot/content/backend/internal/types" - "github.com/hay-kot/content/backend/pkgs/faker" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/faker" ) func UserFactory() types.UserCreate { diff --git a/backend/internal/mocks/mocker_services.go b/backend/internal/mocks/mocker_services.go index e44b464..d1e80bd 100644 --- a/backend/internal/mocks/mocker_services.go +++ b/backend/internal/mocks/mocker_services.go @@ -1,10 +1,10 @@ package mocks import ( - "github.com/hay-kot/content/backend/internal/repo" - "github.com/hay-kot/content/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/services" ) func GetMockServices(repos *repo.AllRepos) *services.AllServices { - return services.NewServices(repos) + return services.NewServices(repos, "/tmp/homebox") } diff --git a/backend/internal/mocks/mocks_ent_repo.go b/backend/internal/mocks/mocks_ent_repo.go index e0b7e81..4b7abcc 100644 --- a/backend/internal/mocks/mocks_ent_repo.go +++ b/backend/internal/mocks/mocks_ent_repo.go @@ -3,8 +3,8 @@ package mocks import ( "context" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/repo" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/repo" _ "github.com/mattn/go-sqlite3" ) diff --git a/backend/internal/repo/main_test.go b/backend/internal/repo/main_test.go index 5644178..14bfbd8 100644 --- a/backend/internal/repo/main_test.go +++ b/backend/internal/repo/main_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/pkgs/faker" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/pkgs/faker" _ "github.com/mattn/go-sqlite3" ) diff --git a/backend/internal/repo/repo_documents.go b/backend/internal/repo/repo_documents.go index 9cb4c0f..e91b9a6 100644 --- a/backend/internal/repo/repo_documents.go +++ b/backend/internal/repo/repo_documents.go @@ -4,10 +4,10 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/ent/document" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/document" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/internal/types" ) // DocumentRepository is a repository for Document entity diff --git a/backend/internal/repo/repo_documents_test.go b/backend/internal/repo/repo_documents_test.go index 187ca0f..df5cd7b 100644 --- a/backend/internal/repo/repo_documents_test.go +++ b/backend/internal/repo/repo_documents_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/types" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repo_documents_tokens.go b/backend/internal/repo/repo_documents_tokens.go index 7c260c4..1924f1d 100644 --- a/backend/internal/repo/repo_documents_tokens.go +++ b/backend/internal/repo/repo_documents_tokens.go @@ -5,9 +5,9 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/types" ) // DocumentTokensRepository is a repository for Document entity diff --git a/backend/internal/repo/repo_documents_tokens_test.go b/backend/internal/repo/repo_documents_tokens_test.go index 7106253..ebd84ed 100644 --- a/backend/internal/repo/repo_documents_tokens_test.go +++ b/backend/internal/repo/repo_documents_tokens_test.go @@ -6,9 +6,9 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/ent/documenttoken" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/types" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repo_group.go b/backend/internal/repo/repo_group.go index c5c173e..dfc7e07 100644 --- a/backend/internal/repo/repo_group.go +++ b/backend/internal/repo/repo_group.go @@ -4,7 +4,7 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" + "github.com/hay-kot/homebox/backend/ent" ) type GroupRepository struct { diff --git a/backend/internal/repo/repo_item_attachments.go b/backend/internal/repo/repo_item_attachments.go index f21bb7e..76b06d6 100644 --- a/backend/internal/repo/repo_item_attachments.go +++ b/backend/internal/repo/repo_item_attachments.go @@ -4,8 +4,8 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/attachment" ) // AttachmentRepo is a repository for Attachments table that links Items to Documents @@ -34,9 +34,15 @@ func (r *AttachmentRepo) Get(ctx context.Context, id uuid.UUID) (*ent.Attachment } func (r *AttachmentRepo) Update(ctx context.Context, itemId uuid.UUID, typ attachment.Type) (*ent.Attachment, error) { - return r.db.Attachment.UpdateOneID(itemId). + itm, err := r.db.Attachment.UpdateOneID(itemId). SetType(typ). Save(ctx) + + if err != nil { + return nil, err + } + + return r.Get(ctx, itm.ID) } func (r *AttachmentRepo) Delete(ctx context.Context, id uuid.UUID) error { diff --git a/backend/internal/repo/repo_item_attachments_test.go b/backend/internal/repo/repo_item_attachments_test.go index 0165b8e..e861001 100644 --- a/backend/internal/repo/repo_item_attachments_test.go +++ b/backend/internal/repo/repo_item_attachments_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/attachment" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repo_items.go b/backend/internal/repo/repo_items.go index 8a95a22..ab7cd8e 100644 --- a/backend/internal/repo/repo_items.go +++ b/backend/internal/repo/repo_items.go @@ -4,10 +4,10 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/item" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/item" + "github.com/hay-kot/homebox/backend/internal/types" ) type ItemsRepository struct { diff --git a/backend/internal/repo/repo_items_test.go b/backend/internal/repo/repo_items_test.go index 631f7cb..5917afe 100644 --- a/backend/internal/repo/repo_items_test.go +++ b/backend/internal/repo/repo_items_test.go @@ -6,8 +6,8 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/types" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repo_labels.go b/backend/internal/repo/repo_labels.go index bbdcfb1..1278068 100644 --- a/backend/internal/repo/repo_labels.go +++ b/backend/internal/repo/repo_labels.go @@ -4,10 +4,10 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/ent/group" - "github.com/hay-kot/content/backend/ent/label" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/internal/types" ) type LabelRepository struct { diff --git a/backend/internal/repo/repo_labels_test.go b/backend/internal/repo/repo_labels_test.go index 137376a..4c9753a 100644 --- a/backend/internal/repo/repo_labels_test.go +++ b/backend/internal/repo/repo_labels_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/types" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repo_locations.go b/backend/internal/repo/repo_locations.go index a1ce055..cb224e2 100644 --- a/backend/internal/repo/repo_locations.go +++ b/backend/internal/repo/repo_locations.go @@ -4,9 +4,9 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/ent/location" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/internal/types" ) type LocationRepository struct { diff --git a/backend/internal/repo/repo_locations_test.go b/backend/internal/repo/repo_locations_test.go index 9370305..6c95c5d 100644 --- a/backend/internal/repo/repo_locations_test.go +++ b/backend/internal/repo/repo_locations_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/internal/types" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repo_tokens.go b/backend/internal/repo/repo_tokens.go index 13d5c72..d452b31 100644 --- a/backend/internal/repo/repo_tokens.go +++ b/backend/internal/repo/repo_tokens.go @@ -4,9 +4,9 @@ import ( "context" "time" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/ent/authtokens" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/types" ) type TokenRepository struct { diff --git a/backend/internal/repo/repo_tokens_test.go b/backend/internal/repo/repo_tokens_test.go index 2ab453a..a0bc654 100644 --- a/backend/internal/repo/repo_tokens_test.go +++ b/backend/internal/repo/repo_tokens_test.go @@ -5,8 +5,8 @@ import ( "testing" "time" - "github.com/hay-kot/content/backend/internal/types" - "github.com/hay-kot/content/backend/pkgs/hasher" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/hasher" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repo_users.go b/backend/internal/repo/repo_users.go index f4acaf4..ad6cd1b 100644 --- a/backend/internal/repo/repo_users.go +++ b/backend/internal/repo/repo_users.go @@ -4,9 +4,9 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/ent/user" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/user" + "github.com/hay-kot/homebox/backend/internal/types" ) type UserRepository struct { diff --git a/backend/internal/repo/repo_users_test.go b/backend/internal/repo/repo_users_test.go index f08acb4..27e3ece 100644 --- a/backend/internal/repo/repo_users_test.go +++ b/backend/internal/repo/repo_users_test.go @@ -5,8 +5,8 @@ import ( "fmt" "testing" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/types" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repos_all.go b/backend/internal/repo/repos_all.go index e89fe33..c47f5a4 100644 --- a/backend/internal/repo/repos_all.go +++ b/backend/internal/repo/repos_all.go @@ -1,6 +1,6 @@ package repo -import "github.com/hay-kot/content/backend/ent" +import "github.com/hay-kot/homebox/backend/ent" // AllRepos is a container for all the repository interfaces type AllRepos struct { diff --git a/backend/internal/services/all.go b/backend/internal/services/all.go index bba6e43..e255e28 100644 --- a/backend/internal/services/all.go +++ b/backend/internal/services/all.go @@ -1,6 +1,6 @@ package services -import "github.com/hay-kot/content/backend/internal/repo" +import "github.com/hay-kot/homebox/backend/internal/repo" type AllServices struct { User *UserService @@ -10,7 +10,14 @@ type AllServices struct { Items *ItemService } -func NewServices(repos *repo.AllRepos) *AllServices { +func NewServices(repos *repo.AllRepos, root string) *AllServices { + if repos == nil { + panic("repos cannot be nil") + } + if root == "" { + panic("root cannot be empty") + } + return &AllServices{ User: &UserService{repos}, Admin: &AdminService{repos}, @@ -18,7 +25,8 @@ func NewServices(repos *repo.AllRepos) *AllServices { Labels: &LabelService{repos}, Items: &ItemService{ repo: repos, - filepath: "/tmp/content", + filepath: root, + at: attachmentTokens{}, }, } } diff --git a/backend/internal/services/contexts.go b/backend/internal/services/contexts.go index bc18fcc..94a2168 100644 --- a/backend/internal/services/contexts.go +++ b/backend/internal/services/contexts.go @@ -3,7 +3,8 @@ package services import ( "context" - "github.com/hay-kot/content/backend/internal/types" + "github.com/google/uuid" + "github.com/hay-kot/homebox/backend/internal/types" ) type contextKeys struct { @@ -15,6 +16,31 @@ var ( ContextUserToken = &contextKeys{name: "UserToken"} ) +type Context struct { + context.Context + + // UID is a unique identifier for the acting user. + UID uuid.UUID + + // GID is a unique identifier for the acting users group. + GID uuid.UUID + + // User is the acting user. + User *types.UserOut +} + +// NewContext is a helper function that returns the service context from the context. +// This extracts the users from the context and embeds it into the ServiceContext struct +func NewContext(ctx context.Context) Context { + user := UseUserCtx(ctx) + return Context{ + Context: ctx, + UID: user.ID, + GID: user.GroupID, + User: user, + } +} + // SetUserCtx is a helper function that sets the ContextUser and ContextUserToken // values within the context of a web request (or any context). func SetUserCtx(ctx context.Context, user *types.UserOut, token string) context.Context { diff --git a/backend/internal/services/contexts_test.go b/backend/internal/services/contexts_test.go index cf5a862..bcbf270 100644 --- a/backend/internal/services/contexts_test.go +++ b/backend/internal/services/contexts_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/google/uuid" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/internal/types" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/services/main_test.go b/backend/internal/services/main_test.go index c5f3575..df0369f 100644 --- a/backend/internal/services/main_test.go +++ b/backend/internal/services/main_test.go @@ -8,16 +8,17 @@ import ( "testing" "time" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/repo" - "github.com/hay-kot/content/backend/internal/types" - "github.com/hay-kot/content/backend/pkgs/faker" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/faker" _ "github.com/mattn/go-sqlite3" ) var ( fk = faker.NewFaker() + tCtx = Context{} tClient *ent.Client tRepos *repo.AllRepos tUser *ent.User @@ -63,10 +64,16 @@ func TestMain(m *testing.M) { tClient = client tRepos = repo.EntAllRepos(tClient) - tSvc = NewServices(tRepos) + tSvc = NewServices(tRepos, "/tmp/homebox") defer client.Close() + bootstrap() + tCtx = Context{ + Context: context.Background(), + GID: tGroup.ID, + UID: tUser.ID, + } os.Exit(m.Run()) } diff --git a/backend/internal/services/mappers/items.go b/backend/internal/services/mappers/items.go index 7698c86..6b9df8d 100644 --- a/backend/internal/services/mappers/items.go +++ b/backend/internal/services/mappers/items.go @@ -1,8 +1,8 @@ package mappers import ( - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/types" ) func ToItemAttachment(attachment *ent.Attachment) *types.ItemAttachment { @@ -10,6 +10,7 @@ func ToItemAttachment(attachment *ent.Attachment) *types.ItemAttachment { ID: attachment.ID, CreatedAt: attachment.CreatedAt, UpdatedAt: attachment.UpdatedAt, + Type: attachment.Type.String(), Document: types.DocumentOut{ ID: attachment.Edges.Document.ID, Title: attachment.Edges.Document.Title, diff --git a/backend/internal/services/mappers/labels.go b/backend/internal/services/mappers/labels.go index c5b886b..a593784 100644 --- a/backend/internal/services/mappers/labels.go +++ b/backend/internal/services/mappers/labels.go @@ -1,8 +1,8 @@ package mappers import ( - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/types" ) func ToLabelSummary(label *ent.Label) *types.LabelSummary { diff --git a/backend/internal/services/mappers/locations.go b/backend/internal/services/mappers/locations.go index 77f0eff..6b4bc5f 100644 --- a/backend/internal/services/mappers/locations.go +++ b/backend/internal/services/mappers/locations.go @@ -1,9 +1,9 @@ package mappers import ( - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/repo" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/types" ) func ToLocationCount(location *repo.LocationWithCount) *types.LocationCount { diff --git a/backend/internal/services/mappers/user.go b/backend/internal/services/mappers/user.go index 37c702b..f5736fb 100644 --- a/backend/internal/services/mappers/user.go +++ b/backend/internal/services/mappers/user.go @@ -1,8 +1,8 @@ package mappers import ( - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/types" ) func ToOutUser(user *ent.User, err error) (*types.UserOut, error) { diff --git a/backend/internal/services/service_admin.go b/backend/internal/services/service_admin.go index 8be4f68..dfc643a 100644 --- a/backend/internal/services/service_admin.go +++ b/backend/internal/services/service_admin.go @@ -4,9 +4,9 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent" - "github.com/hay-kot/content/backend/internal/repo" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/types" ) type AdminService struct { diff --git a/backend/internal/services/service_items.go b/backend/internal/services/service_items.go index 147cb5f..fc76838 100644 --- a/backend/internal/services/service_items.go +++ b/backend/internal/services/service_items.go @@ -2,24 +2,28 @@ package services import ( "context" + "errors" "fmt" - "io" - "os" - "path/filepath" "github.com/google/uuid" - "github.com/hay-kot/content/backend/ent/attachment" - "github.com/hay-kot/content/backend/internal/repo" - "github.com/hay-kot/content/backend/internal/services/mappers" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/services/mappers" + "github.com/hay-kot/homebox/backend/internal/types" "github.com/rs/zerolog/log" ) +var ( + ErrNotFound = errors.New("not found") + ErrFileNotFound = errors.New("file not found") +) + type ItemService struct { repo *repo.AllRepos - // filepath is the root of the storage location that will be used to store all files from. filepath string + // at is a map of tokens to attachment IDs. This is used to store the attachment ID + // for issued URLs + at attachmentTokens } func (svc *ItemService) GetOne(ctx context.Context, gid uuid.UUID, id uuid.UUID) (*types.ItemOut, error) { @@ -94,59 +98,6 @@ func (svc *ItemService) Update(ctx context.Context, gid uuid.UUID, data types.It return mappers.ToItemOut(item), nil } -func (svc *ItemService) attachmentPath(gid, itemId uuid.UUID, filename string) string { - return filepath.Join(svc.filepath, gid.String(), itemId.String(), filename) -} - -// AddAttachment adds an attachment to an item by creating an entry in the Documents table and linking it to the Attachment -// Table and Items table. The file provided via the reader is stored on the file system based on the provided -// relative path during construction of the service. -func (svc *ItemService) AddAttachment(ctx context.Context, gid, itemId uuid.UUID, filename string, file io.Reader) (*types.ItemOut, error) { - // Get the Item - item, err := svc.repo.Items.GetOne(ctx, itemId) - if err != nil { - return nil, err - } - - if item.Edges.Group.ID != gid { - return nil, ErrNotOwner - } - - // Create the document - doc, err := svc.repo.Docs.Create(ctx, gid, types.DocumentCreate{ - Title: filename, - Path: svc.attachmentPath(gid, itemId, filename), - }) - if err != nil { - return nil, err - } - - // Create the attachment - _, err = svc.repo.Attachments.Create(ctx, itemId, doc.ID, attachment.TypeAttachment) - if err != nil { - return nil, err - } - - // Read the contents and write them to a file on the file system - err = os.MkdirAll(filepath.Dir(doc.Path), os.ModePerm) - if err != nil { - return nil, err - } - - f, err := os.Create(doc.Path) - if err != nil { - log.Err(err).Msg("failed to create file") - return nil, err - } - - _, err = io.Copy(f, file) - if err != nil { - return nil, err - } - - return svc.GetOne(ctx, gid, itemId) -} - func (svc *ItemService) CsvImport(ctx context.Context, gid uuid.UUID, data [][]string) error { loaded := []csvRow{} diff --git a/backend/internal/services/service_items_attachments.go b/backend/internal/services/service_items_attachments.go new file mode 100644 index 0000000..9969ee9 --- /dev/null +++ b/backend/internal/services/service_items_attachments.go @@ -0,0 +1,199 @@ +package services + +import ( + "context" + "io" + "os" + "path/filepath" + "time" + + "github.com/google/uuid" + "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/hasher" + "github.com/hay-kot/homebox/backend/pkgs/pathlib" + "github.com/rs/zerolog/log" +) + +// TODO: this isn't a scalable solution, tokens should be stored in the database +type attachmentTokens map[string]uuid.UUID + +func (at attachmentTokens) Add(token string, id uuid.UUID) { + at[token] = id + + log.Debug().Str("token", token).Str("uuid", id.String()).Msg("added token") + + go func() { + ch := time.After(1 * time.Minute) + <-ch + at.Delete(token) + log.Debug().Str("token", token).Msg("deleted token") + }() +} + +func (at attachmentTokens) Get(token string) (uuid.UUID, bool) { + id, ok := at[token] + return id, ok +} + +func (at attachmentTokens) Delete(token string) { + delete(at, token) +} + +func (svc *ItemService) AttachmentToken(ctx Context, itemId, attachmentId uuid.UUID) (string, error) { + item, err := svc.repo.Items.GetOne(ctx, itemId) + if err != nil { + return "", err + } + if item.Edges.Group.ID != ctx.GID { + return "", ErrNotOwner + } + + token := hasher.GenerateToken() + + // Ensure that the file exists + attachment, err := svc.repo.Attachments.Get(ctx, attachmentId) + if err != nil { + return "", err + } + + if _, err := os.Stat(attachment.Edges.Document.Path); os.IsNotExist(err) { + _ = svc.AttachmentDelete(ctx, ctx.GID, itemId, attachmentId) + return "", ErrNotFound + } + + svc.at.Add(token.Raw, attachmentId) + + return token.Raw, nil +} + +func (svc *ItemService) attachmentPath(gid, itemId uuid.UUID, filename string) string { + path := filepath.Join(svc.filepath, gid.String(), itemId.String(), filename) + path = pathlib.Safe(path) + log.Debug().Str("path", path).Msg("attachment path") + return path +} + +func (svc *ItemService) AttachmentPath(ctx context.Context, token string) (string, error) { + attachmentId, ok := svc.at.Get(token) + if !ok { + return "", ErrNotFound + } + + attachment, err := svc.repo.Attachments.Get(ctx, attachmentId) + if err != nil { + return "", err + } + + return attachment.Edges.Document.Path, nil +} + +func (svc *ItemService) AttachmentUpdate(ctx Context, itemId uuid.UUID, data *types.ItemAttachmentUpdate) (*types.ItemOut, error) { + // Update Properties + attachment, err := svc.repo.Attachments.Update(ctx, data.ID, attachment.Type(data.Type)) + if err != nil { + return nil, err + } + + attDoc := attachment.Edges.Document + + if data.Title != attachment.Edges.Document.Title { + newPath := pathlib.Safe(svc.attachmentPath(ctx.GID, itemId, data.Title)) + + // Move File + err = os.Rename(attachment.Edges.Document.Path, newPath) + if err != nil { + return nil, err + } + + _, err = svc.repo.Docs.Update(ctx, attDoc.ID, types.DocumentUpdate{ + Title: data.Title, + Path: newPath, + }) + if err != nil { + return nil, err + } + } + + return svc.GetOne(ctx, ctx.GID, itemId) +} + +// AttachmentAdd adds an attachment to an item by creating an entry in the Documents table and linking it to the Attachment +// Table and Items table. The file provided via the reader is stored on the file system based on the provided +// relative path during construction of the service. +func (svc *ItemService) AttachmentAdd(ctx Context, itemId uuid.UUID, filename string, attachmentType attachment.Type, file io.Reader) (*types.ItemOut, error) { + // Get the Item + item, err := svc.repo.Items.GetOne(ctx, itemId) + if err != nil { + return nil, err + } + + if item.Edges.Group.ID != ctx.GID { + return nil, ErrNotOwner + } + + fp := svc.attachmentPath(ctx.GID, itemId, filename) + filename = filepath.Base(fp) + + // Create the document + doc, err := svc.repo.Docs.Create(ctx, ctx.GID, types.DocumentCreate{ + Title: filename, + Path: fp, + }) + if err != nil { + return nil, err + } + + // Create the attachment + _, err = svc.repo.Attachments.Create(ctx, itemId, doc.ID, attachmentType) + if err != nil { + return nil, err + } + + // Read the contents and write them to a file on the file system + err = os.MkdirAll(filepath.Dir(doc.Path), os.ModePerm) + if err != nil { + return nil, err + } + + f, err := os.Create(doc.Path) + if err != nil { + log.Err(err).Msg("failed to create file") + return nil, err + } + + _, err = io.Copy(f, file) + if err != nil { + return nil, err + } + + return svc.GetOne(ctx, ctx.GID, itemId) +} + +func (svc *ItemService) AttachmentDelete(ctx context.Context, gid, itemId, attachmentId uuid.UUID) error { + // Get the Item + item, err := svc.repo.Items.GetOne(ctx, itemId) + if err != nil { + return err + } + + if item.Edges.Group.ID != gid { + return ErrNotOwner + } + + attachment, err := svc.repo.Attachments.Get(ctx, attachmentId) + if err != nil { + return err + } + + // Delete the attachment + err = svc.repo.Attachments.Delete(ctx, attachmentId) + if err != nil { + return err + } + + // Remove File + err = os.Remove(attachment.Edges.Document.Path) + + return err +} diff --git a/backend/internal/services/service_items_attachments_test.go b/backend/internal/services/service_items_attachments_test.go new file mode 100644 index 0000000..71f9b60 --- /dev/null +++ b/backend/internal/services/service_items_attachments_test.go @@ -0,0 +1,62 @@ +package services + +import ( + "context" + "os" + "path" + "strings" + "testing" + + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/stretchr/testify/assert" +) + +func TestItemService_AddAttachment(t *testing.T) { + temp := os.TempDir() + + svc := &ItemService{ + repo: tRepos, + filepath: temp, + } + + loc, err := tSvc.Location.Create(context.Background(), tGroup.ID, types.LocationCreate{ + Description: "test", + Name: "test", + }) + assert.NoError(t, err) + assert.NotNil(t, loc) + + itmC := types.ItemCreate{ + Name: fk.Str(10), + Description: fk.Str(10), + LocationID: loc.ID, + } + + itm, err := svc.Create(context.Background(), tGroup.ID, itmC) + assert.NoError(t, err) + assert.NotNil(t, itm) + t.Cleanup(func() { + err := svc.repo.Items.Delete(context.Background(), itm.ID) + assert.NoError(t, err) + }) + + contents := fk.Str(1000) + reader := strings.NewReader(contents) + + // Setup + afterAttachment, err := svc.AttachmentAdd(tCtx, itm.ID, "testfile.txt", "attachment", reader) + assert.NoError(t, err) + assert.NotNil(t, afterAttachment) + + // Check that the file exists + storedPath := afterAttachment.Attachments[0].Document.Path + + // {root}/{group}/{item}/{attachment} + assert.Equal(t, path.Join(temp, tGroup.ID.String(), itm.ID.String(), "testfile.txt"), storedPath) + + // Check that the file contents are correct + bts, err := os.ReadFile(storedPath) + assert.NoError(t, err) + assert.Equal(t, contents, string(bts)) + +} diff --git a/backend/internal/services/service_items_csv.go b/backend/internal/services/service_items_csv.go index ed8e5a4..e1d1a96 100644 --- a/backend/internal/services/service_items_csv.go +++ b/backend/internal/services/service_items_csv.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/internal/types" ) var ErrInvalidCsv = errors.New("invalid csv") diff --git a/backend/internal/services/service_items_test.go b/backend/internal/services/service_items_test.go index b71a74e..5a21508 100644 --- a/backend/internal/services/service_items_test.go +++ b/backend/internal/services/service_items_test.go @@ -2,13 +2,9 @@ package services import ( "context" - "os" - "path" - "strings" "testing" "github.com/google/uuid" - "github.com/hay-kot/content/backend/internal/types" "github.com/stretchr/testify/assert" ) @@ -92,53 +88,3 @@ func TestItemService_CsvImport(t *testing.T) { } } } - -func TestItemService_AddAttachment(t *testing.T) { - temp := os.TempDir() - - svc := &ItemService{ - repo: tRepos, - filepath: temp, - } - - loc, err := tSvc.Location.Create(context.Background(), tGroup.ID, types.LocationCreate{ - Description: "test", - Name: "test", - }) - assert.NoError(t, err) - assert.NotNil(t, loc) - - itmC := types.ItemCreate{ - Name: fk.Str(10), - Description: fk.Str(10), - LocationID: loc.ID, - } - - itm, err := svc.Create(context.Background(), tGroup.ID, itmC) - assert.NoError(t, err) - assert.NotNil(t, itm) - t.Cleanup(func() { - err := svc.repo.Items.Delete(context.Background(), itm.ID) - assert.NoError(t, err) - }) - - contents := fk.Str(1000) - reader := strings.NewReader(contents) - - // Setup - afterAttachment, err := svc.AddAttachment(context.Background(), tGroup.ID, itm.ID, "testfile.txt", reader) - assert.NoError(t, err) - assert.NotNil(t, afterAttachment) - - // Check that the file exists - storedPath := afterAttachment.Attachments[0].Document.Path - - // {root}/{group}/{item}/{attachment} - assert.Equal(t, path.Join(temp, tGroup.ID.String(), itm.ID.String(), "testfile.txt"), storedPath) - - // Check that the file contents are correct - bts, err := os.ReadFile(storedPath) - assert.NoError(t, err) - assert.Equal(t, contents, string(bts)) - -} diff --git a/backend/internal/services/service_labels.go b/backend/internal/services/service_labels.go index 70bfa30..5a284e7 100644 --- a/backend/internal/services/service_labels.go +++ b/backend/internal/services/service_labels.go @@ -4,9 +4,9 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/content/backend/internal/repo" - "github.com/hay-kot/content/backend/internal/services/mappers" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/services/mappers" + "github.com/hay-kot/homebox/backend/internal/types" ) type LabelService struct { diff --git a/backend/internal/services/service_locations.go b/backend/internal/services/service_locations.go index 30db743..2349f6b 100644 --- a/backend/internal/services/service_locations.go +++ b/backend/internal/services/service_locations.go @@ -5,9 +5,9 @@ import ( "errors" "github.com/google/uuid" - "github.com/hay-kot/content/backend/internal/repo" - "github.com/hay-kot/content/backend/internal/services/mappers" - "github.com/hay-kot/content/backend/internal/types" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/services/mappers" + "github.com/hay-kot/homebox/backend/internal/types" ) var ( diff --git a/backend/internal/services/service_user.go b/backend/internal/services/service_user.go index b5ced21..8d1abcf 100644 --- a/backend/internal/services/service_user.go +++ b/backend/internal/services/service_user.go @@ -6,10 +6,10 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/content/backend/internal/repo" - "github.com/hay-kot/content/backend/internal/services/mappers" - "github.com/hay-kot/content/backend/internal/types" - "github.com/hay-kot/content/backend/pkgs/hasher" + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/services/mappers" + "github.com/hay-kot/homebox/backend/internal/types" + "github.com/hay-kot/homebox/backend/pkgs/hasher" ) var ( diff --git a/backend/internal/services/service_user_defaults.go b/backend/internal/services/service_user_defaults.go index 185c782..2b5cbbe 100644 --- a/backend/internal/services/service_user_defaults.go +++ b/backend/internal/services/service_user_defaults.go @@ -1,6 +1,6 @@ package services -import "github.com/hay-kot/content/backend/internal/types" +import "github.com/hay-kot/homebox/backend/internal/types" func defaultLocations() []types.LocationCreate { return []types.LocationCreate{ diff --git a/backend/internal/types/item_types.go b/backend/internal/types/item_types.go index ae682ae..d86696f 100644 --- a/backend/internal/types/item_types.go +++ b/backend/internal/types/item_types.go @@ -103,5 +103,16 @@ type ItemAttachment struct { ID uuid.UUID `json:"id"` CreatedAt time.Time `json:"createdAt"` UpdatedAt time.Time `json:"updatedAt"` + Type string `json:"type"` Document DocumentOut `json:"document"` } + +type ItemAttachmentToken struct { + Token string `json:"token"` +} + +type ItemAttachmentUpdate struct { + ID uuid.UUID `json:"-"` + Type string `json:"type"` + Title string `json:"title"` +} diff --git a/backend/internal/types/label_types.go b/backend/internal/types/label_types.go index 301a3fd..725361c 100644 --- a/backend/internal/types/label_types.go +++ b/backend/internal/types/label_types.go @@ -21,7 +21,6 @@ type LabelUpdate struct { type LabelSummary struct { ID uuid.UUID `json:"id"` - GroupID uuid.UUID `json:"groupId"` Name string `json:"name"` Description string `json:"description"` CreatedAt time.Time `json:"createdAt"` diff --git a/backend/pkgs/pathlib/pathlib.go b/backend/pkgs/pathlib/pathlib.go new file mode 100644 index 0000000..24420aa --- /dev/null +++ b/backend/pkgs/pathlib/pathlib.go @@ -0,0 +1,64 @@ +package pathlib + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +type dirReaderFunc func(name string) []string + +var dirReader dirReaderFunc = func(directory string) []string { + f, err := os.Open(directory) + if err != nil { + return nil + } + defer f.Close() + + names, err := f.Readdirnames(-1) + if err != nil { + return nil + } + return names +} + +func hasConflict(path string, neighbors []string) bool { + filename := strings.ToLower(filepath.Base(path)) + + for _, n := range neighbors { + if strings.ToLower(n) == filename { + return true + } + } + return false +} + +// Safe will take a destination path and return a validated path that is safe to use. +// without overwriting any existing files. If a conflict exists, it will append a number +// to the end of the file name. If the parent directory does not exist this function will +// return the original path. +func Safe(path string) string { + parent := filepath.Dir(path) + + neighbors := dirReader(parent) + if neighbors == nil { + return path + } + + if hasConflict(path, neighbors) { + ext := filepath.Ext(path) + + name := strings.TrimSuffix(filepath.Base(path), ext) + + for i := 1; i < 1000; i++ { + newName := fmt.Sprintf("%s (%d)%s", name, i, ext) + newPath := filepath.Join(parent, newName) + if !hasConflict(newPath, neighbors) { + return newPath + } + } + } + + return path +} diff --git a/backend/pkgs/pathlib/pathlib_test.go b/backend/pkgs/pathlib/pathlib_test.go new file mode 100644 index 0000000..193c4ab --- /dev/null +++ b/backend/pkgs/pathlib/pathlib_test.go @@ -0,0 +1,94 @@ +package pathlib + +import ( + "testing" +) + +func Test_hasConflict(t *testing.T) { + type args struct { + path string + neighbors []string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "no conflict", + args: args{ + path: "foo", + neighbors: []string{"bar", "baz"}, + }, + want: false, + }, + { + name: "conflict", + args: args{ + path: "foo", + neighbors: []string{"bar", "foo"}, + }, + want: true, + }, + { + name: "conflict with different case", + args: args{ + path: "foo", + neighbors: []string{"bar", "Foo"}, + }, + want: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := hasConflict(tt.args.path, tt.args.neighbors); got != tt.want { + t.Errorf("hasConflict() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestSafePath(t *testing.T) { + // override dirReader + dirReader = func(name string) []string { + return []string{"bar.pdf", "bar (1).pdf", "bar (2).pdf"} + } + + type args struct { + path string + } + tests := []struct { + name string + args args + want string + }{ + { + name: "no conflict", + args: args{ + path: "/foo/foo.pdf", + }, + want: "/foo/foo.pdf", + }, + { + name: "conflict", + args: args{ + path: "/foo/bar.pdf", + }, + want: "/foo/bar (3).pdf", + }, + { + name: "conflict with different case", + args: args{ + path: "/foo/BAR.pdf", + }, + want: "/foo/BAR (3).pdf", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Safe(tt.args.path); got != tt.want { + t.Errorf("SafePath() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/backend/pkgs/server/response_error_builder.go b/backend/pkgs/server/response_error_builder.go index ac8d34d..4c6d80f 100644 --- a/backend/pkgs/server/response_error_builder.go +++ b/backend/pkgs/server/response_error_builder.go @@ -4,22 +4,47 @@ import ( "net/http" ) +type ValidationError struct { + Field string `json:"field"` + Reason string `json:"reason"` +} + +type ValidationErrors []ValidationError + +func (ve *ValidationErrors) HasErrors() bool { + if (ve == nil) || (len(*ve) == 0) { + return false + } + + for _, err := range *ve { + if err.Field != "" { + return true + } + } + return false +} + +func (ve ValidationErrors) Append(field, reasons string) ValidationErrors { + return append(ve, ValidationError{ + Field: field, + Reason: reasons, + }) +} + // ErrorBuilder is a helper type to build a response that contains an array of errors. // Typical use cases are for returning an array of validation errors back to the user. // // Example: // -// -// { -// "errors": [ -// "invalid id", -// "invalid name", -// "invalid description" -// ], -// "message": "Unprocessable Entity", -// "status": 422 -// } -// +// { +// "errors": [ +// "invalid id", +// "invalid name", +// "invalid description" +// ], +// "message": "Unprocessable Entity", +// "status": 422 +// } type ErrorBuilder struct { errs []string } diff --git a/backend/pkgs/server/response_error_builder_test.go b/backend/pkgs/server/response_error_builder_test.go index 40de141..689faaa 100644 --- a/backend/pkgs/server/response_error_builder_test.go +++ b/backend/pkgs/server/response_error_builder_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/hay-kot/content/backend/pkgs/faker" + "github.com/hay-kot/homebox/backend/pkgs/faker" "github.com/stretchr/testify/assert" ) diff --git a/docs/docs/quick-start.md b/docs/docs/quick-start.md index fce544d..4a488df 100644 --- a/docs/docs/quick-start.md +++ b/docs/docs/quick-start.md @@ -23,6 +23,7 @@ version: "3.4" environment: - HBOX_LOG_LEVEL=info - HBOX_LOG_FORMAT=text + - HBOX_WEB_MAX_UPLOAD_SIZE=10 volumes: - homebox-data:/data/ ports: @@ -35,22 +36,23 @@ volumes: ## Env Variables & Configuration -| Variable | Default | Description | -| ------------------------ | ---------------- | ---------------------------------------------------------------------------------- | -| HBOX_MODE | production | application mode used for runtime behavior can be one of: development, production | -| HBOX_WEB_PORT | 7745 | port to run the web server on, in you're using docker do not change this | -| HBOX_WEB_HOST | | host to run the web server on, in you're using docker do not change this | -| HBOX_DATABASE_DRIVER | sqlite | database driver to use, currently only sqlite is supported | -| HBOX_DATABASE_SQLITE_URL | /data/homebox.db | sqlite database url, in you're using docker do not change this | -| HBOX_LOG_LEVEL | info | log level to use, can be one of: trace, debug, info, warn, error, critical | -| HBOX_LOG_FORMAT | text | log format to use, can be one of: text, json | -| HBOX_MAILER_HOST | | email host to use, if not set no email provider will be used | -| HBOX_MAILER_PORT | 587 | email port to use | -| HBOX_MAILER_USERNAME | | email user to use | -| HBOX_MAILER_PASSWORD | | email password to use | -| HBOX_MAILER_FROM | | email from address to use | -| HBOX_SWAGGER_HOST | 7745 | swagger host to use, if not set swagger will be disabled | -| HBOX_SWAGGER_SCHEMA | http | swagger schema to use, can be one of: http, https | +| Variable | Default | Description | +| ------------------------ | ---------------------- | ---------------------------------------------------------------------------------- | +| HBOX_MODE | production | application mode used for runtime behavior can be one of: development, production | +| HBOX_WEB_PORT | 7745 | port to run the web server on, in you're using docker do not change this | +| HBOX_WEB_HOST | | host to run the web server on, in you're using docker do not change this | +| HBOX_STORAGE_DATA | /data/ | path to the data directory, do not change this if you're using docker | +| HBOX_STORAGE_SQLITE_URL | /data/homebox.db?_fk=1 | sqlite database url, in you're using docker do not change this | +| HBOX_WEB_MAX_UPLOAD_SIZE | 10 | maximum file upload size supported in MB | +| HBOX_LOG_LEVEL | info | log level to use, can be one of: trace, debug, info, warn, error, critical | +| HBOX_LOG_FORMAT | text | log format to use, can be one of: text, json | +| HBOX_MAILER_HOST | | email host to use, if not set no email provider will be used | +| HBOX_MAILER_PORT | 587 | email port to use | +| HBOX_MAILER_USERNAME | | email user to use | +| HBOX_MAILER_PASSWORD | | email password to use | +| HBOX_MAILER_FROM | | email from address to use | +| HBOX_SWAGGER_HOST | 7745 | swagger host to use, if not set swagger will be disabled | +| HBOX_SWAGGER_SCHEMA | http | swagger schema to use, can be one of: http, https | !!! tip "CLI Arguments" If you're deploying without docker you can use command line arguments to configure the application. Run `homebox --help` for more information. @@ -62,10 +64,11 @@ volumes: --mode/$HBOX_MODE (default: development) --web-port/$HBOX_WEB_PORT (default: 7745) --web-host/$HBOX_WEB_HOST - --database-driver/$HBOX_DATABASE_DRIVER (default: sqlite3) - --database-sqlite-url/$HBOX_DATABASE_SQLITE_URL (default: file:ent?mode=memory&cache=shared&_fk=1) - --log-level/$HBOX_LOG_LEVEL (default: debug) - --log-file/$HBOX_LOG_FILE + --web-max-upload-size/$HBOX_WEB_MAX_UPLOAD_SIZE (default: 10) + --storage-data/$HBOX_STORAGE_DATA (default: ./homebox-data) + --storage-sqlite-url/$HBOX_STORAGE_SQLITE_URL (default: ./homebox-data/homebox.db?_fk=1) + --log-level/$HBOX_LOG_LEVEL (default: info) + --log-format/$HBOX_LOG_FORMAT (default: text) --mailer-host/$HBOX_MAILER_HOST --mailer-port/$HBOX_MAILER_PORT --mailer-username/$HBOX_MAILER_USERNAME diff --git a/frontend/components/Form/Select.vue b/frontend/components/Form/Select.vue index bfdc9ff..27e3683 100644 --- a/frontend/components/Form/Select.vue +++ b/frontend/components/Form/Select.vue @@ -25,7 +25,7 @@ }, modelValue: { // eslint-disable-next-line @typescript-eslint/no-explicit-any - type: Object as any, + type: [Object, String, Boolean] as any, default: null, }, items: { @@ -37,18 +37,47 @@ type: String, default: "name", }, + value: { + type: String, + default: null, + required: false, + }, selectFirst: { type: Boolean, default: false, }, }); - watchOnce( - () => props.items, - () => { - if (props.selectFirst && props.items.length > 0) { + function syncSelect() { + if (!props.modelValue) { + if (props.selectFirst) { selectedIdx.value = 0; } + return; + } + // Check if we're already synced + if (props.value) { + if (props.modelValue[props.value] === props.items[selectedIdx.value][props.value]) { + return; + } + } else if (props.modelValue === props.items[selectedIdx.value]) { + return; + } + + const idx = props.items.findIndex(item => { + if (props.value) { + return item[props.value] === props.modelValue; + } + return item === props.modelValue; + }); + + selectedIdx.value = idx; + } + + watch( + () => props.modelValue, + () => { + syncSelect(); } ); @@ -56,6 +85,10 @@ watch( () => selectedIdx.value, () => { + if (props.value) { + emit("update:modelValue", props.items[selectedIdx.value][props.value]); + return; + } emit("update:modelValue", props.items[selectedIdx.value]); } ); diff --git a/frontend/components/Item/AttachmentsList.vue b/frontend/components/Item/AttachmentsList.vue new file mode 100644 index 0000000..f215256 --- /dev/null +++ b/frontend/components/Item/AttachmentsList.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/frontend/components/Item/Card.vue b/frontend/components/Item/Card.vue index d5a8fed..6be75a9 100644 --- a/frontend/components/Item/Card.vue +++ b/frontend/components/Item/Card.vue @@ -23,6 +23,7 @@ + + diff --git a/frontend/composables/use-strings.ts b/frontend/composables/use-strings.ts deleted file mode 100644 index e0658d3..0000000 --- a/frontend/composables/use-strings.ts +++ /dev/null @@ -1,7 +0,0 @@ -export function truncate(str: string, length: number) { - return str.length > length ? str.substring(0, length) + "..." : str; -} - -export function capitalize(str: string) { - return str.charAt(0).toUpperCase() + str.slice(1); -} diff --git a/frontend/lib/api/__test__/user/items.test.ts b/frontend/lib/api/__test__/user/items.test.ts new file mode 100644 index 0000000..75ca5cf --- /dev/null +++ b/frontend/lib/api/__test__/user/items.test.ts @@ -0,0 +1,61 @@ +import { describe, test, expect } from "vitest"; +import { LocationOut } from "../../types/data-contracts"; +import { AttachmentTypes } from "../../types/non-generated"; +import { UserApi } from "../../user"; +import { sharedUserClient } from "../test-utils"; + +describe("user should be able to create an item and add an attachment", () => { + let increment = 0; + /** + * useLocatio sets up a location resource for testing, and returns a function + * that can be used to delete the location from the backend server. + */ + async function useLocation(api: UserApi): Promise<[LocationOut, () => Promise]> { + const { response, data } = await api.locations.create({ + name: `__test__.location.name_${increment}`, + description: `__test__.location.description_${increment}`, + }); + expect(response.status).toBe(201); + increment++; + + const cleanup = async () => { + const { response } = await api.locations.delete(data.id); + expect(response.status).toBe(204); + }; + + return [data, cleanup]; + } + + test("user should be able to create an item and add an attachment", async () => { + const api = await sharedUserClient(); + const [location, cleanup] = await useLocation(api); + + const { response, data: item } = await api.items.create({ + name: "test-item", + labelIds: [], + description: "test-description", + locationId: location.id, + }); + expect(response.status).toBe(201); + + // Add attachment + { + const testFile = new Blob(["test"], { type: "text/plain" }); + const { response } = await api.items.addAttachment(item.id, testFile, "test.txt", AttachmentTypes.Attachment); + expect(response.status).toBe(201); + } + + // Get Attachment + const { response: itmResp, data } = await api.items.get(item.id); + expect(itmResp.status).toBe(200); + + expect(data.attachments).toHaveLength(1); + expect(data.attachments[0].document.title).toBe("test.txt"); + + const resp = await api.items.deleteAttachment(data.id, data.attachments[0].id); + expect(resp.response.status).toBe(204); + + api.items.delete(item.id); + await cleanup(); + }); +}); diff --git a/frontend/lib/api/classes/items.ts b/frontend/lib/api/classes/items.ts index bfcfde3..e98c785 100644 --- a/frontend/lib/api/classes/items.ts +++ b/frontend/lib/api/classes/items.ts @@ -1,15 +1,23 @@ import { BaseAPI, route } from "../base"; import { parseDate } from "../base/base-api"; -import { ItemCreate, ItemOut, ItemSummary, ItemUpdate } from "../types/data-contracts"; +import { + ItemAttachmentToken, + ItemAttachmentUpdate, + ItemCreate, + ItemOut, + ItemSummary, + ItemUpdate, +} from "../types/data-contracts"; +import { AttachmentTypes } from "../types/non-generated"; import { Results } from "./types"; export class ItemsApi extends BaseAPI { getAll() { - return this.http.get>({ url: route("/items") }); + return this.http.get>({ url: route("/items") }); } create(item: ItemCreate) { - return this.http.post({ url: route("/items"), body: item }); + return this.http.post({ url: route("/items"), body: item }); } async get(id: string) { @@ -45,6 +53,44 @@ export class ItemsApi extends BaseAPI { const formData = new FormData(); formData.append("csv", file); - return this.http.post({ url: route("/items/import"), data: formData }); + return this.http.post({ + url: route("/items/import"), + data: formData, + }); + } + + addAttachment(id: string, file: File | Blob, filename: string, type: AttachmentTypes) { + const formData = new FormData(); + formData.append("file", file); + formData.append("type", type); + formData.append("name", filename); + + return this.http.post({ + url: route(`/items/${id}/attachments`), + data: formData, + }); + } + + async getAttachmentUrl(id: string, attachmentId: string): Promise { + const payload = await this.http.get({ + url: route(`/items/${id}/attachments/${attachmentId}`), + }); + + if (!payload.data) { + return ""; + } + + return route(`/items/${id}/attachments/download`, { token: payload.data.token }); + } + + async deleteAttachment(id: string, attachmentId: string) { + return await this.http.delete({ url: route(`/items/${id}/attachments/${attachmentId}`) }); + } + + async updateAttachment(id: string, attachmentId: string, data: ItemAttachmentUpdate) { + return await this.http.put({ + url: route(`/items/${id}/attachments/${attachmentId}`), + body: data, + }); } } diff --git a/frontend/lib/api/types/data-contracts.ts b/frontend/lib/api/types/data-contracts.ts index 4d0d9aa..80a6367 100644 --- a/frontend/lib/api/types/data-contracts.ts +++ b/frontend/lib/api/types/data-contracts.ts @@ -21,6 +21,11 @@ export interface ServerResults { items: any; } +export interface ServerValidationError { + field: string; + reason: string; +} + export interface ApiSummary { build: Build; health: boolean; @@ -45,9 +50,19 @@ export interface ItemAttachment { createdAt: Date; document: DocumentOut; id: string; + type: string; updatedAt: Date; } +export interface ItemAttachmentToken { + token: string; +} + +export interface ItemAttachmentUpdate { + title: string; + type: string; +} + export interface ItemCreate { description: string; labelIds: string[]; @@ -191,7 +206,6 @@ export interface LabelCreate { export interface LabelOut { createdAt: Date; description: string; - groupId: string; id: string; items: ItemSummary[]; name: string; @@ -201,7 +215,6 @@ export interface LabelOut { export interface LabelSummary { createdAt: Date; description: string; - groupId: string; id: string; name: string; updatedAt: Date; diff --git a/frontend/lib/api/types/non-generated.ts b/frontend/lib/api/types/non-generated.ts new file mode 100644 index 0000000..6928784 --- /dev/null +++ b/frontend/lib/api/types/non-generated.ts @@ -0,0 +1,6 @@ +export enum AttachmentTypes { + Photo = "photo", + Manual = "manual", + Warranty = "warranty", + Attachment = "attachment", +} diff --git a/frontend/lib/requests/requests.ts b/frontend/lib/requests/requests.ts index 55e89a7..9d62c36 100644 --- a/frontend/lib/requests/requests.ts +++ b/frontend/lib/requests/requests.ts @@ -97,11 +97,15 @@ export class Requests { return {} as T; } - try { - return await response.json(); - } catch (e) { - return {} as T; + if (response.headers.get("Content-Type")?.startsWith("application/json")) { + try { + return await response.json(); + } catch (e) { + return {} as T; + } } + + return response.body as unknown as T; })(); return { diff --git a/frontend/lib/strings/index.test.ts b/frontend/lib/strings/index.test.ts new file mode 100644 index 0000000..1f266ea --- /dev/null +++ b/frontend/lib/strings/index.test.ts @@ -0,0 +1,56 @@ +import { describe, it, expect } from "vitest"; +import { titlecase, capitalize, truncate } from "."; + +describe("title case tests", () => { + it("should return the same string if it's already title case", () => { + expect(titlecase("Hello World")).toBe("Hello World"); + }); + + it("should title case a lower case word", () => { + expect(titlecase("hello")).toBe("Hello"); + }); + + it("should title case a sentence", () => { + expect(titlecase("hello world")).toBe("Hello World"); + }); + + it("should title case a sentence with multiple words", () => { + expect(titlecase("hello world this is a test")).toBe("Hello World This Is A Test"); + }); +}); + +describe("capitilize tests", () => { + it("should return the same string if it's already capitalized", () => { + expect(capitalize("Hello")).toBe("Hello"); + }); + + it("should capitalize a lower case word", () => { + expect(capitalize("hello")).toBe("Hello"); + }); + + it("should capitalize a sentence", () => { + expect(capitalize("hello world")).toBe("Hello world"); + }); + + it("should capitalize a sentence with multiple words", () => { + expect(capitalize("hello world this is a test")).toBe("Hello world this is a test"); + }); +}); + +describe("truncase tests", () => { + it("should return the same string if it's already truncated", () => { + expect(truncate("Hello", 5)).toBe("Hello"); + }); + + it("should truncate a lower case word", () => { + expect(truncate("hello", 3)).toBe("hel..."); + }); + + it("should truncate a sentence", () => { + expect(truncate("hello world", 5)).toBe("hello..."); + }); + + it("should truncate a sentence with multiple words", () => { + expect(truncate("hello world this is a test", 10)).toBe("hello worl..."); + }); +}); diff --git a/frontend/lib/strings/index.ts b/frontend/lib/strings/index.ts new file mode 100644 index 0000000..9f23e90 --- /dev/null +++ b/frontend/lib/strings/index.ts @@ -0,0 +1,14 @@ +export function titlecase(str: string) { + return str + .split(" ") + .map(word => word[0].toUpperCase() + word.slice(1)) + .join(" "); +} + +export function capitalize(str: string) { + return str[0].toUpperCase() + str.slice(1); +} + +export function truncate(str: string, length: number) { + return str.length > length ? str.substring(0, length) + "..." : str; +} diff --git a/frontend/pages/home.vue b/frontend/pages/home.vue index ae6d8c1..f39eb6b 100644 --- a/frontend/pages/home.vue +++ b/frontend/pages/home.vue @@ -121,7 +121,7 @@

Welcome back,

-

Hayden Kotelman

+

Username

User

diff --git a/frontend/pages/item/[id]/edit.vue b/frontend/pages/item/[id]/edit.vue index afc5d88..59ab0a4 100644 --- a/frontend/pages/item/[id]/edit.vue +++ b/frontend/pages/item/[id]/edit.vue @@ -1,7 +1,9 @@