From 72324b84398e04e15b17f87275ac6b7f18240ae5 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sat, 1 Oct 2022 12:13:53 -0800 Subject: [PATCH 001/435] add user profiles and theme selectors --- frontend/app.vue | 6 +- frontend/components/App/Logo.vue | 3 +- frontend/components/Base/Details.vue | 44 --- frontend/components/Base/SectionHeader.vue | 2 +- frontend/components/Form/DatePicker.vue | 2 +- .../global/DetailsSection/DetailsSection.vue | 4 +- frontend/composables/use-preferences.ts | 33 ++ frontend/composables/use-theme.ts | 42 +++ frontend/pages/home.vue | 8 +- frontend/pages/item/[id]/edit.vue | 8 +- frontend/pages/item/[id]/index.vue | 302 +++++++++++------- frontend/pages/label/[id].vue | 4 +- frontend/pages/location/[id].vue | 4 +- frontend/pages/profile.vue | 190 +++++++++++ 14 files changed, 466 insertions(+), 186 deletions(-) delete mode 100644 frontend/components/Base/Details.vue create mode 100644 frontend/composables/use-theme.ts create mode 100644 frontend/pages/profile.vue diff --git a/frontend/app.vue b/frontend/app.vue index b659bb0..ca390af 100644 --- a/frontend/app.vue +++ b/frontend/app.vue @@ -1,6 +1,10 @@ + + diff --git a/frontend/components/App/Logo.vue b/frontend/components/App/Logo.vue index 72c0c4f..da16ab6 100644 --- a/frontend/components/App/Logo.vue +++ b/frontend/components/App/Logo.vue @@ -29,8 +29,9 @@ /> -
-
-

- -

-

- -

-
-
-
-
-
- {{ dKey }} -
-
- - {{ dValue }} - -
-
-
-
-
- - - - - diff --git a/frontend/components/Base/SectionHeader.vue b/frontend/components/Base/SectionHeader.vue index 13442bd..43fa8b2 100644 --- a/frontend/components/Base/SectionHeader.vue +++ b/frontend/components/Base/SectionHeader.vue @@ -9,7 +9,7 @@ > -

+

diff --git a/frontend/components/Form/DatePicker.vue b/frontend/components/Form/DatePicker.vue index 113ffe9..b8731fa 100644 --- a/frontend/components/Form/DatePicker.vue +++ b/frontend/components/Form/DatePicker.vue @@ -1,5 +1,5 @@
- +
From ba8367f637e5c382a740956d9736dc8bd1a49a72 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Fri, 14 Oct 2022 13:40:27 -0800 Subject: [PATCH 053/435] fix: compose example (#70) --- docs/docs/quick-start.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/docs/quick-start.md b/docs/docs/quick-start.md index bad7bc4..21fdba9 100644 --- a/docs/docs/quick-start.md +++ b/docs/docs/quick-start.md @@ -15,19 +15,20 @@ docker run --name=homebox \ ```yml version: "3.4" - services: - homebox: - image: ghcr.io/hay-kot/homebox:latest - container_name: homebox - restart: always - environment: - - HBOX_LOG_LEVEL=info - - HBOX_LOG_FORMAT=text - - HBOX_WEB_MAX_UPLOAD_SIZE=10 - volumes: - - homebox-data:/data/ - ports: - - 3100:7745 + +services: + homebox: + image: ghcr.io/hay-kot/homebox:latest + container_name: homebox + restart: always + environment: + - HBOX_LOG_LEVEL=info + - HBOX_LOG_FORMAT=text + - HBOX_WEB_MAX_UPLOAD_SIZE=10 + volumes: + - homebox-data:/data/ + ports: + - 3100:7745 volumes: homebox-data: From dea2dcfde81f9000d81c8004ecf3470f45dab00f Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Fri, 14 Oct 2022 14:02:16 -0800 Subject: [PATCH 054/435] feat: allow disable registration (#71) --- backend/app/api/routes.go | 1 + backend/app/api/v1/controller.go | 16 ++++++++++++---- backend/app/api/v1/v1_ctrl_user.go | 5 +++++ backend/internal/config/conf.go | 15 ++++++++------- docs/docs/quick-start.md | 5 ++++- frontend/lib/api/types/data-contracts.ts | 6 ++++++ 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index ab14c76..9cfd289 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -44,6 +44,7 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux { v1Base := v1.BaseUrlFunc(prefix) v1Ctrl := v1.NewControllerV1(a.services, v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize), + v1.WithRegistration(a.conf.AllowRegistration), v1.WithDemoStatus(a.conf.Demo), // Disable Password Change in Demo Mode ) r.Get(v1Base("/status"), v1Ctrl.HandleBase(func() bool { return true }, v1.Build{ diff --git a/backend/app/api/v1/controller.go b/backend/app/api/v1/controller.go index 365feef..349daf5 100644 --- a/backend/app/api/v1/controller.go +++ b/backend/app/api/v1/controller.go @@ -19,10 +19,17 @@ func WithDemoStatus(demoStatus bool) func(*V1Controller) { } } +func WithRegistration(allowRegistration bool) func(*V1Controller) { + return func(ctrl *V1Controller) { + ctrl.allowRegistration = allowRegistration + } +} + type V1Controller struct { - svc *services.AllServices - maxUploadSize int64 - isDemo bool + svc *services.AllServices + maxUploadSize int64 + isDemo bool + allowRegistration bool } type ( @@ -53,7 +60,8 @@ func BaseUrlFunc(prefix string) func(s string) string { func NewControllerV1(svc *services.AllServices, options ...func(*V1Controller)) *V1Controller { ctrl := &V1Controller{ - svc: svc, + svc: svc, + allowRegistration: true, } for _, opt := range options { diff --git a/backend/app/api/v1/v1_ctrl_user.go b/backend/app/api/v1/v1_ctrl_user.go index dc2779a..9ea4fae 100644 --- a/backend/app/api/v1/v1_ctrl_user.go +++ b/backend/app/api/v1/v1_ctrl_user.go @@ -27,6 +27,11 @@ func (ctrl *V1Controller) HandleUserRegistration() http.HandlerFunc { return } + if !ctrl.allowRegistration && regData.GroupToken == "" { + server.RespondError(w, http.StatusForbidden, nil) + return + } + _, err := ctrl.svc.User.RegisterUser(r.Context(), regData) if err != nil { log.Err(err).Msg("failed to register user") diff --git a/backend/internal/config/conf.go b/backend/internal/config/conf.go index a648bcc..f45e19c 100644 --- a/backend/internal/config/conf.go +++ b/backend/internal/config/conf.go @@ -16,13 +16,14 @@ const ( ) type Config struct { - 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"` - Demo bool `yaml:"demo"` + 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"` + Demo bool `yaml:"demo"` + AllowRegistration bool `yaml:"disable_registration" conf:"default:true"` } type SwaggerConf struct { diff --git a/docs/docs/quick-start.md b/docs/docs/quick-start.md index 21fdba9..d3e97a2 100644 --- a/docs/docs/quick-start.md +++ b/docs/docs/quick-start.md @@ -42,9 +42,10 @@ volumes: | 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_ALLOW_REGISTRATION | true | allow users to register themselves | +| HBOX_WEB_MAX_UPLOAD_SIZE | 10 | maximum file upload size supported in MB | | 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 | @@ -77,6 +78,8 @@ volumes: --mailer-from/$HBOX_MAILER_FROM --swagger-host/$HBOX_SWAGGER_HOST (default: localhost:7745) --swagger-scheme/$HBOX_SWAGGER_SCHEME (default: http) + --demo/$HBOX_DEMO + --allow-registration/$HBOX_ALLOW_REGISTRATION (default: true) --help/-h display this help message ``` \ No newline at end of file diff --git a/frontend/lib/api/types/data-contracts.ts b/frontend/lib/api/types/data-contracts.ts index e160c5d..585feb1 100644 --- a/frontend/lib/api/types/data-contracts.ts +++ b/frontend/lib/api/types/data-contracts.ts @@ -187,6 +187,12 @@ export interface LocationSummary { updatedAt: Date; } +export interface PaginationResultRepoItemSummary { + items: ItemSummary[]; + page: number; + pageSize: number; + total: number; +} export interface UserOut { email: string; From 5adb8fbad7e7e2f10f51406731fa2476b6b1dd2d Mon Sep 17 00:00:00 2001 From: Motordom <4337361+Motordom@users.noreply.github.com> Date: Sat, 15 Oct 2022 16:02:34 +1100 Subject: [PATCH 055/435] chore: update issue templates (#78) Update capitalisation on descriptions, and added corresponding labels. --- .github/ISSUE_TEMPLATE/bug_report.yml | 3 ++- .github/ISSUE_TEMPLATE/feature_request.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index c1ee637..309cf28 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,7 @@ --- name: "Bug Report" -description: "submit a bug report for the current release" +description: "Submit a bug report for the current release" +labels: ["bug"] body: - type: checkboxes id: checks diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 8a15b34..550daf4 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,7 @@ --- name: "Feature Request" -description: "submit a feature request for the current release" +description: "Submit a feature request for the current release" +labels: ["feature-request"] body: - type: textarea id: problem-statement From 50bd2ab86e98649432e73f5e7738bcc031c46847 Mon Sep 17 00:00:00 2001 From: Motordom <4337361+Motordom@users.noreply.github.com> Date: Sat, 15 Oct 2022 16:03:46 +1100 Subject: [PATCH 056/435] fix: consistency changes to item pages (#82) Changes to the item index.vue and edit.vue pages to resolve spelling differences between the two --- frontend/pages/item/[id]/edit.vue | 4 ++-- frontend/pages/item/[id]/index.vue | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/pages/item/[id]/edit.vue b/frontend/pages/item/[id]/edit.vue index 8ffcba6..3a58e61 100644 --- a/frontend/pages/item/[id]/edit.vue +++ b/frontend/pages/item/[id]/edit.vue @@ -118,12 +118,12 @@ }, { type: "text", - label: "Purchased Price", + label: "Purchase Price", ref: "purchasePrice", }, { type: "date", - label: "Purchased At", + label: "Purchase Date", ref: "purchaseTime", }, ]; diff --git a/frontend/pages/item/[id]/index.vue b/frontend/pages/item/[id]/index.vue index 5c9c938..be42203 100644 --- a/frontend/pages/item/[id]/index.vue +++ b/frontend/pages/item/[id]/index.vue @@ -183,7 +183,7 @@ const purchaseDetails = computed>(() => { return [ { - name: "Purchase From", + name: "Purchased From", text: item.value?.purchaseFrom || "", }, { @@ -325,17 +325,17 @@ - + - + - +
From 1cc38d6a5c025ca3e79b2310b225f2f86648fd4c Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sat, 15 Oct 2022 11:24:09 -0800 Subject: [PATCH 057/435] Create FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..4626298 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [hay-kot] From 461be2afca6d7edbf5c3ece715f7364c5e7eb26b Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sat, 15 Oct 2022 12:15:55 -0800 Subject: [PATCH 058/435] feat: currency selection support (#72) * initial UI for currency selection * add task to purge invitation tokens * group API contracts * fix type import * use auth middleware * add currency setting support (UI) * use group settings for format currency * fix casing --- Taskfile.yml | 1 + backend/app/api/docs/docs.go | 90 +++++++- backend/app/api/docs/swagger.json | 90 +++++++- backend/app/api/docs/swagger.yaml | 56 ++++- backend/app/api/main.go | 10 +- backend/app/api/routes.go | 4 + backend/app/api/v1/v1_ctrl_group.go | 64 +++++- backend/ent/group/group.go | 5 +- backend/ent/migrate/schema.go | 2 +- backend/ent/schema/group.go | 2 +- backend/internal/repo/repo_group.go | 27 ++- backend/internal/repo/repo_group_test.go | 13 ++ backend/internal/services/all.go | 4 +- backend/internal/services/main_test.go | 2 +- backend/internal/services/service_group.go | 47 ++++ backend/internal/services/service_user.go | 15 -- frontend/components/Form/Select.vue | 15 +- frontend/components/global/Currency.vue | 22 ++ .../global/DetailsSection/DetailsSection.vue | 9 +- .../components/global/DetailsSection/types.ts | 22 +- frontend/composables/use-formatters.ts | 21 ++ frontend/composables/use-preferences.ts | 32 +-- frontend/composables/use-theme.ts | 2 +- frontend/layouts/default.vue | 64 +++++- frontend/layouts/home.vue | 69 ------ frontend/lib/api/__test__/public.test.ts | 40 ---- frontend/lib/api/__test__/user/group.test.ts | 66 ++++++ frontend/lib/api/classes/group.ts | 15 +- frontend/lib/api/types/data-contracts.ts | 13 ++ frontend/lib/data/currency.ts | 35 +++ frontend/lib/data/themes.ts | 150 +++++++++++++ frontend/middleware/auth.ts | 15 ++ frontend/pages/home.vue | 12 +- frontend/pages/item/[id]/edit.vue | 2 +- frontend/pages/item/[id]/index.vue | 16 +- frontend/pages/item/new.vue | 2 +- frontend/pages/items.vue | 3 +- frontend/pages/label/[id].vue | 6 +- frontend/pages/location/[id].vue | 6 +- frontend/pages/profile.vue | 204 +++++++----------- 40 files changed, 930 insertions(+), 343 deletions(-) create mode 100644 backend/internal/services/service_group.go create mode 100644 frontend/components/global/Currency.vue create mode 100644 frontend/composables/use-formatters.ts delete mode 100644 frontend/layouts/home.vue create mode 100644 frontend/lib/api/__test__/user/group.test.ts create mode 100644 frontend/lib/data/currency.ts create mode 100644 frontend/lib/data/themes.ts create mode 100644 frontend/middleware/auth.ts diff --git a/Taskfile.yml b/Taskfile.yml index 6766493..e885488 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -27,6 +27,7 @@ tasks: - "./scripts/process-types.py" generates: - "./frontend/lib/api/types/data-contracts.ts" + - "./backend/ent/schema" - "./backend/app/api/docs/swagger.json" - "./backend/app/api/docs/swagger.yaml" diff --git a/backend/app/api/docs/docs.go b/backend/app/api/docs/docs.go index 5663e3f..b77cd35 100644 --- a/backend/app/api/docs/docs.go +++ b/backend/app/api/docs/docs.go @@ -21,6 +21,63 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/v1/groups": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Group" + ], + "summary": "Get the current user's group", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/repo.Group" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Group" + ], + "summary": "Updates some fields of the current users group", + "parameters": [ + { + "description": "User Data", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/repo.GroupUpdate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/repo.Group" + } + } + } + } + }, "/v1/groups/invitations": { "post": { "security": [ @@ -32,7 +89,7 @@ const docTemplate = `{ "application/json" ], "tags": [ - "User" + "Group" ], "summary": "Get the current user", "parameters": [ @@ -1116,6 +1173,37 @@ const docTemplate = `{ } } }, + "repo.Group": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "repo.GroupUpdate": { + "type": "object", + "properties": { + "currency": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, "repo.ItemAttachment": { "type": "object", "properties": { diff --git a/backend/app/api/docs/swagger.json b/backend/app/api/docs/swagger.json index d625365..913b6a9 100644 --- a/backend/app/api/docs/swagger.json +++ b/backend/app/api/docs/swagger.json @@ -13,6 +13,63 @@ }, "basePath": "/api", "paths": { + "/v1/groups": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Group" + ], + "summary": "Get the current user's group", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/repo.Group" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "produces": [ + "application/json" + ], + "tags": [ + "Group" + ], + "summary": "Updates some fields of the current users group", + "parameters": [ + { + "description": "User Data", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/repo.GroupUpdate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/repo.Group" + } + } + } + } + }, "/v1/groups/invitations": { "post": { "security": [ @@ -24,7 +81,7 @@ "application/json" ], "tags": [ - "User" + "Group" ], "summary": "Get the current user", "parameters": [ @@ -1108,6 +1165,37 @@ } } }, + "repo.Group": { + "type": "object", + "properties": { + "createdAt": { + "type": "string" + }, + "currency": { + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + } + }, + "repo.GroupUpdate": { + "type": "object", + "properties": { + "currency": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, "repo.ItemAttachment": { "type": "object", "properties": { diff --git a/backend/app/api/docs/swagger.yaml b/backend/app/api/docs/swagger.yaml index 8c69cec..aca9f01 100644 --- a/backend/app/api/docs/swagger.yaml +++ b/backend/app/api/docs/swagger.yaml @@ -9,6 +9,26 @@ definitions: title: type: string type: object + repo.Group: + properties: + createdAt: + type: string + currency: + type: string + id: + type: string + name: + type: string + updatedAt: + type: string + type: object + repo.GroupUpdate: + properties: + currency: + type: string + name: + type: string + type: object repo.ItemAttachment: properties: createdAt: @@ -415,6 +435,40 @@ info: title: Go API Templates version: "1.0" paths: + /v1/groups: + get: + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/repo.Group' + security: + - Bearer: [] + summary: Get the current user's group + tags: + - Group + put: + parameters: + - description: User Data + in: body + name: payload + required: true + schema: + $ref: '#/definitions/repo.GroupUpdate' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/repo.Group' + security: + - Bearer: [] + summary: Updates some fields of the current users group + tags: + - Group /v1/groups/invitations: post: parameters: @@ -435,7 +489,7 @@ paths: - Bearer: [] summary: Get the current user tags: - - User + - Group /v1/items: get: parameters: diff --git a/backend/app/api/main.go b/backend/app/api/main.go index 09191a4..4340f20 100644 --- a/backend/app/api/main.go +++ b/backend/app/api/main.go @@ -110,7 +110,7 @@ func run(cfg *config.Config) error { app.db = c app.repos = repo.New(c, cfg.Storage.Data) - app.services = services.NewServices(app.repos) + app.services = services.New(app.repos) // ========================================================================= // Start Server @@ -138,6 +138,14 @@ func run(cfg *config.Config) error { Msg("failed to purge expired tokens") } }) + go app.startBgTask(time.Duration(24)*time.Hour, func() { + _, err := app.repos.Groups.InvitationPurge(context.Background()) + if err != nil { + log.Error(). + Err(err). + Msg("failed to purge expired invitations") + } + }) // TODO: Remove through external API that does setup if cfg.Demo { diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index 9cfd289..813ec26 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -72,6 +72,10 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux { r.Post(v1Base("/groups/invitations"), v1Ctrl.HandleGroupInvitationsCreate()) + // TODO: I don't like /groups being the URL for users + r.Get(v1Base("/groups"), v1Ctrl.HandleGroupGet()) + r.Put(v1Base("/groups"), v1Ctrl.HandleGroupUpdate()) + r.Get(v1Base("/locations"), v1Ctrl.HandleLocationGetAll()) r.Post(v1Base("/locations"), v1Ctrl.HandleLocationCreate()) r.Get(v1Base("/locations/{id}"), v1Ctrl.HandleLocationGet()) diff --git a/backend/app/api/v1/v1_ctrl_group.go b/backend/app/api/v1/v1_ctrl_group.go index 8b78fd8..e8bd796 100644 --- a/backend/app/api/v1/v1_ctrl_group.go +++ b/backend/app/api/v1/v1_ctrl_group.go @@ -2,8 +2,10 @@ package v1 import ( "net/http" + "strings" "time" + "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/rs/zerolog/log" @@ -22,9 +24,63 @@ type ( } ) -// HandleUserSelf godoc +// HandleGroupGet godoc +// @Summary Get the current user's group +// @Tags Group +// @Produce json +// @Success 200 {object} repo.Group +// @Router /v1/groups [Get] +// @Security Bearer +func (ctrl *V1Controller) HandleGroupGet() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := services.NewContext(r.Context()) + + group, err := ctrl.svc.Group.Get(ctx) + if err != nil { + log.Err(err).Msg("failed to get group") + server.RespondError(w, http.StatusInternalServerError, err) + return + } + group.Currency = strings.ToUpper(group.Currency) // TODO: Hack to fix the currency enums being lower caseÍ + + server.Respond(w, http.StatusOK, group) + + } +} + +// HandleGroupUpdate godoc +// @Summary Updates some fields of the current users group +// @Tags Group +// @Produce json +// @Param payload body repo.GroupUpdate true "User Data" +// @Success 200 {object} repo.Group +// @Router /v1/groups [Put] +// @Security Bearer +func (ctrl *V1Controller) HandleGroupUpdate() http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + data := repo.GroupUpdate{} + + if err := server.Decode(r, &data); err != nil { + server.RespondError(w, http.StatusBadRequest, err) + return + } + + ctx := services.NewContext(r.Context()) + + group, err := ctrl.svc.Group.UpdateGroup(ctx, data) + if err != nil { + log.Err(err).Msg("failed to update group") + server.RespondError(w, http.StatusInternalServerError, err) + return + } + group.Currency = strings.ToUpper(group.Currency) // TODO: Hack to fix the currency enums being lower case + server.Respond(w, http.StatusOK, group) + } +} + +// HandleGroupInvitationsCreate godoc // @Summary Get the current user -// @Tags User +// @Tags Group // @Produce json // @Param payload body GroupInvitationCreate true "User Data" // @Success 200 {object} GroupInvitation @@ -36,7 +92,7 @@ func (ctrl *V1Controller) HandleGroupInvitationsCreate() http.HandlerFunc { if err := server.Decode(r, &data); err != nil { log.Err(err).Msg("failed to decode user registration data") - server.RespondError(w, http.StatusInternalServerError, err) + server.RespondError(w, http.StatusBadRequest, err) return } @@ -46,7 +102,7 @@ func (ctrl *V1Controller) HandleGroupInvitationsCreate() http.HandlerFunc { ctx := services.NewContext(r.Context()) - token, err := ctrl.svc.User.NewInvitation(ctx, data.Uses, data.ExpiresAt) + token, err := ctrl.svc.Group.NewInvitation(ctx, data.Uses, data.ExpiresAt) if err != nil { log.Err(err).Msg("failed to create new token") server.RespondError(w, http.StatusInternalServerError, err) diff --git a/backend/ent/group/group.go b/backend/ent/group/group.go index 7485a7e..f46cc94 100644 --- a/backend/ent/group/group.go +++ b/backend/ent/group/group.go @@ -121,6 +121,9 @@ const DefaultCurrency = CurrencyUsd // Currency values. const ( CurrencyUsd Currency = "usd" + CurrencyEur Currency = "eur" + CurrencyGbp Currency = "gbp" + CurrencyJpy Currency = "jpy" ) func (c Currency) String() string { @@ -130,7 +133,7 @@ func (c Currency) String() string { // CurrencyValidator is a validator for the "currency" field enum values. It is called by the builders before save. func CurrencyValidator(c Currency) error { switch c { - case CurrencyUsd: + case CurrencyUsd, CurrencyEur, CurrencyGbp, CurrencyJpy: return nil default: return fmt.Errorf("group: invalid enum value for currency field: %q", c) diff --git a/backend/ent/migrate/schema.go b/backend/ent/migrate/schema.go index d849a68..7954764 100644 --- a/backend/ent/migrate/schema.go +++ b/backend/ent/migrate/schema.go @@ -127,7 +127,7 @@ var ( {Name: "created_at", Type: field.TypeTime}, {Name: "updated_at", Type: field.TypeTime}, {Name: "name", Type: field.TypeString, Size: 255}, - {Name: "currency", Type: field.TypeEnum, Enums: []string{"usd"}, Default: "usd"}, + {Name: "currency", Type: field.TypeEnum, Enums: []string{"usd", "eur", "gbp", "jpy"}, Default: "usd"}, } // GroupsTable holds the schema information for the "groups" table. GroupsTable = &schema.Table{ diff --git a/backend/ent/schema/group.go b/backend/ent/schema/group.go index 01f0c1f..a9d51ed 100644 --- a/backend/ent/schema/group.go +++ b/backend/ent/schema/group.go @@ -27,7 +27,7 @@ func (Group) Fields() []ent.Field { NotEmpty(), field.Enum("currency"). Default("usd"). - Values("usd"), // TODO: add more currencies + Values("usd", "eur", "gbp", "jpy"), // TODO: add more currencies } } diff --git a/backend/internal/repo/repo_group.go b/backend/internal/repo/repo_group.go index ef7b502..ac0e071 100644 --- a/backend/internal/repo/repo_group.go +++ b/backend/internal/repo/repo_group.go @@ -6,6 +6,7 @@ import ( "github.com/google/uuid" "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/ent/group" "github.com/hay-kot/homebox/backend/ent/groupinvitationtoken" ) @@ -15,11 +16,16 @@ type GroupRepository struct { type ( Group struct { - ID uuid.UUID - Name string - CreatedAt time.Time - UpdatedAt time.Time - Currency string + ID uuid.UUID `json:"id,omitempty"` + Name string `json:"name,omitempty"` + CreatedAt time.Time `json:"createdAt,omitempty"` + UpdatedAt time.Time `json:"updatedAt,omitempty"` + Currency string `json:"currency,omitempty"` + } + + GroupUpdate struct { + Name string `json:"name"` + Currency string `json:"currency"` } GroupInvitationCreate struct { @@ -69,6 +75,17 @@ func (r *GroupRepository) GroupCreate(ctx context.Context, name string) (Group, Save(ctx)) } +func (r *GroupRepository) GroupUpdate(ctx context.Context, ID uuid.UUID, data GroupUpdate) (Group, error) { + currency := group.Currency(data.Currency) + + entity, err := r.db.Group.UpdateOneID(ID). + SetName(data.Name). + SetCurrency(currency). + Save(ctx) + + return mapToGroupErr(entity, err) +} + func (r *GroupRepository) GroupByID(ctx context.Context, id uuid.UUID) (Group, error) { return mapToGroupErr(r.db.Group.Get(ctx, id)) } diff --git a/backend/internal/repo/repo_group_test.go b/backend/internal/repo/repo_group_test.go index 198393d..5f3faaf 100644 --- a/backend/internal/repo/repo_group_test.go +++ b/backend/internal/repo/repo_group_test.go @@ -18,3 +18,16 @@ func Test_Group_Create(t *testing.T) { assert.NoError(t, err) assert.Equal(t, g.ID, foundGroup.ID) } + +func Test_Group_Update(t *testing.T) { + g, err := tRepos.Groups.GroupCreate(context.Background(), "test") + assert.NoError(t, err) + + g, err = tRepos.Groups.GroupUpdate(context.Background(), g.ID, GroupUpdate{ + Name: "test2", + Currency: "eur", + }) + assert.NoError(t, err) + assert.Equal(t, "test2", g.Name) + assert.Equal(t, "eur", g.Currency) +} diff --git a/backend/internal/services/all.go b/backend/internal/services/all.go index a8e2e8e..20e377f 100644 --- a/backend/internal/services/all.go +++ b/backend/internal/services/all.go @@ -4,18 +4,20 @@ import "github.com/hay-kot/homebox/backend/internal/repo" type AllServices struct { User *UserService + Group *GroupService Location *LocationService Labels *LabelService Items *ItemService } -func NewServices(repos *repo.AllRepos) *AllServices { +func New(repos *repo.AllRepos) *AllServices { if repos == nil { panic("repos cannot be nil") } return &AllServices{ User: &UserService{repos}, + Group: &GroupService{repos}, Location: &LocationService{repos}, Labels: &LabelService{repos}, Items: &ItemService{ diff --git a/backend/internal/services/main_test.go b/backend/internal/services/main_test.go index 26c3519..37cb556 100644 --- a/backend/internal/services/main_test.go +++ b/backend/internal/services/main_test.go @@ -63,7 +63,7 @@ func TestMain(m *testing.M) { tClient = client tRepos = repo.New(tClient, os.TempDir()+"/homebox") - tSvc = NewServices(tRepos) + tSvc = New(tRepos) defer client.Close() bootstrap() diff --git a/backend/internal/services/service_group.go b/backend/internal/services/service_group.go new file mode 100644 index 0000000..4859f85 --- /dev/null +++ b/backend/internal/services/service_group.go @@ -0,0 +1,47 @@ +package services + +import ( + "errors" + "strings" + "time" + + "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/pkgs/hasher" +) + +type GroupService struct { + repos *repo.AllRepos +} + +func (svc *GroupService) Get(ctx Context) (repo.Group, error) { + return svc.repos.Groups.GroupByID(ctx.Context, ctx.GID) +} + +func (svc *GroupService) UpdateGroup(ctx Context, data repo.GroupUpdate) (repo.Group, error) { + if data.Name == "" { + data.Name = ctx.User.GroupName + } + + if data.Currency == "" { + return repo.Group{}, errors.New("currency cannot be empty") + } + + data.Currency = strings.ToLower(data.Currency) + + return svc.repos.Groups.GroupUpdate(ctx.Context, ctx.GID, data) +} + +func (svc *GroupService) NewInvitation(ctx Context, uses int, expiresAt time.Time) (string, error) { + token := hasher.GenerateToken() + + _, err := svc.repos.Groups.InvitationCreate(ctx, ctx.GID, repo.GroupInvitationCreate{ + Token: token.Hash, + Uses: uses, + ExpiresAt: expiresAt, + }) + if err != nil { + return "", err + } + + return token.Raw, nil +} diff --git a/backend/internal/services/service_user.go b/backend/internal/services/service_user.go index b678ab9..3060ee7 100644 --- a/backend/internal/services/service_user.go +++ b/backend/internal/services/service_user.go @@ -186,21 +186,6 @@ func (svc *UserService) DeleteSelf(ctx context.Context, ID uuid.UUID) error { return svc.repos.Users.Delete(ctx, ID) } -func (svc *UserService) NewInvitation(ctx Context, uses int, expiresAt time.Time) (string, error) { - token := hasher.GenerateToken() - - _, err := svc.repos.Groups.InvitationCreate(ctx, ctx.GID, repo.GroupInvitationCreate{ - Token: token.Hash, - Uses: uses, - ExpiresAt: expiresAt, - }) - if err != nil { - return "", err - } - - return token.Raw, nil -} - func (svc *UserService) ChangePassword(ctx Context, current string, new string) (ok bool) { usr, err := svc.repos.Users.GetOneId(ctx, ctx.UID) if err != nil { diff --git a/frontend/components/Form/Select.vue b/frontend/components/Form/Select.vue index 72f1d2e..5c84066 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, String, Boolean] as any, + type: [Object, String] as any, default: null, }, items: { @@ -53,10 +53,19 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any function compare(a: any, b: any): boolean { - if (props.value != null) { + if (props.value) { return a[props.value] === b[props.value]; } - return a === b; + + if (a === b) { + return true; + } + + if (!a || !b) { + return false; + } + + return JSON.stringify(a) === JSON.stringify(b); } watch( diff --git a/frontend/components/global/Currency.vue b/frontend/components/global/Currency.vue new file mode 100644 index 0000000..9a2c561 --- /dev/null +++ b/frontend/components/global/Currency.vue @@ -0,0 +1,22 @@ + + + diff --git a/frontend/components/global/DetailsSection/DetailsSection.vue b/frontend/components/global/DetailsSection/DetailsSection.vue index f8ee495..6b083e3 100644 --- a/frontend/components/global/DetailsSection/DetailsSection.vue +++ b/frontend/components/global/DetailsSection/DetailsSection.vue @@ -7,9 +7,8 @@
- + + @@ -21,11 +20,11 @@ + + diff --git a/frontend/layouts/home.vue b/frontend/layouts/home.vue deleted file mode 100644 index 9f0adc7..0000000 --- a/frontend/layouts/home.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - diff --git a/frontend/lib/api/__test__/public.test.ts b/frontend/lib/api/__test__/public.test.ts index 044558e..09a1aa1 100644 --- a/frontend/lib/api/__test__/public.test.ts +++ b/frontend/lib/api/__test__/public.test.ts @@ -1,6 +1,5 @@ import { describe, test, expect } from "vitest"; import { factories } from "./factories"; -import { sharedUserClient } from "./test-utils"; describe("[GET] /api/v1/status", () => { test("server should respond", async () => { @@ -32,43 +31,4 @@ describe("first time user workflow (register, login, join group)", () => { expect(response.status).toBe(204); } }); - - test("user should be able to join create join token and have user signup", async () => { - // Setup User 1 Token - - const client = await sharedUserClient(); - const { data: user1 } = await client.user.self(); - - const { response, data } = await client.group.createInvitation({ - expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7), - uses: 1, - }); - - expect(response.status).toBe(201); - expect(data.token).toBeTruthy(); - - // Create User 2 with token - - const duplicateUser = factories.user(); - duplicateUser.token = data.token; - - const { response: registerResp } = await api.register(duplicateUser); - expect(registerResp.status).toBe(204); - - const { response: loginResp, data: loginData } = await api.login(duplicateUser.email, duplicateUser.password); - expect(loginResp.status).toBe(200); - - // Get Self and Assert - - const client2 = factories.client.user(loginData.token); - - const { data: user2 } = await client2.user.self(); - - user2.item.groupName = user1.item.groupName; - - // Cleanup User 2 - - const { response: deleteResp } = await client2.user.delete(); - expect(deleteResp.status).toBe(204); - }); }); diff --git a/frontend/lib/api/__test__/user/group.test.ts b/frontend/lib/api/__test__/user/group.test.ts new file mode 100644 index 0000000..93aa576 --- /dev/null +++ b/frontend/lib/api/__test__/user/group.test.ts @@ -0,0 +1,66 @@ +import { faker } from "@faker-js/faker"; +import { describe, test, expect } from "vitest"; +import { factories } from "../factories"; +import { sharedUserClient } from "../test-utils"; + +describe("first time user workflow (register, login, join group)", () => { + test("user should be able to update group", async () => { + const { client } = await factories.client.singleUse(); + + const name = faker.name.firstName(); + + const { response, data: group } = await client.group.update({ + name, + currency: "eur", + }); + + expect(response.status).toBe(200); + expect(group.name).toBe(name); + }); + + test("user should be able to get own group", async () => { + const { client } = await factories.client.singleUse(); + + const { response, data: group } = await client.group.get(); + + expect(response.status).toBe(200); + expect(group.name).toBeTruthy(); + expect(group.currency).toBe("USD"); + }); + + test("user should be able to join create join token and have user signup", async () => { + const api = factories.client.public(); + + // Setup User 1 Token + const client = await sharedUserClient(); + const { data: user1 } = await client.user.self(); + + const { response, data } = await client.group.createInvitation({ + expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7), + uses: 1, + }); + + expect(response.status).toBe(201); + expect(data.token).toBeTruthy(); + + // Create User 2 with token + const duplicateUser = factories.user(); + duplicateUser.token = data.token; + + const { response: registerResp } = await api.register(duplicateUser); + expect(registerResp.status).toBe(204); + + const { response: loginResp, data: loginData } = await api.login(duplicateUser.email, duplicateUser.password); + expect(loginResp.status).toBe(200); + + // Get Self and Assert + const client2 = factories.client.user(loginData.token); + const { data: user2 } = await client2.user.self(); + + user2.item.groupName = user1.item.groupName; + + // Cleanup User 2 + const { response: deleteResp } = await client2.user.delete(); + expect(deleteResp.status).toBe(204); + }); +}); diff --git a/frontend/lib/api/classes/group.ts b/frontend/lib/api/classes/group.ts index 5a687f1..7468f09 100644 --- a/frontend/lib/api/classes/group.ts +++ b/frontend/lib/api/classes/group.ts @@ -1,5 +1,5 @@ import { BaseAPI, route } from "../base"; -import { GroupInvitation, GroupInvitationCreate } from "../types/data-contracts"; +import { Group, GroupInvitation, GroupInvitationCreate, GroupUpdate } from "../types/data-contracts"; export class GroupApi extends BaseAPI { createInvitation(data: GroupInvitationCreate) { @@ -8,4 +8,17 @@ export class GroupApi extends BaseAPI { body: data, }); } + + update(data: GroupUpdate) { + return this.http.put({ + url: route("/groups"), + body: data, + }); + } + + get() { + return this.http.get({ + url: route("/groups"), + }); + } } diff --git a/frontend/lib/api/types/data-contracts.ts b/frontend/lib/api/types/data-contracts.ts index 585feb1..360ae2a 100644 --- a/frontend/lib/api/types/data-contracts.ts +++ b/frontend/lib/api/types/data-contracts.ts @@ -16,6 +16,19 @@ export interface DocumentOut { title: string; } +export interface Group { + createdAt: Date; + currency: string; + id: string; + name: string; + updatedAt: Date; +} + +export interface GroupUpdate { + currency: string; + name: string; +} + export interface ItemAttachment { createdAt: Date; document: DocumentOut; diff --git a/frontend/lib/data/currency.ts b/frontend/lib/data/currency.ts new file mode 100644 index 0000000..8643d96 --- /dev/null +++ b/frontend/lib/data/currency.ts @@ -0,0 +1,35 @@ +export type Codes = "USD" | "EUR" | "GBP" | "JPY"; + +export type Currency = { + code: Codes; + local: string; + symbol: string; + name: string; +}; + +export const currencies: Currency[] = [ + { + code: "USD", + local: "en-US", + symbol: "$", + name: "US Dollar", + }, + { + code: "EUR", + local: "de-DE", + symbol: "€", + name: "Euro", + }, + { + code: "GBP", + local: "en-GB", + symbol: "£", + name: "British Pound", + }, + { + code: "JPY", + local: "ja-JP", + symbol: "¥", + name: "Japanese Yen", + }, +]; diff --git a/frontend/lib/data/themes.ts b/frontend/lib/data/themes.ts new file mode 100644 index 0000000..55f0f55 --- /dev/null +++ b/frontend/lib/data/themes.ts @@ -0,0 +1,150 @@ +export type DaisyTheme = + | "light" + | "dark" + | "cupcake" + | "bumblebee" + | "emerald" + | "corporate" + | "synthwave" + | "retro" + | "cyberpunk" + | "valentine" + | "halloween" + | "garden" + | "forest" + | "aqua" + | "lofi" + | "pastel" + | "fantasy" + | "wireframe" + | "black" + | "luxury" + | "dracula" + | "cmyk" + | "autumn" + | "business" + | "acid" + | "lemonade" + | "night" + | "coffee" + | "winter"; + +export type ThemeOption = { + label: string; + value: DaisyTheme; +}; + +export const themes: ThemeOption[] = [ + { + label: "Garden", + value: "garden", + }, + { + label: "Light", + value: "light", + }, + { + label: "Cupcake", + value: "cupcake", + }, + { + label: "Bumblebee", + value: "bumblebee", + }, + { + label: "Emerald", + value: "emerald", + }, + { + label: "Corporate", + value: "corporate", + }, + { + label: "Synthwave", + value: "synthwave", + }, + { + label: "Retro", + value: "retro", + }, + { + label: "Cyberpunk", + value: "cyberpunk", + }, + { + label: "Valentine", + value: "valentine", + }, + { + label: "Halloween", + value: "halloween", + }, + { + label: "Forest", + value: "forest", + }, + { + label: "Aqua", + value: "aqua", + }, + { + label: "Lofi", + value: "lofi", + }, + { + label: "Pastel", + value: "pastel", + }, + { + label: "Fantasy", + value: "fantasy", + }, + { + label: "Wireframe", + value: "wireframe", + }, + { + label: "Black", + value: "black", + }, + { + label: "Luxury", + value: "luxury", + }, + { + label: "Dracula", + value: "dracula", + }, + { + label: "Cmyk", + value: "cmyk", + }, + { + label: "Autumn", + value: "autumn", + }, + { + label: "Business", + value: "business", + }, + { + label: "Acid", + value: "acid", + }, + { + label: "Lemonade", + value: "lemonade", + }, + { + label: "Night", + value: "night", + }, + { + label: "Coffee", + value: "coffee", + }, + { + label: "Winter", + value: "winter", + }, +]; diff --git a/frontend/middleware/auth.ts b/frontend/middleware/auth.ts new file mode 100644 index 0000000..f67fa01 --- /dev/null +++ b/frontend/middleware/auth.ts @@ -0,0 +1,15 @@ +import { useAuthStore } from "~~/stores/auth"; + +export default defineNuxtRouteMiddleware(async () => { + const auth = useAuthStore(); + const api = useUserApi(); + + if (!auth.self) { + const { data, error } = await api.user.self(); + if (error) { + navigateTo("/"); + } + + auth.$patch({ self: data.item }); + } +}); diff --git a/frontend/pages/home.vue b/frontend/pages/home.vue index c3a4819..8bf0a54 100644 --- a/frontend/pages/home.vue +++ b/frontend/pages/home.vue @@ -5,8 +5,9 @@ import { useLocationStore } from "~~/stores/locations"; definePageMeta({ - layout: "home", + middleware: ["auth"], }); + useHead({ title: "Homebox | Home", }); @@ -15,15 +16,6 @@ const auth = useAuthStore(); - if (auth.self === null) { - const { data, error } = await api.user.self(); - if (error) { - navigateTo("/"); - } - - auth.$patch({ self: data.item }); - } - const itemsStore = useItemStore(); const items = computed(() => itemsStore.items); diff --git a/frontend/pages/item/[id]/edit.vue b/frontend/pages/item/[id]/edit.vue index 3a58e61..8ab71d4 100644 --- a/frontend/pages/item/[id]/edit.vue +++ b/frontend/pages/item/[id]/edit.vue @@ -6,7 +6,7 @@ import { capitalize } from "~~/lib/strings"; definePageMeta({ - layout: "home", + middleware: ["auth"], }); const route = useRoute(); diff --git a/frontend/pages/item/[id]/index.vue b/frontend/pages/item/[id]/index.vue index be42203..32145ab 100644 --- a/frontend/pages/item/[id]/index.vue +++ b/frontend/pages/item/[id]/index.vue @@ -1,9 +1,9 @@ diff --git a/frontend/lib/api/__test__/factories/index.ts b/frontend/lib/api/__test__/factories/index.ts index 51a0fb0..cebfb5f 100644 --- a/frontend/lib/api/__test__/factories/index.ts +++ b/frontend/lib/api/__test__/factories/index.ts @@ -2,11 +2,23 @@ import { faker } from "@faker-js/faker"; import { expect } from "vitest"; import { overrideParts } from "../../base/urls"; import { PublicApi } from "../../public"; -import { LabelCreate, LocationCreate, UserRegistration } from "../../types/data-contracts"; +import { ItemField, LabelCreate, LocationCreate, UserRegistration } from "../../types/data-contracts"; import * as config from "../../../../test/config"; import { UserClient } from "../../user"; import { Requests } from "../../../requests"; +function itemField(id = null): ItemField { + return { + id, + name: faker.lorem.word(), + type: "text", + textValue: faker.lorem.sentence(), + booleanValue: false, + numberValue: faker.datatype.number(), + timeValue: null, + }; +} + /** * Returns a random user registration object that can be * used to signup a new user. @@ -72,6 +84,7 @@ export const factories = { user, location, label, + itemField, client: { public: publicClient, user: userClient, diff --git a/frontend/lib/api/__test__/user/items.test.ts b/frontend/lib/api/__test__/user/items.test.ts index 9bdea4d..7837e50 100644 --- a/frontend/lib/api/__test__/user/items.test.ts +++ b/frontend/lib/api/__test__/user/items.test.ts @@ -1,7 +1,9 @@ +import { faker } from "@faker-js/faker"; import { describe, test, expect } from "vitest"; -import { LocationOut } from "../../types/data-contracts"; +import { ItemField, LocationOut } from "../../types/data-contracts"; import { AttachmentTypes } from "../../types/non-generated"; import { UserClient } from "../../user"; +import { factories } from "../factories"; import { sharedUserClient } from "../test-utils"; describe("user should be able to create an item and add an attachment", () => { @@ -58,4 +60,57 @@ describe("user should be able to create an item and add an attachment", () => { api.items.delete(item.id); await cleanup(); }); + + test("user should be able to create and delete fields on an item", async () => { + const api = await sharedUserClient(); + const [location, cleanup] = await useLocation(api); + + const { response, data: item } = await api.items.create({ + name: faker.vehicle.model(), + labelIds: [], + description: faker.lorem.paragraph(1), + locationId: location.id, + }); + expect(response.status).toBe(201); + + const fields: ItemField[] = [ + factories.itemField(), + factories.itemField(), + factories.itemField(), + factories.itemField(), + ]; + + // Add fields + const itemUpdate = { + ...item, + locationId: item.location.id, + labelIds: item.labels.map(l => l.id), + fields, + }; + + const { response: updateResponse, data: item2 } = await api.items.update(item.id, itemUpdate); + expect(updateResponse.status).toBe(200); + + expect(item2.fields).toHaveLength(fields.length); + + for (let i = 0; i < fields.length; i++) { + expect(item2.fields[i].name).toBe(fields[i].name); + expect(item2.fields[i].textValue).toBe(fields[i].textValue); + expect(item2.fields[i].numberValue).toBe(fields[i].numberValue); + } + + itemUpdate.fields = [fields[0], fields[1]]; + + const { response: updateResponse2, data: item3 } = await api.items.update(item.id, itemUpdate); + expect(updateResponse2.status).toBe(200); + + expect(item3.fields).toHaveLength(2); + for (let i = 0; i < item3.fields.length; i++) { + expect(item3.fields[i].name).toBe(itemUpdate.fields[i].name); + expect(item3.fields[i].textValue).toBe(itemUpdate.fields[i].textValue); + expect(item3.fields[i].numberValue).toBe(itemUpdate.fields[i].numberValue); + } + + cleanup(); + }); }); diff --git a/frontend/lib/api/types/data-contracts.ts b/frontend/lib/api/types/data-contracts.ts index 360ae2a..41c9610 100644 --- a/frontend/lib/api/types/data-contracts.ts +++ b/frontend/lib/api/types/data-contracts.ts @@ -51,10 +51,23 @@ export interface ItemCreate { name: string; } +export interface ItemField { + booleanValue: boolean; + id: string; + name: string; + numberValue: number; + textValue: string; + timeValue: string; + type: string; +} + export interface ItemOut { attachments: ItemAttachment[]; createdAt: Date; description: string; + + /** Future */ + fields: ItemField[]; id: string; insured: boolean; labels: LabelSummary[]; @@ -108,6 +121,7 @@ export interface ItemSummary { export interface ItemUpdate { description: string; + fields: ItemField[]; id: string; insured: boolean; labelIds: string[]; diff --git a/frontend/pages/item/[id]/edit.vue b/frontend/pages/item/[id]/edit.vue index c5cfb53..b08b42c 100644 --- a/frontend/pages/item/[id]/edit.vue +++ b/frontend/pages/item/[id]/edit.vue @@ -278,6 +278,34 @@ toast.success("Attachment updated"); } + + // Custom Fields + // const fieldTypes = [ + // { + // name: "Text", + // value: "text", + // }, + // { + // name: "Number", + // value: "number", + // }, + // { + // name: "Boolean", + // value: "boolean", + // }, + // ]; + + function addField() { + item.value.fields.push({ + id: null, + name: "Field Name", + type: "text", + textValue: "", + numberValue: 0, + booleanValue: false, + timeValue: null, + }); + } diff --git a/frontend/pages/location/[id].vue b/frontend/pages/location/[id].vue index a8c97ab..092ace3 100644 --- a/frontend/pages/location/[id].vue +++ b/frontend/pages/location/[id].vue @@ -1,5 +1,7 @@ @@ -152,11 +177,18 @@ -
+
Items
+ +
+ Child Locations +
+ +
+
From d151d42081983e0e191f4907673404b3dfeadb87 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Mon, 24 Oct 2022 18:24:18 -0800 Subject: [PATCH 071/435] feat: debug-endpoints (#110) * reorg + pprof endpoints * fix spacing issue * fix generation directory --- .vscode/settings.json | 5 +- Taskfile.yml | 10 +- .../app/api/handlers/debughandlers/debug.go | 16 +++ .../app/api/{ => handlers}/v1/controller.go | 0 backend/app/api/{ => handlers}/v1/partials.go | 0 .../app/api/{ => handlers}/v1/v1_ctrl_auth.go | 0 .../api/{ => handlers}/v1/v1_ctrl_group.go | 0 .../api/{ => handlers}/v1/v1_ctrl_items.go | 0 .../v1/v1_ctrl_items_attachments.go | 0 .../api/{ => handlers}/v1/v1_ctrl_labels.go | 0 .../{ => handlers}/v1/v1_ctrl_locations.go | 0 .../app/api/{ => handlers}/v1/v1_ctrl_user.go | 0 backend/app/api/main.go | 12 +- backend/app/api/routes.go | 14 ++- backend/app/api/{ => static}/docs/docs.go | 0 .../app/api/{ => static}/docs/swagger.json | 0 .../app/api/{ => static}/docs/swagger.yaml | 0 backend/app/api/{ => static}/public/.gitkeep | 0 backend/internal/config/conf.go | 6 + frontend/pages/location/[id].vue | 103 +++++++++--------- 20 files changed, 105 insertions(+), 61 deletions(-) create mode 100644 backend/app/api/handlers/debughandlers/debug.go rename backend/app/api/{ => handlers}/v1/controller.go (100%) rename backend/app/api/{ => handlers}/v1/partials.go (100%) rename backend/app/api/{ => handlers}/v1/v1_ctrl_auth.go (100%) rename backend/app/api/{ => handlers}/v1/v1_ctrl_group.go (100%) rename backend/app/api/{ => handlers}/v1/v1_ctrl_items.go (100%) rename backend/app/api/{ => handlers}/v1/v1_ctrl_items_attachments.go (100%) rename backend/app/api/{ => handlers}/v1/v1_ctrl_labels.go (100%) rename backend/app/api/{ => handlers}/v1/v1_ctrl_locations.go (100%) rename backend/app/api/{ => handlers}/v1/v1_ctrl_user.go (100%) rename backend/app/api/{ => static}/docs/docs.go (100%) rename backend/app/api/{ => static}/docs/swagger.json (100%) rename backend/app/api/{ => static}/docs/swagger.yaml (100%) rename backend/app/api/{ => static}/public/.gitkeep (100%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 85f49ba..b330533 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,5 +10,8 @@ "package.json": "package-lock.json, yarn.lock, .eslintrc.js, tsconfig.json, .prettierrc, .editorconfig, pnpm-lock.yaml, postcss.config.js, tailwind.config.js", "docker-compose.yml": "Dockerfile, .dockerignore, docker-compose.dev.yml, docker-compose.yml", "README.md": "LICENSE, SECURITY.md" - } + }, + "cSpell.words": [ + "debughandlers" + ] } diff --git a/Taskfile.yml b/Taskfile.yml index a3dbd81..4462265 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -17,13 +17,13 @@ tasks: deps: - db:generate cmds: - - cd backend/app/api/ && swag fmt - - cd backend/app/api/ && swag init --dir=./,../../internal,../../pkgs + - cd backend/app/api/static && swag fmt --dir=../ + - cd backend/app/api/static && swag init --dir=../,../../../internal,../../../pkgs - | npx swagger-typescript-api \ --no-client \ --modular \ - --path ./backend/app/api/docs/swagger.json \ + --path ./backend/app/api/static/docs/swagger.json \ --output ./frontend/lib/api/types - python3 ./scripts/process-types.py ./frontend/lib/api/types/data-contracts.ts sources: @@ -34,8 +34,8 @@ tasks: generates: - "./frontend/lib/api/types/data-contracts.ts" - "./backend/ent/schema" - - "./backend/app/api/docs/swagger.json" - - "./backend/app/api/docs/swagger.yaml" + - "./backend/app/api/static/docs/swagger.json" + - "./backend/app/api/static/docs/swagger.yaml" api: desc: Starts the backend api server (depends on generate task) diff --git a/backend/app/api/handlers/debughandlers/debug.go b/backend/app/api/handlers/debughandlers/debug.go new file mode 100644 index 0000000..ffba624 --- /dev/null +++ b/backend/app/api/handlers/debughandlers/debug.go @@ -0,0 +1,16 @@ +package debughandlers + +import ( + "expvar" + "net/http" + "net/http/pprof" +) + +func New(mux *http.ServeMux) { + mux.HandleFunc("/debug/pprof", pprof.Index) + mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) + mux.HandleFunc("/debug/pprof/profile", pprof.Profile) + mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) + mux.HandleFunc("/debug/pprof/trace", pprof.Trace) + mux.Handle("/debug/vars", expvar.Handler()) +} diff --git a/backend/app/api/v1/controller.go b/backend/app/api/handlers/v1/controller.go similarity index 100% rename from backend/app/api/v1/controller.go rename to backend/app/api/handlers/v1/controller.go diff --git a/backend/app/api/v1/partials.go b/backend/app/api/handlers/v1/partials.go similarity index 100% rename from backend/app/api/v1/partials.go rename to backend/app/api/handlers/v1/partials.go diff --git a/backend/app/api/v1/v1_ctrl_auth.go b/backend/app/api/handlers/v1/v1_ctrl_auth.go similarity index 100% rename from backend/app/api/v1/v1_ctrl_auth.go rename to backend/app/api/handlers/v1/v1_ctrl_auth.go diff --git a/backend/app/api/v1/v1_ctrl_group.go b/backend/app/api/handlers/v1/v1_ctrl_group.go similarity index 100% rename from backend/app/api/v1/v1_ctrl_group.go rename to backend/app/api/handlers/v1/v1_ctrl_group.go diff --git a/backend/app/api/v1/v1_ctrl_items.go b/backend/app/api/handlers/v1/v1_ctrl_items.go similarity index 100% rename from backend/app/api/v1/v1_ctrl_items.go rename to backend/app/api/handlers/v1/v1_ctrl_items.go diff --git a/backend/app/api/v1/v1_ctrl_items_attachments.go b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go similarity index 100% rename from backend/app/api/v1/v1_ctrl_items_attachments.go rename to backend/app/api/handlers/v1/v1_ctrl_items_attachments.go diff --git a/backend/app/api/v1/v1_ctrl_labels.go b/backend/app/api/handlers/v1/v1_ctrl_labels.go similarity index 100% rename from backend/app/api/v1/v1_ctrl_labels.go rename to backend/app/api/handlers/v1/v1_ctrl_labels.go diff --git a/backend/app/api/v1/v1_ctrl_locations.go b/backend/app/api/handlers/v1/v1_ctrl_locations.go similarity index 100% rename from backend/app/api/v1/v1_ctrl_locations.go rename to backend/app/api/handlers/v1/v1_ctrl_locations.go diff --git a/backend/app/api/v1/v1_ctrl_user.go b/backend/app/api/handlers/v1/v1_ctrl_user.go similarity index 100% rename from backend/app/api/v1/v1_ctrl_user.go rename to backend/app/api/handlers/v1/v1_ctrl_user.go diff --git a/backend/app/api/main.go b/backend/app/api/main.go index 4340f20..9cbff98 100644 --- a/backend/app/api/main.go +++ b/backend/app/api/main.go @@ -2,13 +2,14 @@ package main import ( "context" + "net/http" "os" "path/filepath" "time" atlas "ariga.io/atlas/sql/migrate" "entgo.io/ent/dialect/sql/schema" - "github.com/hay-kot/homebox/backend/app/api/docs" + "github.com/hay-kot/homebox/backend/app/api/static/docs" "github.com/hay-kot/homebox/backend/ent" "github.com/hay-kot/homebox/backend/internal/config" "github.com/hay-kot/homebox/backend/internal/migrations" @@ -153,5 +154,14 @@ func run(cfg *config.Config) error { app.SetupDemo() } + if cfg.Debug.Enabled { + debugrouter := app.debugRouter() + go func() { + if err := http.ListenAndServe(":"+cfg.Debug.Port, debugrouter); err != nil { + log.Fatal().Err(err).Msg("failed to start debug server") + } + }() + } + return app.server.Start(routes) } diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index b0a1f1c..67882ed 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -11,8 +11,9 @@ import ( "path/filepath" "github.com/go-chi/chi/v5" - _ "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/app/api/handlers/debughandlers" + v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1" + _ "github.com/hay-kot/homebox/backend/app/api/static/docs" "github.com/hay-kot/homebox/backend/internal/repo" "github.com/rs/zerolog/log" httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware @@ -23,10 +24,17 @@ const prefix = "/api" var ( ErrDir = errors.New("path is dir") - //go:embed all:public/* + //go:embed all:static/public/* public embed.FS ) +func (a *app) debugRouter() *http.ServeMux { + dbg := http.NewServeMux() + debughandlers.New(dbg) + + return dbg +} + // registerRoutes registers all the routes for the API func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux { registerMimes() diff --git a/backend/app/api/docs/docs.go b/backend/app/api/static/docs/docs.go similarity index 100% rename from backend/app/api/docs/docs.go rename to backend/app/api/static/docs/docs.go diff --git a/backend/app/api/docs/swagger.json b/backend/app/api/static/docs/swagger.json similarity index 100% rename from backend/app/api/docs/swagger.json rename to backend/app/api/static/docs/swagger.json diff --git a/backend/app/api/docs/swagger.yaml b/backend/app/api/static/docs/swagger.yaml similarity index 100% rename from backend/app/api/docs/swagger.yaml rename to backend/app/api/static/docs/swagger.yaml diff --git a/backend/app/api/public/.gitkeep b/backend/app/api/static/public/.gitkeep similarity index 100% rename from backend/app/api/public/.gitkeep rename to backend/app/api/static/public/.gitkeep diff --git a/backend/internal/config/conf.go b/backend/internal/config/conf.go index f45e19c..8e55756 100644 --- a/backend/internal/config/conf.go +++ b/backend/internal/config/conf.go @@ -24,6 +24,12 @@ type Config struct { Swagger SwaggerConf `yaml:"swagger"` Demo bool `yaml:"demo"` AllowRegistration bool `yaml:"disable_registration" conf:"default:true"` + Debug DebugConf `yaml:"debug"` +} + +type DebugConf struct { + Enabled bool `yaml:"enabled" conf:"default:false"` + Port string `yaml:"port" conf:"default:4000"` } type SwaggerConf struct { diff --git a/frontend/pages/location/[id].vue b/frontend/pages/location/[id].vue index 092ace3..d915e0b 100644 --- a/frontend/pages/location/[id].vue +++ b/frontend/pages/location/[id].vue @@ -124,7 +124,7 @@ From 4aee60c24212f620fcfd65408176ffea77cdfc81 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Tue, 25 Oct 2022 09:17:31 -0800 Subject: [PATCH 072/435] update frontend output --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 674e8b1..d93ea2b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ WORKDIR /go/src/app COPY ./backend . RUN go get -d -v ./... RUN rm -rf ./app/api/public -COPY --from=frontend-builder /app/.output/public ./app/api/public +COPY --from=frontend-builder /app/.output/public ./app/api/static/public RUN CGO_ENABLED=1 GOOS=linux go build \ -ldflags "-s -w -X main.commit=$COMMIT -X main.buildTime=$BUILD_TIME -X main.version=$VERSION" \ -o /go/bin/api \ From 82269e8a953c61fef82fbaae0f1affdecbbfb212 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Tue, 25 Oct 2022 11:24:19 -0800 Subject: [PATCH 073/435] clean logs --- backend/app/api/routes.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index 67882ed..f5d887a 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -15,7 +15,6 @@ import ( v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1" _ "github.com/hay-kot/homebox/backend/app/api/static/docs" "github.com/hay-kot/homebox/backend/internal/repo" - "github.com/rs/zerolog/log" httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware ) @@ -167,14 +166,11 @@ func notFoundHandler() http.HandlerFunc { } return func(w http.ResponseWriter, r *http.Request) { - err := tryRead(public, "public", r.URL.Path, w) + err := tryRead(public, "static/public", r.URL.Path, w) if err == nil { return } - log.Debug(). - Str("path", r.URL.Path). - Msg("served from embed not found - serving index.html") - err = tryRead(public, "public", "index.html", w) + err = tryRead(public, "static/public", "index.html", w) if err != nil { panic(err) } From e2d93f8523a0257d6c1cdf74a6e718a8151e88b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 29 Oct 2022 18:11:23 -0800 Subject: [PATCH 074/435] fix(deps): bump github.com/mattn/go-sqlite3 in /backend (#113) Bumps [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) from 1.14.15 to 1.14.16. - [Release notes](https://github.com/mattn/go-sqlite3/releases) - [Commits](https://github.com/mattn/go-sqlite3/compare/v1.14.15...v1.14.16) --- updated-dependencies: - dependency-name: github.com/mattn/go-sqlite3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- backend/go.mod | 2 +- backend/go.sum | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/backend/go.mod b/backend/go.mod index 0fab265..d9d7116 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -8,7 +8,7 @@ require ( github.com/ardanlabs/conf/v2 v2.2.0 github.com/go-chi/chi/v5 v5.0.7 github.com/google/uuid v1.3.0 - github.com/mattn/go-sqlite3 v1.14.15 + github.com/mattn/go-sqlite3 v1.14.16 github.com/rs/zerolog v1.28.0 github.com/stretchr/testify v1.8.1 github.com/swaggo/http-swagger v1.3.3 diff --git a/backend/go.sum b/backend/go.sum index 3c11bcb..3510f5d 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -61,13 +61,11 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= -github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= -github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -77,8 +75,6 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= -github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= From 6529549289b4cfc8b1c9f07777a6ece6d815f7e3 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sat, 29 Oct 2022 18:15:35 -0800 Subject: [PATCH 075/435] refactor: http interfaces (#114) * implement custom http handler interface * implement trace_id * normalize http method spacing for consistent logs * fix failing test * fix linter errors * cleanup old dead code * more route cleanup * cleanup some inconsistent errors * update and generate code * make taskfile more consistent * update task calls * run tidy * drop `@` tag for version * use relative paths * tidy * fix auto-setting variables * update build paths * add contributing guide * tidy --- .github/workflows/partial-backend.yaml | 4 +- .github/workflows/pull-requests.yaml | 4 +- .gitignore | 2 +- CONTRIBUTING.md | 51 +++++++ Taskfile.yml | 70 ++++++---- backend/app/api/handlers/v1/controller.go | 6 +- backend/app/api/handlers/v1/partials.go | 24 ++-- backend/app/api/handlers/v1/v1_ctrl_auth.go | 59 ++++---- backend/app/api/handlers/v1/v1_ctrl_group.go | 36 +++-- backend/app/api/handlers/v1/v1_ctrl_items.go | 75 +++++------ .../handlers/v1/v1_ctrl_items_attachments.go | 94 ++++++------- backend/app/api/handlers/v1/v1_ctrl_labels.go | 59 ++++---- .../app/api/handlers/v1/v1_ctrl_locations.go | 58 ++++---- backend/app/api/handlers/v1/v1_ctrl_user.go | 61 ++++----- backend/app/api/logger.go | 2 +- backend/app/api/main.go | 23 +++- backend/app/api/middleware.go | 123 +---------------- backend/app/api/routes.go | 127 +++++++----------- backend/app/api/static/docs/docs.go | 30 ++--- backend/app/api/static/docs/swagger.json | 30 ++--- backend/app/api/static/docs/swagger.yaml | 20 +-- backend/internal/sys/validate/errors.go | 119 ++++++++++++++++ backend/internal/web/mid/errors.go | 70 ++++++++++ backend/internal/web/mid/logger.go | 97 +++++++++++++ backend/internal/web/mid/panic.go | 33 +++++ backend/pkgs/server/errors.go | 23 ++++ backend/pkgs/server/handler.go | 25 ++++ backend/pkgs/server/middleware.go | 38 ++++++ backend/pkgs/server/mux.go | 103 ++++++++++++++ backend/pkgs/server/request.go | 10 +- backend/pkgs/server/response.go | 37 ++--- backend/pkgs/server/response_error_builder.go | 76 ----------- .../server/response_error_builder_test.go | 107 --------------- backend/pkgs/server/response_test.go | 45 +------ backend/pkgs/server/result.go | 12 -- backend/pkgs/server/server.go | 13 +- backend/pkgs/server/server_options.go | 7 + backend/pkgs/server/server_test.go | 7 +- frontend/lib/api/types/data-contracts.ts | 10 +- frontend/pages/index.vue | 2 +- 40 files changed, 984 insertions(+), 808 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 backend/internal/sys/validate/errors.go create mode 100644 backend/internal/web/mid/errors.go create mode 100644 backend/internal/web/mid/logger.go create mode 100644 backend/internal/web/mid/panic.go create mode 100644 backend/pkgs/server/errors.go create mode 100644 backend/pkgs/server/handler.go create mode 100644 backend/pkgs/server/middleware.go create mode 100644 backend/pkgs/server/mux.go delete mode 100644 backend/pkgs/server/response_error_builder.go delete mode 100644 backend/pkgs/server/response_error_builder_test.go diff --git a/.github/workflows/partial-backend.yaml b/.github/workflows/partial-backend.yaml index f01a0df..1bb0dce 100644 --- a/.github/workflows/partial-backend.yaml +++ b/.github/workflows/partial-backend.yaml @@ -28,7 +28,7 @@ jobs: args: --timeout=6m - name: Build API - run: task api:build + run: task go:build - name: Test - run: task api:coverage + run: task go:coverage diff --git a/.github/workflows/pull-requests.yaml b/.github/workflows/pull-requests.yaml index 1ccdec6..2debdbd 100644 --- a/.github/workflows/pull-requests.yaml +++ b/.github/workflows/pull-requests.yaml @@ -8,8 +8,8 @@ on: jobs: backend-tests: name: "Backend Server Tests" - uses: hay-kot/homebox/.github/workflows/partial-backend.yaml@main + uses: ./.github/workflows/partial-backend.yaml frontend-tests: name: "Frontend and End-to-End Tests" - uses: hay-kot/homebox/.github/workflows/partial-frontend.yaml@main + uses: ./.github/workflows/partial-frontend.yaml diff --git a/.gitignore b/.gitignore index 2aab999..7fbecd2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ backend/.data/* config.yml homebox.db .idea - .DS_Store test-mailer.json node_modules @@ -32,6 +31,7 @@ node_modules go.work .task/ backend/.env +build/* # Output Directory for Nuxt/Frontend during build step backend/app/api/public/* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..90095ac --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,51 @@ +# Contributing + +## We Develop with Github + +We use github to host code, to track issues and feature requests, as well as accept pull requests. + +## Branch Flow + +We use the `main` branch as the development branch. All PRs should be made to the `main` branch from a feature branch. To create a pull request you can use the following steps: + +1. Fork the repository and create a new branch from `main`. +2. If you've added code that should be tested, add tests. +3. If you've changed API's, update the documentation. +4. Ensure that the test suite and linters pass +5. Issue your pull request + +## How To Get Started + +### Prerequisites + +There is a devcontainer available for this project. If you are using VSCode, you can use the devcontainer to get started. If you are not using VSCode, you can need to ensure that you have the following tools installed: + +- [Go 1.19+](https://golang.org/doc/install) +- [Swaggo](https://github.com/swaggo/swag) +- [Node.js 16+](https://nodejs.org/en/download/) +- [pnpm](https://pnpm.io/installation) +- [Taskfile](https://taskfile.dev/#/installation) (Optional but recommended) +- For code generation, you'll need to have `python3` available on your path. In most cases, this is already installed and available. + +If you're using `taskfile` you can run `task --list-all` for a list of all commands and their descriptions. + +### Setup + +If you're using the taskfile you can use the `task setup` command to run the required setup commands. Otherwise you can review the commands required in the `Taskfile.yml` file. + +Note that when installing dependencies with pnpm you must use the `--shamefully-hoist` flag. If you don't use this flag you will get an error when running the the frontend server. + +### API Development Notes + +start command `task go:run` + +1. API Server does not auto reload. You'll need to restart the server after making changes. +2. Unit tests should be written in Go, however end-to-end or user story tests should be written in TypeScript using the client library in the frontend directory. + +### Frontend Development Notes + +start command `task: ui:dev` + +1. The frontend is a Vue 3 app with Nuxt.js that uses Tailwind and DaisyUI for styling. +2. We're using Vitest for our automated testing. you can run these with `task ui:watch`. +3. Tests require the API server to be running and in some cases the first run will fail due to a race condition. If this happens just run the tests again and they should pass. \ No newline at end of file diff --git a/Taskfile.yml b/Taskfile.yml index 4462265..48044ee 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -5,11 +5,12 @@ env: UNSAFE_DISABLE_PASSWORD_PROJECTION: "yes_i_am_sure" tasks: setup: - desc: Install dependencies + desc: Install development dependencies cmds: - go install github.com/swaggo/swag/cmd/swag@latest - cd backend && go mod tidy - cd frontend && pnpm install --shamefully-hoist + generate: desc: | Generates collateral files from the backend project @@ -37,7 +38,7 @@ tasks: - "./backend/app/api/static/docs/swagger.json" - "./backend/app/api/static/docs/swagger.yaml" - api: + go:run: desc: Starts the backend api server (depends on generate task) deps: - generate @@ -45,42 +46,38 @@ tasks: - cd backend && go run ./app/api/ {{ .CLI_ARGS }} silent: false - api:build: + go:test: + desc: Runs all go tests using gotestsum - supports passing gotestsum args cmds: - - cd backend && go build ./app/api/ - silent: true + - cd backend && gotestsum {{ .CLI_ARGS }} ./... - api:test: - cmds: - - cd backend && go test ./app/api/ - silent: true - - api:watch: - cmds: - - cd backend && gotestsum --watch ./... - - api:coverage: + go:coverage: + desc: Runs all go tests with -race flag and generates a coverage report cmds: - cd backend && go test -race -coverprofile=coverage.out -covermode=atomic ./app/... ./internal/... ./pkgs/... -v -cover silent: true - test:ci: + go:tidy: + desc: Runs go mod tidy on the backend cmds: - - cd backend && go build ./app/api - - backend/api & - - sleep 5 - - cd frontend && pnpm run test:ci - silent: true + - cd backend && go mod tidy - frontend:watch: - desc: Starts the vitest test runner in watch mode + go:lint: + desc: Runs golangci-lint cmds: - - cd frontend && pnpm vitest --watch + - cd backend && golangci-lint run ./... - frontend: - desc: Run frontend development server + go:all: + desc: Runs all go test and lint related tasks cmds: - - cd frontend && pnpm dev + - task: go:tidy + - task: go:lint + - task: go:test + + go:build: + desc: Builds the backend binary + cmds: + - cd backend && go build -o ../build/backend ./app/api db:generate: desc: Run Entgo.io Code Generation @@ -99,3 +96,22 @@ tasks: - db:generate cmds: - cd backend && go run app/migrations/main.go {{ .CLI_ARGS }} + + ui:watch: + desc: Starts the vitest test runner in watch mode + cmds: + - cd frontend && pnpm vitest --watch + + ui:dev: + desc: Run frontend development server + cmds: + - cd frontend && pnpm dev + + test:ci: + desc: Runs end-to-end test on a live server (only for use in CI) + cmds: + - cd backend && go build ./app/api + - backend/api & + - sleep 5 + - cd frontend && pnpm run test:ci + silent: true diff --git a/backend/app/api/handlers/v1/controller.go b/backend/app/api/handlers/v1/controller.go index ed1f3f7..2c41bc1 100644 --- a/backend/app/api/handlers/v1/controller.go +++ b/backend/app/api/handlers/v1/controller.go @@ -76,9 +76,9 @@ func NewControllerV1(svc *services.AllServices, options ...func(*V1Controller)) // @Produce json // @Success 200 {object} ApiSummary // @Router /v1/status [GET] -func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - server.Respond(w, http.StatusOK, ApiSummary{ +func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { + return server.Respond(w, http.StatusOK, ApiSummary{ Healthy: ready(), Title: "Go API Template", Message: "Welcome to the Go API Template Application!", diff --git a/backend/app/api/handlers/v1/partials.go b/backend/app/api/handlers/v1/partials.go index 47249e6..763805f 100644 --- a/backend/app/api/handlers/v1/partials.go +++ b/backend/app/api/handlers/v1/partials.go @@ -5,17 +5,23 @@ import ( "github.com/go-chi/chi/v5" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/pkgs/server" - "github.com/rs/zerolog/log" + "github.com/hay-kot/homebox/backend/internal/sys/validate" ) -func (ctrl *V1Controller) routeID(w http.ResponseWriter, r *http.Request) (uuid.UUID, error) { - ID, err := uuid.Parse(chi.URLParam(r, "id")) - if err != nil { - log.Err(err).Msg("failed to parse id") - server.RespondError(w, http.StatusBadRequest, err) - return uuid.Nil, err - } +// routeID extracts the ID from the request URL. If the ID is not in a valid +// format, an error is returned. If a error is returned, it can be directly returned +// from the handler. the validate.ErrInvalidID error is known by the error middleware +// and will be handled accordingly. +// +// Example: /api/v1/ac614db5-d8b8-4659-9b14-6e913a6eb18a -> uuid.UUID{ac614db5-d8b8-4659-9b14-6e913a6eb18a} +func (ctrl *V1Controller) routeID(r *http.Request) (uuid.UUID, error) { + return ctrl.routeUUID(r, "id") +} +func (ctrl *V1Controller) routeUUID(r *http.Request, key string) (uuid.UUID, error) { + ID, err := uuid.Parse(chi.URLParam(r, key)) + if err != nil { + return uuid.Nil, validate.NewInvalidRouteKeyError(key) + } return ID, nil } diff --git a/backend/app/api/handlers/v1/v1_ctrl_auth.go b/backend/app/api/handlers/v1/v1_ctrl_auth.go index d410a86..28ee0dc 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_auth.go +++ b/backend/app/api/handlers/v1/v1_ctrl_auth.go @@ -6,6 +6,7 @@ import ( "time" "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) @@ -32,17 +33,15 @@ type ( // @Produce json // @Success 200 {object} TokenResponse // @Router /v1/users/login [POST] -func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleAuthLogin() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { loginForm := &LoginForm{} switch r.Header.Get("Content-Type") { case server.ContentFormUrlEncoded: err := r.ParseForm() if err != nil { - server.Respond(w, http.StatusBadRequest, server.Wrap(err)) - log.Error().Err(err).Msg("failed to parse form") - return + return server.Respond(w, http.StatusBadRequest, server.Wrap(err)) } loginForm.Username = r.PostFormValue("username") @@ -52,27 +51,31 @@ func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc { if err != nil { log.Err(err).Msg("failed to decode login form") - server.Respond(w, http.StatusBadRequest, server.Wrap(err)) - return } default: - server.Respond(w, http.StatusBadRequest, errors.New("invalid content type")) - return + return server.Respond(w, http.StatusBadRequest, errors.New("invalid content type")) } if loginForm.Username == "" || loginForm.Password == "" { - server.RespondError(w, http.StatusBadRequest, errors.New("username and password are required")) - return + return validate.NewFieldErrors( + validate.FieldError{ + Field: "username", + Error: "username or password is empty", + }, + validate.FieldError{ + Field: "password", + Error: "username or password is empty", + }, + ) } newToken, err := ctrl.svc.User.Login(r.Context(), loginForm.Username, loginForm.Password) if err != nil { - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, TokenResponse{ + return server.Respond(w, http.StatusOK, TokenResponse{ Token: "Bearer " + newToken.Raw, ExpiresAt: newToken.ExpiresAt, }) @@ -85,23 +88,19 @@ func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc { // @Success 204 // @Router /v1/users/logout [POST] // @Security Bearer -func (ctrl *V1Controller) HandleAuthLogout() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleAuthLogout() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { token := services.UseTokenCtx(r.Context()) - if token == "" { - server.RespondError(w, http.StatusUnauthorized, errors.New("no token within request context")) - return + return validate.NewRequestError(errors.New("no token within request context"), http.StatusUnauthorized) } err := ctrl.svc.User.Logout(r.Context(), token) - if err != nil { - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusNoContent, nil) + return server.Respond(w, http.StatusNoContent, nil) } } @@ -113,22 +112,18 @@ func (ctrl *V1Controller) HandleAuthLogout() http.HandlerFunc { // @Success 200 // @Router /v1/users/refresh [GET] // @Security Bearer -func (ctrl *V1Controller) HandleAuthRefresh() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleAuthRefresh() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { requestToken := services.UseTokenCtx(r.Context()) - if requestToken == "" { - server.RespondError(w, http.StatusUnauthorized, errors.New("no user token found")) - return + return validate.NewRequestError(errors.New("no token within request context"), http.StatusUnauthorized) } newToken, err := ctrl.svc.User.RenewToken(r.Context(), requestToken) - if err != nil { - server.RespondUnauthorized(w) - return + return validate.NewUnauthorizedError() } - server.Respond(w, http.StatusOK, newToken) + return server.Respond(w, http.StatusOK, newToken) } } diff --git a/backend/app/api/handlers/v1/v1_ctrl_group.go b/backend/app/api/handlers/v1/v1_ctrl_group.go index fe87379..a403877 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_group.go +++ b/backend/app/api/handlers/v1/v1_ctrl_group.go @@ -7,6 +7,7 @@ import ( "github.com/hay-kot/homebox/backend/internal/repo" "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) @@ -31,7 +32,7 @@ type ( // @Success 200 {object} repo.Group // @Router /v1/groups [Get] // @Security Bearer -func (ctrl *V1Controller) HandleGroupGet() http.HandlerFunc { +func (ctrl *V1Controller) HandleGroupGet() server.HandlerFunc { return ctrl.handleGroupGeneral() } @@ -43,12 +44,12 @@ func (ctrl *V1Controller) HandleGroupGet() http.HandlerFunc { // @Success 200 {object} repo.Group // @Router /v1/groups [Put] // @Security Bearer -func (ctrl *V1Controller) HandleGroupUpdate() http.HandlerFunc { +func (ctrl *V1Controller) HandleGroupUpdate() server.HandlerFunc { return ctrl.handleGroupGeneral() } -func (ctrl *V1Controller) handleGroupGeneral() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) handleGroupGeneral() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { ctx := services.NewContext(r.Context()) switch r.Method { @@ -56,29 +57,28 @@ func (ctrl *V1Controller) handleGroupGeneral() http.HandlerFunc { group, err := ctrl.svc.Group.Get(ctx) if err != nil { log.Err(err).Msg("failed to get group") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } group.Currency = strings.ToUpper(group.Currency) // TODO: Hack to fix the currency enums being lower caseÍ - server.Respond(w, http.StatusOK, group) + return server.Respond(w, http.StatusOK, group) case http.MethodPut: data := repo.GroupUpdate{} if err := server.Decode(r, &data); err != nil { - server.RespondError(w, http.StatusBadRequest, err) - return + return validate.NewRequestError(err, http.StatusBadRequest) } group, err := ctrl.svc.Group.UpdateGroup(ctx, data) if err != nil { log.Err(err).Msg("failed to update group") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } group.Currency = strings.ToUpper(group.Currency) // TODO: Hack to fix the currency enums being lower case - server.Respond(w, http.StatusOK, group) + return server.Respond(w, http.StatusOK, group) } + + return nil } } @@ -90,13 +90,12 @@ func (ctrl *V1Controller) handleGroupGeneral() http.HandlerFunc { // @Success 200 {object} GroupInvitation // @Router /v1/groups/invitations [Post] // @Security Bearer -func (ctrl *V1Controller) HandleGroupInvitationsCreate() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleGroupInvitationsCreate() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { data := GroupInvitationCreate{} if err := server.Decode(r, &data); err != nil { log.Err(err).Msg("failed to decode user registration data") - server.RespondError(w, http.StatusBadRequest, err) - return + return validate.NewRequestError(err, http.StatusBadRequest) } if data.ExpiresAt.IsZero() { @@ -108,11 +107,10 @@ func (ctrl *V1Controller) HandleGroupInvitationsCreate() http.HandlerFunc { token, err := ctrl.svc.Group.NewInvitation(ctx, data.Uses, data.ExpiresAt) if err != nil { log.Err(err).Msg("failed to create new token") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusCreated, GroupInvitation{ + return server.Respond(w, http.StatusCreated, GroupInvitation{ Token: token, ExpiresAt: data.ExpiresAt, Uses: data.Uses, diff --git a/backend/app/api/handlers/v1/v1_ctrl_items.go b/backend/app/api/handlers/v1/v1_ctrl_items.go index 49fe8b6..84591ca 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items.go @@ -9,6 +9,7 @@ import ( "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/repo" "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) @@ -25,7 +26,7 @@ import ( // @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{} // @Router /v1/items [GET] // @Security Bearer -func (ctrl *V1Controller) HandleItemsGetAll() http.HandlerFunc { +func (ctrl *V1Controller) HandleItemsGetAll() server.HandlerFunc { uuidList := func(params url.Values, key string) []uuid.UUID { var ids []uuid.UUID for _, id := range params[key] { @@ -58,15 +59,14 @@ func (ctrl *V1Controller) HandleItemsGetAll() http.HandlerFunc { } } - return func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) error { ctx := services.NewContext(r.Context()) items, err := ctrl.svc.Items.Query(ctx, extractQuery(r)) if err != nil { log.Err(err).Msg("failed to get items") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, items) + return server.Respond(w, http.StatusOK, items) } } @@ -78,24 +78,22 @@ func (ctrl *V1Controller) HandleItemsGetAll() http.HandlerFunc { // @Success 200 {object} repo.ItemSummary // @Router /v1/items [POST] // @Security Bearer -func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleItemsCreate() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { createData := repo.ItemCreate{} if err := server.Decode(r, &createData); err != nil { log.Err(err).Msg("failed to decode request body") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } user := services.UseUserCtx(r.Context()) item, err := ctrl.svc.Items.Create(r.Context(), user.GroupID, createData) if err != nil { log.Err(err).Msg("failed to create item") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusCreated, item) + return server.Respond(w, http.StatusCreated, item) } } @@ -107,7 +105,7 @@ func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc { // @Success 200 {object} repo.ItemOut // @Router /v1/items/{id} [GET] // @Security Bearer -func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc { +func (ctrl *V1Controller) HandleItemGet() server.HandlerFunc { return ctrl.handleItemsGeneral() } @@ -119,7 +117,7 @@ func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc { // @Success 204 // @Router /v1/items/{id} [DELETE] // @Security Bearer -func (ctrl *V1Controller) HandleItemDelete() http.HandlerFunc { +func (ctrl *V1Controller) HandleItemDelete() server.HandlerFunc { return ctrl.handleItemsGeneral() } @@ -132,16 +130,16 @@ func (ctrl *V1Controller) HandleItemDelete() http.HandlerFunc { // @Success 200 {object} repo.ItemOut // @Router /v1/items/{id} [PUT] // @Security Bearer -func (ctrl *V1Controller) HandleItemUpdate() http.HandlerFunc { +func (ctrl *V1Controller) HandleItemUpdate() server.HandlerFunc { return ctrl.handleItemsGeneral() } -func (ctrl *V1Controller) handleItemsGeneral() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) handleItemsGeneral() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { ctx := services.NewContext(r.Context()) - ID, err := ctrl.routeID(w, r) + ID, err := ctrl.routeID(r) if err != nil { - return + return err } switch r.Method { @@ -149,37 +147,32 @@ func (ctrl *V1Controller) handleItemsGeneral() http.HandlerFunc { items, err := ctrl.svc.Items.GetOne(r.Context(), ctx.GID, ID) if err != nil { log.Err(err).Msg("failed to get item") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, items) - return + return server.Respond(w, http.StatusOK, items) case http.MethodDelete: err = ctrl.svc.Items.Delete(r.Context(), ctx.GID, ID) if err != nil { log.Err(err).Msg("failed to delete item") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusNoContent, nil) - return + return server.Respond(w, http.StatusNoContent, nil) case http.MethodPut: body := repo.ItemUpdate{} if err := server.Decode(r, &body); err != nil { log.Err(err).Msg("failed to decode request body") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } body.ID = ID result, err := ctrl.svc.Items.Update(r.Context(), ctx.GID, body) if err != nil { log.Err(err).Msg("failed to update item") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, result) + return server.Respond(w, http.StatusOK, result) } + return nil } } @@ -191,29 +184,26 @@ func (ctrl *V1Controller) handleItemsGeneral() http.HandlerFunc { // @Param csv formData file true "Image to upload" // @Router /v1/items/import [Post] // @Security Bearer -func (ctrl *V1Controller) HandleItemsImport() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleItemsImport() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { err := r.ParseMultipartForm(ctrl.maxUploadSize << 20) if err != nil { log.Err(err).Msg("failed to parse multipart form") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } file, _, err := r.FormFile("csv") if err != nil { log.Err(err).Msg("failed to get file from form") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } reader := csv.NewReader(file) data, err := reader.ReadAll() if err != nil { log.Err(err).Msg("failed to read csv") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } user := services.UseUserCtx(r.Context()) @@ -221,10 +211,9 @@ func (ctrl *V1Controller) HandleItemsImport() http.HandlerFunc { _, err = ctrl.svc.Items.CsvImport(r.Context(), user.GroupID, data) if err != nil { log.Err(err).Msg("failed to import items") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusNoContent, nil) + return server.Respond(w, http.StatusNoContent, nil) } } diff --git a/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go index d4e2981..5d90157 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go @@ -5,11 +5,10 @@ import ( "fmt" "net/http" - "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/repo" "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) @@ -29,19 +28,19 @@ type ( // @Param type formData string true "Type of file" // @Param name formData string true "name of the file including extension" // @Success 200 {object} repo.ItemOut -// @Failure 422 {object} []server.ValidationError +// @Failure 422 {object} server.ErrorResponse // @Router /v1/items/{id}/attachments [POST] // @Security Bearer -func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleItemAttachmentCreate() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { 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 + return validate.NewRequestError(errors.New("failed to parse multipart form"), http.StatusBadRequest) + } - errs := make(server.ValidationErrors, 0) + errs := validate.NewFieldErrors() file, _, err := r.FormFile("file") if err != nil { @@ -51,8 +50,7 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc { errs = errs.Append("file", "file is required") default: log.Err(err).Msg("failed to get file from form") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } } @@ -62,9 +60,8 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc { errs = errs.Append("name", "name is required") } - if errs.HasErrors() { - server.Respond(w, http.StatusUnprocessableEntity, errs) - return + if !errs.Nil() { + return server.Respond(w, http.StatusUnprocessableEntity, errs) } attachmentType := r.FormValue("type") @@ -72,9 +69,9 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc { attachmentType = attachment.TypeAttachment.String() } - id, err := ctrl.routeID(w, r) + id, err := ctrl.routeID(r) if err != nil { - return + return err } ctx := services.NewContext(r.Context()) @@ -89,11 +86,10 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc { if err != nil { log.Err(err).Msg("failed to add attachment") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusCreated, item) + return server.Respond(w, http.StatusCreated, item) } } @@ -106,21 +102,21 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc { // @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) { +func (ctrl *V1Controller) HandleItemAttachmentDownload() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { token := server.GetParam(r, "token", "") doc, err := ctrl.svc.Items.AttachmentPath(r.Context(), token) if err != nil { log.Err(err).Msg("failed to get attachment") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", doc.Title)) w.Header().Set("Content-Type", "application/octet-stream") http.ServeFile(w, r, doc.Path) + return nil } } @@ -133,7 +129,7 @@ func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc { // @Success 200 {object} ItemAttachmentToken // @Router /v1/items/{id}/attachments/{attachment_id} [GET] // @Security Bearer -func (ctrl *V1Controller) HandleItemAttachmentToken() http.HandlerFunc { +func (ctrl *V1Controller) HandleItemAttachmentToken() server.HandlerFunc { return ctrl.handleItemAttachmentsHandler } @@ -145,7 +141,7 @@ func (ctrl *V1Controller) HandleItemAttachmentToken() http.HandlerFunc { // @Success 204 // @Router /v1/items/{id}/attachments/{attachment_id} [DELETE] // @Security Bearer -func (ctrl *V1Controller) HandleItemAttachmentDelete() http.HandlerFunc { +func (ctrl *V1Controller) HandleItemAttachmentDelete() server.HandlerFunc { return ctrl.handleItemAttachmentsHandler } @@ -158,66 +154,60 @@ func (ctrl *V1Controller) HandleItemAttachmentDelete() http.HandlerFunc { // @Success 200 {object} repo.ItemOut // @Router /v1/items/{id}/attachments/{attachment_id} [PUT] // @Security Bearer -func (ctrl *V1Controller) HandleItemAttachmentUpdate() http.HandlerFunc { +func (ctrl *V1Controller) HandleItemAttachmentUpdate() server.HandlerFunc { return ctrl.handleItemAttachmentsHandler } -func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r *http.Request) { - ID, err := ctrl.routeID(w, r) +func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r *http.Request) error { + ID, err := ctrl.routeID(r) if err != nil { - return + return err } - attachmentId, err := uuid.Parse(chi.URLParam(r, "attachment_id")) + attachmentID, err := ctrl.routeUUID(r, "attachment_id") if err != nil { - log.Err(err).Msg("failed to parse attachment_id param") - server.RespondError(w, http.StatusBadRequest, err) - return + return err } ctx := services.NewContext(r.Context()) - switch r.Method { - // Token Handler case http.MethodGet: - token, err := ctrl.svc.Items.AttachmentToken(ctx, ID, attachmentId) + token, err := ctrl.svc.Items.AttachmentToken(ctx, ID, attachmentID) if err != nil { switch err { case services.ErrNotFound: log.Err(err). - Str("id", attachmentId.String()). + Str("id", attachmentID.String()). Msg("failed to find attachment with id") - server.RespondError(w, http.StatusNotFound, err) + return validate.NewRequestError(err, http.StatusNotFound) case services.ErrFileNotFound: log.Err(err). - Str("id", attachmentId.String()). + 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) + return validate.NewRequestError(err, http.StatusNotFound) default: log.Err(err).Msg("failed to get attachment") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } } - server.Respond(w, http.StatusOK, ItemAttachmentToken{Token: token}) + return server.Respond(w, http.StatusOK, ItemAttachmentToken{Token: token}) // Delete Attachment Handler case http.MethodDelete: - err = ctrl.svc.Items.AttachmentDelete(r.Context(), ctx.GID, ID, attachmentId) + err = ctrl.svc.Items.AttachmentDelete(r.Context(), ctx.GID, ID, attachmentID) if err != nil { log.Err(err).Msg("failed to delete attachment") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusNoContent, nil) + return server.Respond(w, http.StatusNoContent, nil) // Update Attachment Handler case http.MethodPut: @@ -225,18 +215,18 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r err = server.Decode(r, &attachment) if err != nil { log.Err(err).Msg("failed to decode attachment") - server.RespondError(w, http.StatusBadRequest, err) - return + return validate.NewRequestError(err, http.StatusBadRequest) } - attachment.ID = attachmentId + attachment.ID = attachmentID val, err := ctrl.svc.Items.AttachmentUpdate(ctx, ID, &attachment) if err != nil { log.Err(err).Msg("failed to delete attachment") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, val) + return server.Respond(w, http.StatusOK, val) } + + return nil } diff --git a/backend/app/api/handlers/v1/v1_ctrl_labels.go b/backend/app/api/handlers/v1/v1_ctrl_labels.go index 7d3c00d..f02a929 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_labels.go +++ b/backend/app/api/handlers/v1/v1_ctrl_labels.go @@ -6,6 +6,7 @@ import ( "github.com/hay-kot/homebox/backend/ent" "github.com/hay-kot/homebox/backend/internal/repo" "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) @@ -17,16 +18,15 @@ import ( // @Success 200 {object} server.Results{items=[]repo.LabelOut} // @Router /v1/labels [GET] // @Security Bearer -func (ctrl *V1Controller) HandleLabelsGetAll() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleLabelsGetAll() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { user := services.UseUserCtx(r.Context()) labels, err := ctrl.svc.Labels.GetAll(r.Context(), user.GroupID) if err != nil { log.Err(err).Msg("error getting labels") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, server.Results{Items: labels}) + return server.Respond(w, http.StatusOK, server.Results{Items: labels}) } } @@ -38,24 +38,22 @@ func (ctrl *V1Controller) HandleLabelsGetAll() http.HandlerFunc { // @Success 200 {object} repo.LabelSummary // @Router /v1/labels [POST] // @Security Bearer -func (ctrl *V1Controller) HandleLabelsCreate() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleLabelsCreate() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { createData := repo.LabelCreate{} if err := server.Decode(r, &createData); err != nil { log.Err(err).Msg("error decoding label create data") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } user := services.UseUserCtx(r.Context()) label, err := ctrl.svc.Labels.Create(r.Context(), user.GroupID, createData) if err != nil { log.Err(err).Msg("error creating label") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusCreated, label) + return server.Respond(w, http.StatusCreated, label) } } @@ -67,7 +65,7 @@ func (ctrl *V1Controller) HandleLabelsCreate() http.HandlerFunc { // @Success 204 // @Router /v1/labels/{id} [DELETE] // @Security Bearer -func (ctrl *V1Controller) HandleLabelDelete() http.HandlerFunc { +func (ctrl *V1Controller) HandleLabelDelete() server.HandlerFunc { return ctrl.handleLabelsGeneral() } @@ -79,7 +77,7 @@ func (ctrl *V1Controller) HandleLabelDelete() http.HandlerFunc { // @Success 200 {object} repo.LabelOut // @Router /v1/labels/{id} [GET] // @Security Bearer -func (ctrl *V1Controller) HandleLabelGet() http.HandlerFunc { +func (ctrl *V1Controller) HandleLabelGet() server.HandlerFunc { return ctrl.handleLabelsGeneral() } @@ -91,16 +89,16 @@ func (ctrl *V1Controller) HandleLabelGet() http.HandlerFunc { // @Success 200 {object} repo.LabelOut // @Router /v1/labels/{id} [PUT] // @Security Bearer -func (ctrl *V1Controller) HandleLabelUpdate() http.HandlerFunc { +func (ctrl *V1Controller) HandleLabelUpdate() server.HandlerFunc { return ctrl.handleLabelsGeneral() } -func (ctrl *V1Controller) handleLabelsGeneral() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) handleLabelsGeneral() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { ctx := services.NewContext(r.Context()) - ID, err := ctrl.routeID(w, r) + ID, err := ctrl.routeID(r) if err != nil { - return + return err } switch r.Method { @@ -111,40 +109,37 @@ func (ctrl *V1Controller) handleLabelsGeneral() http.HandlerFunc { log.Err(err). Str("id", ID.String()). Msg("label not found") - server.RespondError(w, http.StatusNotFound, err) - return + return validate.NewRequestError(err, http.StatusNotFound) } log.Err(err).Msg("error getting label") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, labels) + return server.Respond(w, http.StatusOK, labels) case http.MethodDelete: err = ctrl.svc.Labels.Delete(r.Context(), ctx.GID, ID) if err != nil { log.Err(err).Msg("error deleting label") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusNoContent, nil) + return server.Respond(w, http.StatusNoContent, nil) case http.MethodPut: body := repo.LabelUpdate{} if err := server.Decode(r, &body); err != nil { log.Err(err).Msg("error decoding label update data") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } body.ID = ID result, err := ctrl.svc.Labels.Update(r.Context(), ctx.GID, body) if err != nil { log.Err(err).Msg("error updating label") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, result) + return server.Respond(w, http.StatusOK, result) } + + return nil } } diff --git a/backend/app/api/handlers/v1/v1_ctrl_locations.go b/backend/app/api/handlers/v1/v1_ctrl_locations.go index 7a9e525..775cf76 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_locations.go +++ b/backend/app/api/handlers/v1/v1_ctrl_locations.go @@ -6,6 +6,7 @@ import ( "github.com/hay-kot/homebox/backend/ent" "github.com/hay-kot/homebox/backend/internal/repo" "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) @@ -17,17 +18,16 @@ import ( // @Success 200 {object} server.Results{items=[]repo.LocationOutCount} // @Router /v1/locations [GET] // @Security Bearer -func (ctrl *V1Controller) HandleLocationGetAll() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleLocationGetAll() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { user := services.UseUserCtx(r.Context()) locations, err := ctrl.svc.Location.GetAll(r.Context(), user.GroupID) if err != nil { log.Err(err).Msg("failed to get locations") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, server.Results{Items: locations}) + return server.Respond(w, http.StatusOK, server.Results{Items: locations}) } } @@ -39,24 +39,22 @@ func (ctrl *V1Controller) HandleLocationGetAll() http.HandlerFunc { // @Success 200 {object} repo.LocationSummary // @Router /v1/locations [POST] // @Security Bearer -func (ctrl *V1Controller) HandleLocationCreate() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleLocationCreate() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { createData := repo.LocationCreate{} if err := server.Decode(r, &createData); err != nil { log.Err(err).Msg("failed to decode location create data") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } user := services.UseUserCtx(r.Context()) location, err := ctrl.svc.Location.Create(r.Context(), user.GroupID, createData) if err != nil { log.Err(err).Msg("failed to create location") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusCreated, location) + return server.Respond(w, http.StatusCreated, location) } } @@ -68,7 +66,7 @@ func (ctrl *V1Controller) HandleLocationCreate() http.HandlerFunc { // @Success 204 // @Router /v1/locations/{id} [DELETE] // @Security Bearer -func (ctrl *V1Controller) HandleLocationDelete() http.HandlerFunc { +func (ctrl *V1Controller) HandleLocationDelete() server.HandlerFunc { return ctrl.handleLocationGeneral() } @@ -80,7 +78,7 @@ func (ctrl *V1Controller) HandleLocationDelete() http.HandlerFunc { // @Success 200 {object} repo.LocationOut // @Router /v1/locations/{id} [GET] // @Security Bearer -func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc { +func (ctrl *V1Controller) HandleLocationGet() server.HandlerFunc { return ctrl.handleLocationGeneral() } @@ -93,16 +91,16 @@ func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc { // @Success 200 {object} repo.LocationOut // @Router /v1/locations/{id} [PUT] // @Security Bearer -func (ctrl *V1Controller) HandleLocationUpdate() http.HandlerFunc { +func (ctrl *V1Controller) HandleLocationUpdate() server.HandlerFunc { return ctrl.handleLocationGeneral() } -func (ctrl *V1Controller) handleLocationGeneral() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) handleLocationGeneral() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { ctx := services.NewContext(r.Context()) - ID, err := ctrl.routeID(w, r) + ID, err := ctrl.routeID(r) if err != nil { - return + return err } switch r.Method { @@ -115,21 +113,18 @@ func (ctrl *V1Controller) handleLocationGeneral() http.HandlerFunc { if ent.IsNotFound(err) { l.Msg("location not found") - server.RespondError(w, http.StatusNotFound, err) - return + return validate.NewRequestError(err, http.StatusNotFound) } l.Msg("failed to get location") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, location) + return server.Respond(w, http.StatusOK, location) case http.MethodPut: body := repo.LocationUpdate{} if err := server.Decode(r, &body); err != nil { log.Err(err).Msg("failed to decode location update data") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } body.ID = ID @@ -137,18 +132,17 @@ func (ctrl *V1Controller) handleLocationGeneral() http.HandlerFunc { result, err := ctrl.svc.Location.Update(r.Context(), ctx.GID, body) if err != nil { log.Err(err).Msg("failed to update location") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, result) + return server.Respond(w, http.StatusOK, result) case http.MethodDelete: err = ctrl.svc.Location.Delete(r.Context(), ctx.GID, ID) if err != nil { log.Err(err).Msg("failed to delete location") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusNoContent, nil) + return server.Respond(w, http.StatusNoContent, nil) } + return nil } } diff --git a/backend/app/api/handlers/v1/v1_ctrl_user.go b/backend/app/api/handlers/v1/v1_ctrl_user.go index 3b8fd44..b7bf5ee 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_user.go +++ b/backend/app/api/handlers/v1/v1_ctrl_user.go @@ -6,6 +6,7 @@ import ( "github.com/google/uuid" "github.com/hay-kot/homebox/backend/internal/repo" "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" ) @@ -17,29 +18,26 @@ import ( // @Param payload body services.UserRegistration true "User Data" // @Success 204 // @Router /v1/users/register [Post] -func (ctrl *V1Controller) HandleUserRegistration() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleUserRegistration() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { regData := services.UserRegistration{} if err := server.Decode(r, ®Data); err != nil { log.Err(err).Msg("failed to decode user registration data") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } if !ctrl.allowRegistration && regData.GroupToken == "" { - server.RespondError(w, http.StatusForbidden, nil) - return + return validate.NewRequestError(nil, http.StatusForbidden) } _, err := ctrl.svc.User.RegisterUser(r.Context(), regData) if err != nil { log.Err(err).Msg("failed to register user") - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusNoContent, nil) + return server.Respond(w, http.StatusNoContent, nil) } } @@ -50,17 +48,16 @@ func (ctrl *V1Controller) HandleUserRegistration() http.HandlerFunc { // @Success 200 {object} server.Result{item=repo.UserOut} // @Router /v1/users/self [GET] // @Security Bearer -func (ctrl *V1Controller) HandleUserSelf() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleUserSelf() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { token := services.UseTokenCtx(r.Context()) usr, err := ctrl.svc.User.GetSelf(r.Context(), token) if usr.ID == uuid.Nil || err != nil { log.Err(err).Msg("failed to get user") - server.RespondServerError(w) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, server.Wrap(usr)) + return server.Respond(w, http.StatusOK, server.Wrap(usr)) } } @@ -72,24 +69,22 @@ func (ctrl *V1Controller) HandleUserSelf() http.HandlerFunc { // @Success 200 {object} server.Result{item=repo.UserUpdate} // @Router /v1/users/self [PUT] // @Security Bearer -func (ctrl *V1Controller) HandleUserSelfUpdate() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleUserSelfUpdate() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { updateData := repo.UserUpdate{} if err := server.Decode(r, &updateData); err != nil { log.Err(err).Msg("failed to decode user update data") - server.RespondError(w, http.StatusBadRequest, err) - return + return validate.NewRequestError(err, http.StatusBadRequest) } actor := services.UseUserCtx(r.Context()) newData, err := ctrl.svc.User.UpdateSelf(r.Context(), actor.ID, updateData) if err != nil { - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusOK, server.Wrap(newData)) + return server.Respond(w, http.StatusOK, server.Wrap(newData)) } } @@ -100,20 +95,18 @@ func (ctrl *V1Controller) HandleUserSelfUpdate() http.HandlerFunc { // @Success 204 // @Router /v1/users/self [DELETE] // @Security Bearer -func (ctrl *V1Controller) HandleUserSelfDelete() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleUserSelfDelete() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { if ctrl.isDemo { - server.RespondError(w, http.StatusForbidden, nil) - return + return validate.NewRequestError(nil, http.StatusForbidden) } actor := services.UseUserCtx(r.Context()) if err := ctrl.svc.User.DeleteSelf(r.Context(), actor.ID); err != nil { - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusNoContent, nil) + return server.Respond(w, http.StatusNoContent, nil) } } @@ -131,11 +124,10 @@ type ( // @Param payload body ChangePassword true "Password Payload" // @Router /v1/users/change-password [PUT] // @Security Bearer -func (ctrl *V1Controller) HandleUserSelfChangePassword() http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { +func (ctrl *V1Controller) HandleUserSelfChangePassword() server.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) error { if ctrl.isDemo { - server.RespondError(w, http.StatusForbidden, nil) - return + return validate.NewRequestError(nil, http.StatusForbidden) } var cp ChangePassword @@ -148,10 +140,9 @@ func (ctrl *V1Controller) HandleUserSelfChangePassword() http.HandlerFunc { ok := ctrl.svc.User.ChangePassword(ctx, cp.Current, cp.New) if !ok { - server.RespondError(w, http.StatusInternalServerError, err) - return + return validate.NewRequestError(err, http.StatusInternalServerError) } - server.Respond(w, http.StatusNoContent, nil) + return server.Respond(w, http.StatusNoContent, nil) } } diff --git a/backend/app/api/logger.go b/backend/app/api/logger.go index 6756ffc..86085a5 100644 --- a/backend/app/api/logger.go +++ b/backend/app/api/logger.go @@ -15,7 +15,7 @@ func (a *app) setupLogger() { // Logger Init // zerolog.TimeFieldFormat = zerolog.TimeFormatUnix if a.conf.Log.Format != config.LogFormatJSON { - log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}).With().Caller().Logger() } log.Level(getLevel(a.conf.Log.Level)) diff --git a/backend/app/api/main.go b/backend/app/api/main.go index 9cbff98..e48ae04 100644 --- a/backend/app/api/main.go +++ b/backend/app/api/main.go @@ -15,6 +15,7 @@ import ( "github.com/hay-kot/homebox/backend/internal/migrations" "github.com/hay-kot/homebox/backend/internal/repo" "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/web/mid" "github.com/hay-kot/homebox/backend/pkgs/server" _ "github.com/mattn/go-sqlite3" "github.com/rs/zerolog/log" @@ -114,17 +115,25 @@ func run(cfg *config.Config) error { app.services = services.New(app.repos) // ========================================================================= - // Start Server + // Start Server\ + logger := log.With().Caller().Logger() + + mwLogger := mid.Logger(logger) + if app.conf.Mode == config.ModeDevelopment { + mwLogger = mid.SugarLogger(logger) + } + app.server = server.NewServer( server.WithHost(app.conf.Web.Host), server.WithPort(app.conf.Web.Port), + server.WithMiddleware( + mwLogger, + mid.Errors(logger), + mid.Panic(app.conf.Mode == config.ModeDevelopment), + ), ) - routes := app.newRouter(app.repos) - - if app.conf.Mode != config.ModeDevelopment { - app.logRoutes(routes) - } + app.mountRoutes(app.repos) log.Info().Msgf("Starting HTTP Server on %s:%s", app.server.Host, app.server.Port) @@ -163,5 +172,5 @@ func run(cfg *config.Config) error { }() } - return app.server.Start(routes) + return app.server.Start() } diff --git a/backend/app/api/middleware.go b/backend/app/api/middleware.go index 7db65aa..68bfde1 100644 --- a/backend/app/api/middleware.go +++ b/backend/app/api/middleware.go @@ -1,143 +1,34 @@ package main import ( - "fmt" + "errors" "net/http" "strings" - "time" - "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" - "github.com/hay-kot/homebox/backend/internal/config" "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" - "github.com/rs/zerolog/log" ) -func (a *app) setGlobalMiddleware(r *chi.Mux) { - // ========================================================================= - // Middleware - r.Use(middleware.RequestID) - r.Use(middleware.RealIP) - r.Use(mwStripTrailingSlash) - - // Use struct logger in production for requests, but use - // pretty console logger in development. - if a.conf.Mode == config.ModeDevelopment { - r.Use(a.mwSummaryLogger) - } else { - r.Use(a.mwStructLogger) - } - r.Use(middleware.Recoverer) - - // Set a timeout value on the request context (ctx), that will signal - // through ctx.Done() that the request has timed out and further - // processing should be stopped. - r.Use(middleware.Timeout(60 * time.Second)) -} - // mwAuthToken is a middleware that will check the database for a stateful token // and attach it to the request context with the user, or return a 401 if it doesn't exist. -func (a *app) mwAuthToken(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +func (a *app) mwAuthToken(next server.Handler) server.Handler { + return server.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { requestToken := r.Header.Get("Authorization") if requestToken == "" { - server.RespondUnauthorized(w) - return + return validate.NewRequestError(errors.New("Authorization header is required"), http.StatusUnauthorized) } requestToken = strings.TrimPrefix(requestToken, "Bearer ") usr, err := a.services.User.GetSelf(r.Context(), requestToken) // Check the database for the token - if err != nil { - server.RespondUnauthorized(w) - return + return validate.NewRequestError(errors.New("Authorization header is required"), http.StatusUnauthorized) } r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken)) - - next.ServeHTTP(w, r) - }) -} - -// mqStripTrailingSlash is a middleware that will strip trailing slashes from the request path. -func mwStripTrailingSlash(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - r.URL.Path = strings.TrimSuffix(r.URL.Path, "/") - next.ServeHTTP(w, r) - }) -} - -type StatusRecorder struct { - http.ResponseWriter - Status int -} - -func (r *StatusRecorder) WriteHeader(status int) { - r.Status = status - r.ResponseWriter.WriteHeader(status) -} - -func (a *app) mwStructLogger(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - record := &StatusRecorder{ResponseWriter: w, Status: http.StatusOK} - next.ServeHTTP(record, r) - - scheme := "http" - if r.TLS != nil { - scheme = "https" - } - - url := fmt.Sprintf("%s://%s%s %s", scheme, r.Host, r.RequestURI, r.Proto) - - log.Info(). - Str("id", middleware.GetReqID(r.Context())). - Str("method", r.Method). - Str("remote_addr", r.RemoteAddr). - Int("status", record.Status). - Msg(url) - }) -} - -func (a *app) mwSummaryLogger(next http.Handler) http.Handler { - bold := func(s string) string { return "\033[1m" + s + "\033[0m" } - orange := func(s string) string { return "\033[33m" + s + "\033[0m" } - aqua := func(s string) string { return "\033[36m" + s + "\033[0m" } - red := func(s string) string { return "\033[31m" + s + "\033[0m" } - green := func(s string) string { return "\033[32m" + s + "\033[0m" } - - fmtCode := func(code int) string { - switch { - case code >= 500: - return red(fmt.Sprintf("%d", code)) - case code >= 400: - return orange(fmt.Sprintf("%d", code)) - case code >= 300: - return aqua(fmt.Sprintf("%d", code)) - default: - return green(fmt.Sprintf("%d", code)) - } - } - - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - record := &StatusRecorder{ResponseWriter: w, Status: http.StatusOK} - next.ServeHTTP(record, r) // Blocks until the next handler returns. - - scheme := "http" - if r.TLS != nil { - scheme = "https" - } - - url := fmt.Sprintf("%s://%s%s %s", scheme, r.Host, r.RequestURI, r.Proto) - - log.Info(). - Msgf("%s %s %s", - bold(orange(""+r.Method+"")), - aqua(url), - bold(fmtCode(record.Status)), - ) + return next.ServeHTTP(w, r) }) } diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index f5d887a..02a7f74 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -10,11 +10,11 @@ import ( "path" "path/filepath" - "github.com/go-chi/chi/v5" "github.com/hay-kot/homebox/backend/app/api/handlers/debughandlers" v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1" _ "github.com/hay-kot/homebox/backend/app/api/static/docs" "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/pkgs/server" httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware ) @@ -35,101 +35,76 @@ func (a *app) debugRouter() *http.ServeMux { } // registerRoutes registers all the routes for the API -func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux { +func (a *app) mountRoutes(repos *repo.AllRepos) { registerMimes() - r := chi.NewRouter() - a.setGlobalMiddleware(r) - - r.Get("/swagger/*", httpSwagger.Handler( + a.server.Get("/swagger/*", server.ToHandler(httpSwagger.Handler( httpSwagger.URL(fmt.Sprintf("%s://%s/swagger/doc.json", a.conf.Swagger.Scheme, a.conf.Swagger.Host)), - )) + ))) // ========================================================================= // API Version 1 v1Base := v1.BaseUrlFunc(prefix) - v1Ctrl := v1.NewControllerV1(a.services, + + v1Ctrl := v1.NewControllerV1( + a.services, v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize), v1.WithRegistration(a.conf.AllowRegistration), v1.WithDemoStatus(a.conf.Demo), // Disable Password Change in Demo Mode ) - r.Get(v1Base("/status"), v1Ctrl.HandleBase(func() bool { return true }, v1.Build{ + + a.server.Get(v1Base("/status"), v1Ctrl.HandleBase(func() bool { return true }, v1.Build{ Version: version, Commit: commit, BuildTime: buildTime, })) - r.Post(v1Base("/users/register"), v1Ctrl.HandleUserRegistration()) - r.Post(v1Base("/users/login"), v1Ctrl.HandleAuthLogin()) + a.server.Post(v1Base("/users/register"), v1Ctrl.HandleUserRegistration()) + a.server.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()) + a.server.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()) - r.Put(v1Base("/users/self"), v1Ctrl.HandleUserSelfUpdate()) - r.Delete(v1Base("/users/self"), v1Ctrl.HandleUserSelfDelete()) - r.Post(v1Base("/users/logout"), v1Ctrl.HandleAuthLogout()) - r.Get(v1Base("/users/refresh"), v1Ctrl.HandleAuthRefresh()) - r.Put(v1Base("/users/self/change-password"), v1Ctrl.HandleUserSelfChangePassword()) + a.server.Get(v1Base("/users/self"), v1Ctrl.HandleUserSelf(), a.mwAuthToken) + a.server.Put(v1Base("/users/self"), v1Ctrl.HandleUserSelfUpdate(), a.mwAuthToken) + a.server.Delete(v1Base("/users/self"), v1Ctrl.HandleUserSelfDelete(), a.mwAuthToken) + a.server.Post(v1Base("/users/logout"), v1Ctrl.HandleAuthLogout(), a.mwAuthToken) + a.server.Get(v1Base("/users/refresh"), v1Ctrl.HandleAuthRefresh(), a.mwAuthToken) + a.server.Put(v1Base("/users/self/change-password"), v1Ctrl.HandleUserSelfChangePassword(), a.mwAuthToken) - r.Post(v1Base("/groups/invitations"), v1Ctrl.HandleGroupInvitationsCreate()) + a.server.Post(v1Base("/groups/invitations"), v1Ctrl.HandleGroupInvitationsCreate(), a.mwAuthToken) - // TODO: I don't like /groups being the URL for users - r.Get(v1Base("/groups"), v1Ctrl.HandleGroupGet()) - r.Put(v1Base("/groups"), v1Ctrl.HandleGroupUpdate()) + // TODO: I don't like /groups being the URL for users + a.server.Get(v1Base("/groups"), v1Ctrl.HandleGroupGet(), a.mwAuthToken) + a.server.Put(v1Base("/groups"), v1Ctrl.HandleGroupUpdate(), a.mwAuthToken) - r.Get(v1Base("/locations"), v1Ctrl.HandleLocationGetAll()) - r.Post(v1Base("/locations"), v1Ctrl.HandleLocationCreate()) - r.Get(v1Base("/locations/{id}"), v1Ctrl.HandleLocationGet()) - r.Put(v1Base("/locations/{id}"), v1Ctrl.HandleLocationUpdate()) - r.Delete(v1Base("/locations/{id}"), v1Ctrl.HandleLocationDelete()) + a.server.Get(v1Base("/locations"), v1Ctrl.HandleLocationGetAll(), a.mwAuthToken) + a.server.Post(v1Base("/locations"), v1Ctrl.HandleLocationCreate(), a.mwAuthToken) + a.server.Get(v1Base("/locations/{id}"), v1Ctrl.HandleLocationGet(), a.mwAuthToken) + a.server.Put(v1Base("/locations/{id}"), v1Ctrl.HandleLocationUpdate(), a.mwAuthToken) + a.server.Delete(v1Base("/locations/{id}"), v1Ctrl.HandleLocationDelete(), a.mwAuthToken) - r.Get(v1Base("/labels"), v1Ctrl.HandleLabelsGetAll()) - r.Post(v1Base("/labels"), v1Ctrl.HandleLabelsCreate()) - r.Get(v1Base("/labels/{id}"), v1Ctrl.HandleLabelGet()) - r.Put(v1Base("/labels/{id}"), v1Ctrl.HandleLabelUpdate()) - r.Delete(v1Base("/labels/{id}"), v1Ctrl.HandleLabelDelete()) + a.server.Get(v1Base("/labels"), v1Ctrl.HandleLabelsGetAll(), a.mwAuthToken) + a.server.Post(v1Base("/labels"), v1Ctrl.HandleLabelsCreate(), a.mwAuthToken) + a.server.Get(v1Base("/labels/{id}"), v1Ctrl.HandleLabelGet(), a.mwAuthToken) + a.server.Put(v1Base("/labels/{id}"), v1Ctrl.HandleLabelUpdate(), a.mwAuthToken) + a.server.Delete(v1Base("/labels/{id}"), v1Ctrl.HandleLabelDelete(), a.mwAuthToken) - r.Get(v1Base("/items"), v1Ctrl.HandleItemsGetAll()) - r.Post(v1Base("/items/import"), v1Ctrl.HandleItemsImport()) - r.Post(v1Base("/items"), v1Ctrl.HandleItemsCreate()) - r.Get(v1Base("/items/{id}"), v1Ctrl.HandleItemGet()) - r.Put(v1Base("/items/{id}"), v1Ctrl.HandleItemUpdate()) - r.Delete(v1Base("/items/{id}"), v1Ctrl.HandleItemDelete()) + a.server.Get(v1Base("/items"), v1Ctrl.HandleItemsGetAll(), a.mwAuthToken) + a.server.Post(v1Base("/items/import"), v1Ctrl.HandleItemsImport(), a.mwAuthToken) + a.server.Post(v1Base("/items"), v1Ctrl.HandleItemsCreate(), a.mwAuthToken) + a.server.Get(v1Base("/items/{id}"), v1Ctrl.HandleItemGet(), a.mwAuthToken) + a.server.Put(v1Base("/items/{id}"), v1Ctrl.HandleItemUpdate(), a.mwAuthToken) + a.server.Delete(v1Base("/items/{id}"), v1Ctrl.HandleItemDelete(), a.mwAuthToken) - 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()) - }) + a.server.Post(v1Base("/items/{id}/attachments"), v1Ctrl.HandleItemAttachmentCreate(), a.mwAuthToken) + a.server.Get(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentToken(), a.mwAuthToken) + a.server.Put(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentUpdate(), a.mwAuthToken) + a.server.Delete(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentDelete(), a.mwAuthToken) - r.NotFound(notFoundHandler()) - return r -} - -// logRoutes logs the routes of the server that are registered within Server.registerRoutes(). This is useful for debugging. -// See https://github.com/go-chi/chi/issues/332 for details and inspiration. -func (a *app) logRoutes(r *chi.Mux) { - desiredSpaces := 10 - - walkFunc := func(method string, route string, handler http.Handler, middleware ...func(http.Handler) http.Handler) error { - text := "[" + method + "]" - - for len(text) < desiredSpaces { - text = text + " " - } - - fmt.Printf("Registered Route: %s%s\n", text, route) - return nil - } - - if err := chi.Walk(r, walkFunc); err != nil { - fmt.Printf("Logging err: %s\n", err.Error()) - } + a.server.NotFound(notFoundHandler()) } func registerMimes() { @@ -146,7 +121,7 @@ func registerMimes() { // notFoundHandler perform the main logic around handling the internal SPA embed and ensuring that // the client side routing is handled correctly. -func notFoundHandler() http.HandlerFunc { +func notFoundHandler() server.HandlerFunc { tryRead := func(fs embed.FS, prefix, requestedPath string, w http.ResponseWriter) error { f, err := fs.Open(path.Join(prefix, requestedPath)) if err != nil { @@ -165,14 +140,16 @@ func notFoundHandler() http.HandlerFunc { return err } - return func(w http.ResponseWriter, r *http.Request) { + return func(w http.ResponseWriter, r *http.Request) error { err := tryRead(public, "static/public", r.URL.Path, w) - if err == nil { - return - } - err = tryRead(public, "static/public", "index.html", w) if err != nil { - panic(err) + // Fallback to the index.html file. + // should succeed in all cases. + err = tryRead(public, "static/public", "index.html", w) + if err != nil { + return err + } } + return nil } } diff --git a/backend/app/api/static/docs/docs.go b/backend/app/api/static/docs/docs.go index 2bd7e41..7cad594 100644 --- a/backend/app/api/static/docs/docs.go +++ b/backend/app/api/static/docs/docs.go @@ -395,10 +395,7 @@ const docTemplate = `{ "422": { "description": "Unprocessable Entity", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/server.ValidationError" - } + "$ref": "#/definitions/server.ErrorResponse" } } } @@ -1735,6 +1732,20 @@ const docTemplate = `{ } } }, + "server.ErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "fields": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, "server.Result": { "type": "object", "properties": { @@ -1754,17 +1765,6 @@ const docTemplate = `{ "items": {} } }, - "server.ValidationError": { - "type": "object", - "properties": { - "field": { - "type": "string" - }, - "reason": { - "type": "string" - } - } - }, "services.UserRegistration": { "type": "object", "properties": { diff --git a/backend/app/api/static/docs/swagger.json b/backend/app/api/static/docs/swagger.json index 139990c..b5e97e8 100644 --- a/backend/app/api/static/docs/swagger.json +++ b/backend/app/api/static/docs/swagger.json @@ -387,10 +387,7 @@ "422": { "description": "Unprocessable Entity", "schema": { - "type": "array", - "items": { - "$ref": "#/definitions/server.ValidationError" - } + "$ref": "#/definitions/server.ErrorResponse" } } } @@ -1727,6 +1724,20 @@ } } }, + "server.ErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "string" + }, + "fields": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, "server.Result": { "type": "object", "properties": { @@ -1746,17 +1757,6 @@ "items": {} } }, - "server.ValidationError": { - "type": "object", - "properties": { - "field": { - "type": "string" - }, - "reason": { - "type": "string" - } - } - }, "services.UserRegistration": { "type": "object", "properties": { diff --git a/backend/app/api/static/docs/swagger.yaml b/backend/app/api/static/docs/swagger.yaml index bda3d97..d2cf02a 100644 --- a/backend/app/api/static/docs/swagger.yaml +++ b/backend/app/api/static/docs/swagger.yaml @@ -394,6 +394,15 @@ definitions: name: type: string type: object + server.ErrorResponse: + properties: + error: + type: string + fields: + additionalProperties: + type: string + type: object + type: object server.Result: properties: details: {} @@ -407,13 +416,6 @@ definitions: properties: items: {} type: object - server.ValidationError: - properties: - field: - type: string - reason: - type: string - type: object services.UserRegistration: properties: email: @@ -708,9 +710,7 @@ paths: "422": description: Unprocessable Entity schema: - items: - $ref: '#/definitions/server.ValidationError' - type: array + $ref: '#/definitions/server.ErrorResponse' security: - Bearer: [] summary: imports items into the database diff --git a/backend/internal/sys/validate/errors.go b/backend/internal/sys/validate/errors.go new file mode 100644 index 0000000..d08a448 --- /dev/null +++ b/backend/internal/sys/validate/errors.go @@ -0,0 +1,119 @@ +package validate + +import ( + "encoding/json" + "errors" +) + +type UnauthorizedError struct { +} + +func (err *UnauthorizedError) Error() string { + return "unauthorized" +} + +func IsUnauthorizedError(err error) bool { + var re *UnauthorizedError + return errors.As(err, &re) +} + +func NewUnauthorizedError() error { + return &UnauthorizedError{} +} + +type InvalidRouteKeyError struct { + key string +} + +func (err *InvalidRouteKeyError) Error() string { + return "invalid route key: " + err.key +} + +func NewInvalidRouteKeyError(key string) error { + return &InvalidRouteKeyError{key} +} + +func IsInvalidRouteKeyError(err error) bool { + var re *InvalidRouteKeyError + return errors.As(err, &re) +} + +// ErrorResponse is the form used for API responses from failures in the API. +type ErrorResponse struct { + Error string `json:"error"` + Fields string `json:"fields,omitempty"` +} + +// RequestError is used to pass an error during the request through the +// application with web specific context. +type RequestError struct { + Err error + Status int + Fields error +} + +// NewRequestError wraps a provided error with an HTTP status code. This +// function should be used when handlers encounter expected errors. +func NewRequestError(err error, status int) error { + return &RequestError{err, status, nil} +} + +func (err *RequestError) Error() string { + return err.Err.Error() +} + +// IsRequestError checks if an error of type RequestError exists. +func IsRequestError(err error) bool { + var re *RequestError + return errors.As(err, &re) +} + +// FieldError is used to indicate an error with a specific request field. +type FieldError struct { + Field string `json:"field"` + Error string `json:"error"` +} + +// FieldErrors represents a collection of field errors. +type FieldErrors []FieldError + +func (fe FieldErrors) Append(field, reason string) FieldErrors { + return append(fe, FieldError{ + Field: field, + Error: reason, + }) +} + +func (fe FieldErrors) Nil() bool { + return len(fe) == 0 +} + +// Error implments the error interface. +func (fe FieldErrors) Error() string { + d, err := json.Marshal(fe) + if err != nil { + return err.Error() + } + return string(d) +} + +func NewFieldErrors(errs ...FieldError) FieldErrors { + return errs +} + +func IsFieldError(err error) bool { + v := FieldErrors{} + return errors.As(err, &v) +} + +// Cause iterates through all the wrapped errors until the root +// error value is reached. +func Cause(err error) error { + root := err + for { + if err = errors.Unwrap(root); err == nil { + return root + } + root = err + } +} diff --git a/backend/internal/web/mid/errors.go b/backend/internal/web/mid/errors.go new file mode 100644 index 0000000..0802a11 --- /dev/null +++ b/backend/internal/web/mid/errors.go @@ -0,0 +1,70 @@ +package mid + +import ( + "net/http" + + "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/sys/validate" + "github.com/hay-kot/homebox/backend/pkgs/server" + "github.com/rs/zerolog" +) + +func Errors(log zerolog.Logger) server.Middleware { + return func(h server.Handler) server.Handler { + return server.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { + err := h.ServeHTTP(w, r) + + if err != nil { + var resp server.ErrorResponse + var code int + + log.Err(err). + Str("trace_id", server.GetTraceID(r.Context())). + Msg("ERROR occurred") + + switch { + case validate.IsUnauthorizedError(err): + code = http.StatusUnauthorized + resp = server.ErrorResponse{ + Error: "unauthorized", + } + case validate.IsInvalidRouteKeyError(err): + code = http.StatusBadRequest + resp = server.ErrorResponse{ + Error: err.Error(), + } + case validate.IsFieldError(err): + fieldErrors := err.(validate.FieldErrors) + resp.Error = "Validation Error" + resp.Fields = map[string]string{} + + for _, fieldError := range fieldErrors { + resp.Fields[fieldError.Field] = fieldError.Error + } + case validate.IsRequestError(err): + requestError := err.(*validate.RequestError) + resp.Error = requestError.Error() + code = requestError.Status + case ent.IsNotFound(err): + resp.Error = "Not Found" + code = http.StatusNotFound + default: + resp.Error = "Unknown Error" + code = http.StatusInternalServerError + + } + + if err := server.Respond(w, code, resp); err != nil { + return err + } + + // If Showdown error, return error + if server.IsShutdownError(err) { + return err + } + } + + return nil + }) + } +} diff --git a/backend/internal/web/mid/logger.go b/backend/internal/web/mid/logger.go new file mode 100644 index 0000000..86b8cdb --- /dev/null +++ b/backend/internal/web/mid/logger.go @@ -0,0 +1,97 @@ +package mid + +import ( + "fmt" + "net/http" + + "github.com/hay-kot/homebox/backend/pkgs/server" + "github.com/rs/zerolog" +) + +type statusRecorder struct { + http.ResponseWriter + Status int +} + +func (r *statusRecorder) WriteHeader(status int) { + r.Status = status + r.ResponseWriter.WriteHeader(status) +} + +func Logger(log zerolog.Logger) server.Middleware { + return func(next server.Handler) server.Handler { + return server.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { + traceId := server.GetTraceID(r.Context()) + + log.Info(). + Str("trace_id", traceId). + Str("method", r.Method). + Str("path", r.URL.Path). + Str("remove_address", r.RemoteAddr). + Msg("request started") + + record := &statusRecorder{ResponseWriter: w, Status: http.StatusOK} + + err := next.ServeHTTP(record, r) + + log.Info(). + Str("trace_id", traceId). + Str("method", r.Method). + Str("url", r.URL.Path). + Str("remote_address", r.RemoteAddr). + Int("status_code", record.Status). + Msg("request completed") + + return err + }) + } +} + +func SugarLogger(log zerolog.Logger) server.Middleware { + orange := func(s string) string { return "\033[33m" + s + "\033[0m" } + aqua := func(s string) string { return "\033[36m" + s + "\033[0m" } + red := func(s string) string { return "\033[31m" + s + "\033[0m" } + green := func(s string) string { return "\033[32m" + s + "\033[0m" } + + fmtCode := func(code int) string { + switch { + case code >= 500: + return red(fmt.Sprintf("%d", code)) + case code >= 400: + return orange(fmt.Sprintf("%d", code)) + case code >= 300: + return aqua(fmt.Sprintf("%d", code)) + default: + return green(fmt.Sprintf("%d", code)) + } + } + bold := func(s string) string { return "\033[1m" + s + "\033[0m" } + + atLeast6 := func(s string) string { + for len(s) <= 6 { + s += " " + } + return s + } + + return func(next server.Handler) server.Handler { + return server.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { + + record := &statusRecorder{ResponseWriter: w, Status: http.StatusOK} + + err := next.ServeHTTP(record, r) // Blocks until the next handler returns. + + url := fmt.Sprintf("%s %s", r.RequestURI, r.Proto) + + log.Info(). + Str("trace_id", server.GetTraceID(r.Context())). + Msgf("%s %s %s", + bold(fmtCode(record.Status)), + bold(orange(atLeast6(r.Method))), + aqua(url), + ) + + return err + }) + } +} diff --git a/backend/internal/web/mid/panic.go b/backend/internal/web/mid/panic.go new file mode 100644 index 0000000..9879bb8 --- /dev/null +++ b/backend/internal/web/mid/panic.go @@ -0,0 +1,33 @@ +package mid + +import ( + "fmt" + "net/http" + "runtime/debug" + + "github.com/hay-kot/homebox/backend/pkgs/server" +) + +// Panic is a middleware that recovers from panics anywhere in the chain and wraps the error. +// and returns it up the middleware chain. +func Panic(develop bool) server.Middleware { + return func(h server.Handler) server.Handler { + return server.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (err error) { + defer func() { + if rec := recover(); rec != nil { + trace := debug.Stack() + + if develop { + err = fmt.Errorf("PANIC [%v]", rec) + fmt.Printf("%s", string(trace)) + } else { + err = fmt.Errorf("PANIC [%v] TRACE[%s]", rec, string(trace)) + } + + } + }() + + return h.ServeHTTP(w, r) + }) + } +} diff --git a/backend/pkgs/server/errors.go b/backend/pkgs/server/errors.go new file mode 100644 index 0000000..5b1d60b --- /dev/null +++ b/backend/pkgs/server/errors.go @@ -0,0 +1,23 @@ +package server + +import "errors" + +type shutdownError struct { + message string +} + +func (e *shutdownError) Error() string { + return e.message +} + +// ShutdownError returns an error that indicates that the server has lost +// integrity and should be shut down. +func ShutdownError(message string) error { + return &shutdownError{message} +} + +// IsShutdownError returns true if the error is a shutdown error. +func IsShutdownError(err error) bool { + var e *shutdownError + return errors.As(err, &e) +} diff --git a/backend/pkgs/server/handler.go b/backend/pkgs/server/handler.go new file mode 100644 index 0000000..76ae131 --- /dev/null +++ b/backend/pkgs/server/handler.go @@ -0,0 +1,25 @@ +package server + +import ( + "net/http" +) + +type HandlerFunc func(w http.ResponseWriter, r *http.Request) error + +func (f HandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request) error { + return f(w, r) +} + +type Handler interface { + ServeHTTP(http.ResponseWriter, *http.Request) error +} + +// ToHandler converts a function to a customer implementation of the Handler interface. +// that returns an error. This wrapper around the handler function and simply +// returns the nil in all cases +func ToHandler(handler http.Handler) Handler { + return HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { + handler.ServeHTTP(w, r) + return nil + }) +} diff --git a/backend/pkgs/server/middleware.go b/backend/pkgs/server/middleware.go new file mode 100644 index 0000000..f24f06b --- /dev/null +++ b/backend/pkgs/server/middleware.go @@ -0,0 +1,38 @@ +package server + +import ( + "net/http" + "strings" +) + +type Middleware func(Handler) Handler + +// wrapMiddleware creates a new handler by wrapping middleware around a final +// handler. The middlewares' Handlers will be executed by requests in the order +// they are provided. +func wrapMiddleware(mw []Middleware, handler Handler) Handler { + + // Loop backwards through the middleware invoking each one. Replace the + // handler with the new wrapped handler. Looping backwards ensures that the + // first middleware of the slice is the first to be executed by requests. + for i := len(mw) - 1; i >= 0; i-- { + h := mw[i] + if h != nil { + handler = h(handler) + } + } + + return handler +} + +// StripTrailingSlash is a middleware that will strip trailing slashes from the request path. +// +// Example: /api/v1/ -> /api/v1 +func StripTrailingSlash() Middleware { + return func(h Handler) Handler { + return HandlerFunc(func(w http.ResponseWriter, r *http.Request) error { + r.URL.Path = strings.TrimSuffix(r.URL.Path, "/") + return h.ServeHTTP(w, r) + }) + } +} diff --git a/backend/pkgs/server/mux.go b/backend/pkgs/server/mux.go new file mode 100644 index 0000000..9e77e32 --- /dev/null +++ b/backend/pkgs/server/mux.go @@ -0,0 +1,103 @@ +package server + +import ( + "context" + "net/http" + + "github.com/google/uuid" +) + +type vkey int + +const ( + // Key is the key for the server in the request context. + key vkey = 1 +) + +type Values struct { + TraceID string +} + +func GetTraceID(ctx context.Context) string { + v, ok := ctx.Value(key).(Values) + if !ok { + return "" + } + return v.TraceID +} + +func (s *Server) toHttpHandler(handler Handler, mw ...Middleware) http.HandlerFunc { + handler = wrapMiddleware(mw, handler) + + handler = wrapMiddleware(s.mw, handler) + + return func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + // Add the trace ID to the context + ctx = context.WithValue(ctx, key, Values{ + TraceID: uuid.NewString(), + }) + + err := handler.ServeHTTP(w, r.WithContext(ctx)) + + if err != nil { + if IsShutdownError(err) { + _ = s.Shutdown("SIGTERM") + } + } + } +} + +func (s *Server) handle(method, pattern string, handler Handler, mw ...Middleware) { + h := s.toHttpHandler(handler, mw...) + + switch method { + case http.MethodGet: + s.mux.Get(pattern, h) + case http.MethodPost: + s.mux.Post(pattern, h) + case http.MethodPut: + s.mux.Put(pattern, h) + case http.MethodDelete: + s.mux.Delete(pattern, h) + case http.MethodPatch: + s.mux.Patch(pattern, h) + case http.MethodHead: + s.mux.Head(pattern, h) + case http.MethodOptions: + s.mux.Options(pattern, h) + } +} + +func (s *Server) Get(pattern string, handler Handler, mw ...Middleware) { + s.handle(http.MethodGet, pattern, handler, mw...) +} + +func (s *Server) Post(pattern string, handler Handler, mw ...Middleware) { + s.handle(http.MethodPost, pattern, handler, mw...) +} + +func (s *Server) Put(pattern string, handler Handler, mw ...Middleware) { + s.handle(http.MethodPut, pattern, handler, mw...) +} + +func (s *Server) Delete(pattern string, handler Handler, mw ...Middleware) { + s.handle(http.MethodDelete, pattern, handler, mw...) +} + +func (s *Server) Patch(pattern string, handler Handler, mw ...Middleware) { + s.handle(http.MethodPatch, pattern, handler, mw...) +} + +func (s *Server) Head(pattern string, handler Handler, mw ...Middleware) { + s.handle(http.MethodHead, pattern, handler, mw...) +} + +func (s *Server) Options(pattern string, handler Handler, mw ...Middleware) { + s.handle(http.MethodOptions, pattern, handler, mw...) +} + +func (s *Server) NotFound(handler Handler) { + s.mux.NotFound(s.toHttpHandler(handler)) +} diff --git a/backend/pkgs/server/request.go b/backend/pkgs/server/request.go index ffb76d1..38c3189 100644 --- a/backend/pkgs/server/request.go +++ b/backend/pkgs/server/request.go @@ -16,7 +16,7 @@ func Decode(r *http.Request, val interface{}) error { return nil } -// GetId is a shotcut to get the id from the request URL or return a default value +// GetId is a shortcut to get the id from the request URL or return a default value func GetParam(r *http.Request, key, d string) string { val := r.URL.Query().Get(key) @@ -27,22 +27,22 @@ func GetParam(r *http.Request, key, d string) string { return val } -// GetSkip is a shotcut to get the skip from the request URL parameters +// GetSkip is a shortcut to get the skip from the request URL parameters func GetSkip(r *http.Request, d string) string { return GetParam(r, "skip", d) } -// GetSkip is a shotcut to get the skip from the request URL parameters +// GetSkip is a shortcut to get the skip from the request URL parameters func GetId(r *http.Request, d string) string { return GetParam(r, "id", d) } -// GetLimit is a shotcut to get the limit from the request URL parameters +// GetLimit is a shortcut to get the limit from the request URL parameters func GetLimit(r *http.Request, d string) string { return GetParam(r, "limit", d) } -// GetQuery is a shotcut to get the sort from the request URL parameters +// GetQuery is a shortcut to get the sort from the request URL parameters func GetQuery(r *http.Request, d string) string { return GetParam(r, "query", d) } diff --git a/backend/pkgs/server/response.go b/backend/pkgs/server/response.go index cf14dd2..7d5880e 100644 --- a/backend/pkgs/server/response.go +++ b/backend/pkgs/server/response.go @@ -2,16 +2,20 @@ package server import ( "encoding/json" - "errors" "net/http" ) +type ErrorResponse struct { + Error string `json:"error"` + Fields map[string]string `json:"fields,omitempty"` +} + // Respond converts a Go value to JSON and sends it to the client. // Adapted from https://github.com/ardanlabs/service/tree/master/foundation/web -func Respond(w http.ResponseWriter, statusCode int, data interface{}) { +func Respond(w http.ResponseWriter, statusCode int, data interface{}) error { if statusCode == http.StatusNoContent { w.WriteHeader(statusCode) - return + return nil } // Convert the response value to JSON. @@ -28,31 +32,8 @@ func Respond(w http.ResponseWriter, statusCode int, data interface{}) { // Send the result back to the client. if _, err := w.Write(jsonData); err != nil { - panic(err) + return err } -} -// ResponseError is a helper function that sends a JSON response of an error message -func RespondError(w http.ResponseWriter, statusCode int, err error) { - eb := ErrorBuilder{} - eb.AddError(err) - eb.Respond(w, statusCode) -} - -// RespondServerError is a wrapper around RespondError that sends a 500 internal server error. Useful for -// Sending generic errors when everything went wrong. -func RespondServerError(w http.ResponseWriter) { - RespondError(w, http.StatusInternalServerError, errors.New("internal server error")) -} - -// RespondNotFound is a helper utility for responding with a generic -// "unauthorized" error. -func RespondUnauthorized(w http.ResponseWriter) { - RespondError(w, http.StatusUnauthorized, errors.New("unauthorized")) -} - -// RespondForbidden is a helper utility for responding with a generic -// "forbidden" error. -func RespondForbidden(w http.ResponseWriter) { - RespondError(w, http.StatusForbidden, errors.New("forbidden")) + return nil } diff --git a/backend/pkgs/server/response_error_builder.go b/backend/pkgs/server/response_error_builder.go deleted file mode 100644 index 4c6d80f..0000000 --- a/backend/pkgs/server/response_error_builder.go +++ /dev/null @@ -1,76 +0,0 @@ -package server - -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 -// } -type ErrorBuilder struct { - errs []string -} - -// HasErrors returns true if the ErrorBuilder has any errors. -func (eb *ErrorBuilder) HasErrors() bool { - if (eb.errs == nil) || (len(eb.errs) == 0) { - return false - } - return true -} - -// AddError adds an error to the ErrorBuilder if an error is not nil. If the -// Error is nil, then nothing is added. -func (eb *ErrorBuilder) AddError(err error) { - if err != nil { - if eb.errs == nil { - eb.errs = make([]string, 0) - } - - eb.errs = append(eb.errs, err.Error()) - } -} - -// Respond sends a JSON response with the ErrorBuilder's errors. If there are no errors, then -// the errors field will be an empty array. -func (eb *ErrorBuilder) Respond(w http.ResponseWriter, statusCode int) { - Respond(w, statusCode, Wrap(nil).AddError(http.StatusText(statusCode), eb.errs)) -} diff --git a/backend/pkgs/server/response_error_builder_test.go b/backend/pkgs/server/response_error_builder_test.go deleted file mode 100644 index 689faaa..0000000 --- a/backend/pkgs/server/response_error_builder_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package server - -import ( - "encoding/json" - "errors" - "net/http" - "net/http/httptest" - "testing" - - "github.com/hay-kot/homebox/backend/pkgs/faker" - "github.com/stretchr/testify/assert" -) - -func Test_ErrorBuilder_HasErrors_NilList(t *testing.T) { - t.Parallel() - - var ebNilList = ErrorBuilder{} - assert.False(t, ebNilList.HasErrors(), "ErrorBuilder.HasErrors() should return false when list is nil") - -} - -func Test_ErrorBuilder_HasErrors_EmptyList(t *testing.T) { - t.Parallel() - - var ebEmptyList = ErrorBuilder{ - errs: []string{}, - } - assert.False(t, ebEmptyList.HasErrors(), "ErrorBuilder.HasErrors() should return false when list is empty") - -} - -func Test_ErrorBuilder_HasErrors_WithError(t *testing.T) { - t.Parallel() - - var ebList = ErrorBuilder{} - ebList.AddError(errors.New("test error")) - - assert.True(t, ebList.HasErrors(), "ErrorBuilder.HasErrors() should return true when list is not empty") - -} - -func Test_ErrorBuilder_AddError(t *testing.T) { - t.Parallel() - - randomError := make([]error, 10) - - f := faker.NewFaker() - - errorStrings := make([]string, 10) - - for i := 0; i < 10; i++ { - err := errors.New(f.Str(10)) - randomError[i] = err - errorStrings[i] = err.Error() - } - - // Check Results - var ebList = ErrorBuilder{} - - for _, err := range randomError { - ebList.AddError(err) - } - - assert.Equal(t, errorStrings, ebList.errs, "ErrorBuilder.AddError() should add an error to the list") -} - -func Test_ErrorBuilder_Respond(t *testing.T) { - t.Parallel() - - f := faker.NewFaker() - - randomError := make([]error, 5) - - for i := 0; i < 5; i++ { - err := errors.New(f.Str(5)) - randomError[i] = err - } - - // Check Results - var ebList = ErrorBuilder{} - - for _, err := range randomError { - ebList.AddError(err) - } - - fakeWriter := httptest.NewRecorder() - - ebList.Respond(fakeWriter, 422) - - assert.Equal(t, 422, fakeWriter.Code, "ErrorBuilder.Respond() should return a status code of 422") - - // Check errors payload is correct - - errorsStruct := struct { - Errors []string `json:"details"` - Message string `json:"message"` - Error bool `json:"error"` - }{ - Errors: ebList.errs, - Message: http.StatusText(http.StatusUnprocessableEntity), - Error: true, - } - - asJson, _ := json.Marshal(errorsStruct) - assert.JSONEq(t, string(asJson), fakeWriter.Body.String(), "ErrorBuilder.Respond() should return a JSON response with the errors") - -} diff --git a/backend/pkgs/server/response_test.go b/backend/pkgs/server/response_test.go index a6446d3..ef23d60 100644 --- a/backend/pkgs/server/response_test.go +++ b/backend/pkgs/server/response_test.go @@ -1,7 +1,6 @@ package server import ( - "errors" "net/http" "net/http/httptest" "testing" @@ -17,7 +16,8 @@ func Test_Respond_NoContent(t *testing.T) { Name: "dummy", } - Respond(recorder, http.StatusNoContent, dummystruct) + err := Respond(recorder, http.StatusNoContent, dummystruct) + assert.NoError(t, err) assert.Equal(t, http.StatusNoContent, recorder.Code) assert.Empty(t, recorder.Body.String()) @@ -31,48 +31,11 @@ func Test_Respond_JSON(t *testing.T) { Name: "dummy", } - Respond(recorder, http.StatusCreated, dummystruct) + err := Respond(recorder, http.StatusCreated, dummystruct) + assert.NoError(t, err) assert.Equal(t, http.StatusCreated, recorder.Code) assert.JSONEq(t, recorder.Body.String(), `{"name":"dummy"}`) assert.Equal(t, "application/json", recorder.Header().Get("Content-Type")) } - -func Test_RespondError(t *testing.T) { - recorder := httptest.NewRecorder() - var customError = errors.New("custom error") - - RespondError(recorder, http.StatusBadRequest, customError) - - assert.Equal(t, http.StatusBadRequest, recorder.Code) - assert.JSONEq(t, recorder.Body.String(), `{"details":["custom error"], "message":"Bad Request", "error":true}`) - -} -func Test_RespondInternalServerError(t *testing.T) { - recorder := httptest.NewRecorder() - - RespondServerError(recorder) - - assert.Equal(t, http.StatusInternalServerError, recorder.Code) - assert.JSONEq(t, recorder.Body.String(), `{"details":["internal server error"], "message":"Internal Server Error", "error":true}`) - -} -func Test_RespondUnauthorized(t *testing.T) { - recorder := httptest.NewRecorder() - - RespondUnauthorized(recorder) - - assert.Equal(t, http.StatusUnauthorized, recorder.Code) - assert.JSONEq(t, recorder.Body.String(), `{"details":["unauthorized"], "message":"Unauthorized", "error":true}`) - -} -func Test_RespondForbidden(t *testing.T) { - recorder := httptest.NewRecorder() - - RespondForbidden(recorder) - - assert.Equal(t, http.StatusForbidden, recorder.Code) - assert.JSONEq(t, recorder.Body.String(), `{"details":["forbidden"], "message":"Forbidden", "error":true}`) - -} diff --git a/backend/pkgs/server/result.go b/backend/pkgs/server/result.go index 656d17b..69dcf81 100644 --- a/backend/pkgs/server/result.go +++ b/backend/pkgs/server/result.go @@ -17,15 +17,3 @@ func Wrap(data interface{}) Result { Item: data, } } - -func (r Result) AddMessage(message string) Result { - r.Message = message - return r -} - -func (r Result) AddError(err string, details interface{}) Result { - r.Message = err - r.Details = details - r.Error = true - return r -} diff --git a/backend/pkgs/server/server.go b/backend/pkgs/server/server.go index 1cc7cf1..921c576 100644 --- a/backend/pkgs/server/server.go +++ b/backend/pkgs/server/server.go @@ -10,6 +10,8 @@ import ( "sync" "syscall" "time" + + "github.com/go-chi/chi/v5" ) var ( @@ -22,7 +24,11 @@ type Server struct { Port string Worker Worker - wg sync.WaitGroup + wg sync.WaitGroup + mux *chi.Mux + + // mw is the global middleware chain for the server. + mw []Middleware started bool activeServer *http.Server @@ -36,6 +42,7 @@ func NewServer(opts ...Option) *Server { s := &Server{ Host: "localhost", Port: "8080", + mux: chi.NewRouter(), Worker: NewSimpleWorker(), idleTimeout: 30 * time.Second, readTimeout: 10 * time.Second, @@ -75,14 +82,14 @@ func (s *Server) Shutdown(sig string) error { } -func (s *Server) Start(router http.Handler) error { +func (s *Server) Start() error { if s.started { return ErrServerAlreadyStarted } s.activeServer = &http.Server{ Addr: s.Host + ":" + s.Port, - Handler: router, + Handler: s.mux, IdleTimeout: s.idleTimeout, ReadTimeout: s.readTimeout, WriteTimeout: s.writeTimeout, diff --git a/backend/pkgs/server/server_options.go b/backend/pkgs/server/server_options.go index 1029b1f..93b7781 100644 --- a/backend/pkgs/server/server_options.go +++ b/backend/pkgs/server/server_options.go @@ -4,6 +4,13 @@ import "time" type Option = func(s *Server) error +func WithMiddleware(mw ...Middleware) Option { + return func(s *Server) error { + s.mw = append(s.mw, mw...) + return nil + } +} + func WithWorker(w Worker) Option { return func(s *Server) error { s.Worker = w diff --git a/backend/pkgs/server/server_test.go b/backend/pkgs/server/server_test.go index 1d8b105..95a93fe 100644 --- a/backend/pkgs/server/server_test.go +++ b/backend/pkgs/server/server_test.go @@ -12,8 +12,11 @@ import ( func testServer(t *testing.T, r http.Handler) *Server { svr := NewServer(WithHost("127.0.0.1"), WithPort("19245")) + if r != nil { + svr.mux.Mount("/", r) + } go func() { - err := svr.Start(r) + err := svr.Start() assert.NoError(t, err) }() @@ -42,7 +45,7 @@ func Test_ServerShutdown_Error(t *testing.T) { func Test_ServerStarts_Error(t *testing.T) { svr := testServer(t, nil) - err := svr.Start(nil) + err := svr.Start() assert.ErrorIs(t, err, ErrServerAlreadyStarted) err = svr.Shutdown("test") diff --git a/frontend/lib/api/types/data-contracts.ts b/frontend/lib/api/types/data-contracts.ts index 8d5fef1..e1bc8dd 100644 --- a/frontend/lib/api/types/data-contracts.ts +++ b/frontend/lib/api/types/data-contracts.ts @@ -247,6 +247,11 @@ export interface UserUpdate { name: string; } +export interface ServerErrorResponse { + error: string; + fields: Record; +} + export interface ServerResult { details: any; error: boolean; @@ -258,11 +263,6 @@ export interface ServerResults { items: any; } -export interface ServerValidationError { - field: string; - reason: string; -} - export interface UserRegistration { email: string; name: string; diff --git a/frontend/pages/index.vue b/frontend/pages/index.vue index f2d05e1..44183c6 100644 --- a/frontend/pages/index.vue +++ b/frontend/pages/index.vue @@ -14,7 +14,7 @@ const { data: status } = useAsyncData(async () => { const { data } = await api.status(); - if (data) { + if (data.demo) { username.value = "demo@example.com"; password.value = "demo"; } From cd82fe0d895524c5c4507ebd9356b7e1569c6da6 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sat, 29 Oct 2022 20:05:38 -0800 Subject: [PATCH 076/435] refactor: remove empty services (#116) * remove empty services * remove old factory * remove old static files * cleanup more duplicate service code * file/folder reorg --- Taskfile.yml | 14 +++--- backend/app/api/app.go | 8 +-- backend/app/api/demo.go | 2 +- backend/app/api/handlers/v1/controller.go | 7 ++- backend/app/api/handlers/v1/v1_ctrl_auth.go | 2 +- backend/app/api/handlers/v1/v1_ctrl_group.go | 10 ++-- backend/app/api/handlers/v1/v1_ctrl_items.go | 14 +++--- .../handlers/v1/v1_ctrl_items_attachments.go | 6 +-- backend/app/api/handlers/v1/v1_ctrl_labels.go | 18 +++---- .../app/api/handlers/v1/v1_ctrl_locations.go | 16 +++--- backend/app/api/handlers/v1/v1_ctrl_user.go | 4 +- backend/app/api/logger.go | 2 +- backend/app/api/main.go | 10 ++-- backend/app/api/middleware.go | 2 +- backend/app/api/routes.go | 3 +- backend/app/{ => tools}/migrations/main.go | 4 +- backend/go.mod | 5 +- backend/go.sum | 26 +++++++++- backend/internal/core/services/all.go | 24 +++++++++ .../internal/{ => core}/services/contexts.go | 2 +- .../{ => core}/services/contexts_test.go | 2 +- .../internal/{ => core}/services/main_test.go | 4 +- .../{ => core}/services/service_group.go | 9 +--- .../{ => core}/services/service_items.go | 26 +--------- .../services/service_items_attachments.go | 10 ++-- .../service_items_attachments_test.go | 6 +-- .../{ => core}/services/service_items_csv.go | 2 +- .../services/service_items_csv_test.go | 0 .../{ => core}/services/service_items_test.go | 14 ++---- .../{ => core}/services/service_user.go | 2 +- .../services/service_user_defaults.go | 2 +- backend/{ => internal/data}/ent/attachment.go | 6 +-- .../data}/ent/attachment/attachment.go | 0 .../data}/ent/attachment/where.go | 2 +- .../data}/ent/attachment_create.go | 6 +-- .../data}/ent/attachment_delete.go | 4 +- .../data}/ent/attachment_query.go | 8 +-- .../data}/ent/attachment_update.go | 8 +-- backend/{ => internal/data}/ent/authtokens.go | 4 +- .../data}/ent/authtokens/authtokens.go | 0 .../data}/ent/authtokens/where.go | 2 +- .../data}/ent/authtokens_create.go | 4 +- .../data}/ent/authtokens_delete.go | 4 +- .../data}/ent/authtokens_query.go | 6 +-- .../data}/ent/authtokens_update.go | 6 +-- backend/{ => internal/data}/ent/client.go | 24 ++++----- backend/{ => internal/data}/ent/config.go | 0 backend/{ => internal/data}/ent/context.go | 0 backend/{ => internal/data}/ent/document.go | 4 +- .../data}/ent/document/document.go | 0 .../{ => internal/data}/ent/document/where.go | 2 +- .../data}/ent/document_create.go | 8 +-- .../data}/ent/document_delete.go | 4 +- .../{ => internal/data}/ent/document_query.go | 10 ++-- .../data}/ent/document_update.go | 10 ++-- .../{ => internal/data}/ent/documenttoken.go | 4 +- .../data}/ent/documenttoken/documenttoken.go | 0 .../data}/ent/documenttoken/where.go | 2 +- .../data}/ent/documenttoken_create.go | 4 +- .../data}/ent/documenttoken_delete.go | 4 +- .../data}/ent/documenttoken_query.go | 6 +-- .../data}/ent/documenttoken_update.go | 6 +-- backend/{ => internal/data}/ent/ent.go | 22 ++++---- .../data}/ent/enttest/enttest.go | 6 +-- backend/{ => internal/data}/ent/external.go | 0 backend/{ => internal/data}/ent/generate.go | 0 backend/{ => internal/data}/ent/group.go | 2 +- .../{ => internal/data}/ent/group/group.go | 0 .../{ => internal/data}/ent/group/where.go | 2 +- .../{ => internal/data}/ent/group_create.go | 14 +++--- .../{ => internal/data}/ent/group_delete.go | 4 +- .../{ => internal/data}/ent/group_query.go | 16 +++--- .../{ => internal/data}/ent/group_update.go | 16 +++--- .../data}/ent/groupinvitationtoken.go | 4 +- .../groupinvitationtoken.go | 0 .../data}/ent/groupinvitationtoken/where.go | 2 +- .../data}/ent/groupinvitationtoken_create.go | 4 +- .../data}/ent/groupinvitationtoken_delete.go | 4 +- .../data}/ent/groupinvitationtoken_query.go | 6 +-- .../data}/ent/groupinvitationtoken_update.go | 6 +-- backend/{ => internal/data}/ent/has_id.go | 0 backend/{ => internal/data}/ent/hook/hook.go | 2 +- backend/{ => internal/data}/ent/item.go | 6 +-- backend/{ => internal/data}/ent/item/item.go | 0 backend/{ => internal/data}/ent/item/where.go | 2 +- .../{ => internal/data}/ent/item_create.go | 12 ++--- .../{ => internal/data}/ent/item_delete.go | 4 +- backend/{ => internal/data}/ent/item_query.go | 14 +++--- .../{ => internal/data}/ent/item_update.go | 14 +++--- backend/{ => internal/data}/ent/itemfield.go | 4 +- .../data}/ent/itemfield/itemfield.go | 0 .../data}/ent/itemfield/where.go | 2 +- .../data}/ent/itemfield_create.go | 4 +- .../data}/ent/itemfield_delete.go | 4 +- .../data}/ent/itemfield_query.go | 6 +-- .../data}/ent/itemfield_update.go | 6 +-- backend/{ => internal/data}/ent/label.go | 4 +- .../{ => internal/data}/ent/label/label.go | 0 .../{ => internal/data}/ent/label/where.go | 2 +- .../{ => internal/data}/ent/label_create.go | 6 +-- .../{ => internal/data}/ent/label_delete.go | 4 +- .../{ => internal/data}/ent/label_query.go | 8 +-- .../{ => internal/data}/ent/label_update.go | 8 +-- backend/{ => internal/data}/ent/location.go | 4 +- .../data}/ent/location/location.go | 0 .../{ => internal/data}/ent/location/where.go | 2 +- .../data}/ent/location_create.go | 6 +-- .../data}/ent/location_delete.go | 4 +- .../{ => internal/data}/ent/location_query.go | 8 +-- .../data}/ent/location_update.go | 8 +-- .../data}/ent/migrate/migrate.go | 0 .../{ => internal/data}/ent/migrate/schema.go | 0 backend/{ => internal/data}/ent/mutation.go | 24 ++++----- .../data}/ent/predicate/predicate.go | 0 backend/{ => internal/data}/ent/runtime.go | 24 ++++----- .../data}/ent/runtime/runtime.go | 2 +- .../data}/ent/schema/attachment.go | 2 +- .../data}/ent/schema/auth_tokens.go | 2 +- .../data}/ent/schema/document.go | 2 +- .../data}/ent/schema/document_token.go | 2 +- .../{ => internal/data}/ent/schema/group.go | 2 +- .../ent/schema/group_invitation_token.go | 2 +- .../{ => internal/data}/ent/schema/item.go | 2 +- .../data}/ent/schema/item_field.go | 2 +- .../{ => internal/data}/ent/schema/label.go | 2 +- .../data}/ent/schema/location.go | 2 +- .../data}/ent/schema/mixins/base.go | 0 .../data}/ent/schema/templates/has_id.tmpl | 0 .../{ => internal/data}/ent/schema/user.go | 2 +- backend/{ => internal/data}/ent/tx.go | 0 backend/{ => internal/data}/ent/user.go | 4 +- backend/{ => internal/data}/ent/user/user.go | 0 backend/{ => internal/data}/ent/user/where.go | 2 +- .../{ => internal/data}/ent/user_create.go | 6 +-- .../{ => internal/data}/ent/user_delete.go | 4 +- backend/{ => internal/data}/ent/user_query.go | 8 +-- .../{ => internal/data}/ent/user_update.go | 8 +-- .../{ => data}/migrations/migrations.go | 0 .../migrations/20220929052825_init.sql | 0 .../20221001210956_group_invitations.sql | 0 .../20221009173029_add_user_roles.sql | 0 .../20221020043305_allow_nesting_types.sql | 0 .../migrations/migrations/atlas.sum | 0 backend/internal/{ => data}/repo/id_set.go | 0 backend/internal/{ => data}/repo/main_test.go | 2 +- .../internal/{ => data}/repo/map_helpers.go | 0 .../internal/{ => data}/repo/pagination.go | 0 .../{ => data}/repo/repo_document_tokens.go | 4 +- .../repo/repo_document_tokens_test.go | 4 +- .../{ => data}/repo/repo_documents.go | 6 +-- .../{ => data}/repo/repo_documents_test.go | 2 +- .../internal/{ => data}/repo/repo_group.go | 11 ++-- .../{ => data}/repo/repo_group_test.go | 2 +- .../{ => data}/repo/repo_item_attachments.go | 4 +- .../repo/repo_item_attachments_test.go | 4 +- .../internal/{ => data}/repo/repo_items.go | 14 +++--- .../{ => data}/repo/repo_items_test.go | 0 .../internal/{ => data}/repo/repo_labels.go | 39 ++++++++++++--- .../{ => data}/repo/repo_labels_test.go | 0 .../{ => data}/repo/repo_locations.go | 37 +++++++++----- .../{ => data}/repo/repo_locations_test.go | 0 .../internal/{ => data}/repo/repo_tokens.go | 4 +- .../{ => data}/repo/repo_tokens_test.go | 0 .../internal/{ => data}/repo/repo_users.go | 4 +- .../{ => data}/repo/repo_users_test.go | 0 backend/internal/{ => data}/repo/repos_all.go | 2 +- backend/internal/mocks/chimocker/chimocker.go | 30 ----------- backend/internal/mocks/factories/users.go | 16 ------ backend/internal/services/all.go | 28 ----------- backend/internal/services/service_labels.go | 37 -------------- .../internal/services/service_locations.go | 47 ------------------ backend/internal/{ => sys}/config/conf.go | 0 .../{ => sys}/config/conf_database.go | 0 .../internal/{ => sys}/config/conf_logger.go | 0 .../internal/{ => sys}/config/conf_mailer.go | 0 .../{ => sys}/config/conf_mailer_test.go | 0 backend/internal/sys/validate/validate.go | 37 ++++++++++++++ backend/internal/web/mid/errors.go | 2 +- backend/static/favicon.ico | Bin 1366 -> 0 bytes 179 files changed, 514 insertions(+), 582 deletions(-) rename backend/app/{ => tools}/migrations/main.go (90%) create mode 100644 backend/internal/core/services/all.go rename backend/internal/{ => core}/services/contexts.go (96%) rename backend/internal/{ => core}/services/contexts_test.go (92%) rename backend/internal/{ => core}/services/main_test.go (92%) rename backend/internal/{ => core}/services/service_group.go (77%) rename backend/internal/{ => core}/services/service_items.go (80%) rename backend/internal/{ => core}/services/service_items_attachments.go (92%) rename backend/internal/{ => core}/services/service_items_attachments_test.go (84%) rename backend/internal/{ => core}/services/service_items_csv.go (97%) rename backend/internal/{ => core}/services/service_items_csv_test.go (100%) rename backend/internal/{ => core}/services/service_items_test.go (83%) rename backend/internal/{ => core}/services/service_user.go (99%) rename backend/internal/{ => core}/services/service_user_defaults.go (91%) rename backend/{ => internal/data}/ent/attachment.go (97%) rename backend/{ => internal/data}/ent/attachment/attachment.go (100%) rename backend/{ => internal/data}/ent/attachment/where.go (99%) rename backend/{ => internal/data}/ent/attachment_create.go (98%) rename backend/{ => internal/data}/ent/attachment_delete.go (95%) rename backend/{ => internal/data}/ent/attachment_query.go (98%) rename backend/{ => internal/data}/ent/attachment_update.go (98%) rename backend/{ => internal/data}/ent/authtokens.go (97%) rename backend/{ => internal/data}/ent/authtokens/authtokens.go (100%) rename backend/{ => internal/data}/ent/authtokens/where.go (99%) rename backend/{ => internal/data}/ent/authtokens_create.go (98%) rename backend/{ => internal/data}/ent/authtokens_delete.go (95%) rename backend/{ => internal/data}/ent/authtokens_query.go (98%) rename backend/{ => internal/data}/ent/authtokens_update.go (98%) rename backend/{ => internal/data}/ent/client.go (98%) rename backend/{ => internal/data}/ent/config.go (100%) rename backend/{ => internal/data}/ent/context.go (100%) rename backend/{ => internal/data}/ent/document.go (98%) rename backend/{ => internal/data}/ent/document/document.go (100%) rename backend/{ => internal/data}/ent/document/where.go (99%) rename backend/{ => internal/data}/ent/document_create.go (97%) rename backend/{ => internal/data}/ent/document_delete.go (95%) rename backend/{ => internal/data}/ent/document_query.go (98%) rename backend/{ => internal/data}/ent/document_update.go (98%) rename backend/{ => internal/data}/ent/documenttoken.go (97%) rename backend/{ => internal/data}/ent/documenttoken/documenttoken.go (100%) rename backend/{ => internal/data}/ent/documenttoken/where.go (99%) rename backend/{ => internal/data}/ent/documenttoken_create.go (98%) rename backend/{ => internal/data}/ent/documenttoken_delete.go (95%) rename backend/{ => internal/data}/ent/documenttoken_query.go (98%) rename backend/{ => internal/data}/ent/documenttoken_update.go (98%) rename backend/{ => internal/data}/ent/ent.go (94%) rename backend/{ => internal/data}/ent/enttest/enttest.go (90%) rename backend/{ => internal/data}/ent/external.go (100%) rename backend/{ => internal/data}/ent/generate.go (100%) rename backend/{ => internal/data}/ent/group.go (99%) rename backend/{ => internal/data}/ent/group/group.go (100%) rename backend/{ => internal/data}/ent/group/where.go (99%) rename backend/{ => internal/data}/ent/group_create.go (97%) rename backend/{ => internal/data}/ent/group_delete.go (95%) rename backend/{ => internal/data}/ent/group_query.go (98%) rename backend/{ => internal/data}/ent/group_update.go (98%) rename backend/{ => internal/data}/ent/groupinvitationtoken.go (98%) rename backend/{ => internal/data}/ent/groupinvitationtoken/groupinvitationtoken.go (100%) rename backend/{ => internal/data}/ent/groupinvitationtoken/where.go (99%) rename backend/{ => internal/data}/ent/groupinvitationtoken_create.go (98%) rename backend/{ => internal/data}/ent/groupinvitationtoken_delete.go (95%) rename backend/{ => internal/data}/ent/groupinvitationtoken_query.go (98%) rename backend/{ => internal/data}/ent/groupinvitationtoken_update.go (98%) rename backend/{ => internal/data}/ent/has_id.go (100%) rename backend/{ => internal/data}/ent/hook/hook.go (99%) rename backend/{ => internal/data}/ent/item.go (98%) rename backend/{ => internal/data}/ent/item/item.go (100%) rename backend/{ => internal/data}/ent/item/where.go (99%) rename backend/{ => internal/data}/ent/item_create.go (98%) rename backend/{ => internal/data}/ent/item_delete.go (95%) rename backend/{ => internal/data}/ent/item_query.go (98%) rename backend/{ => internal/data}/ent/item_update.go (99%) rename backend/{ => internal/data}/ent/itemfield.go (98%) rename backend/{ => internal/data}/ent/itemfield/itemfield.go (100%) rename backend/{ => internal/data}/ent/itemfield/where.go (99%) rename backend/{ => internal/data}/ent/itemfield_create.go (99%) rename backend/{ => internal/data}/ent/itemfield_delete.go (95%) rename backend/{ => internal/data}/ent/itemfield_query.go (98%) rename backend/{ => internal/data}/ent/itemfield_update.go (99%) rename backend/{ => internal/data}/ent/label.go (98%) rename backend/{ => internal/data}/ent/label/label.go (100%) rename backend/{ => internal/data}/ent/label/where.go (99%) rename backend/{ => internal/data}/ent/label_create.go (98%) rename backend/{ => internal/data}/ent/label_delete.go (95%) rename backend/{ => internal/data}/ent/label_query.go (98%) rename backend/{ => internal/data}/ent/label_update.go (98%) rename backend/{ => internal/data}/ent/location.go (98%) rename backend/{ => internal/data}/ent/location/location.go (100%) rename backend/{ => internal/data}/ent/location/where.go (99%) rename backend/{ => internal/data}/ent/location_create.go (98%) rename backend/{ => internal/data}/ent/location_delete.go (95%) rename backend/{ => internal/data}/ent/location_query.go (98%) rename backend/{ => internal/data}/ent/location_update.go (99%) rename backend/{ => internal/data}/ent/migrate/migrate.go (100%) rename backend/{ => internal/data}/ent/migrate/schema.go (100%) rename backend/{ => internal/data}/ent/mutation.go (99%) rename backend/{ => internal/data}/ent/predicate/predicate.go (100%) rename backend/{ => internal/data}/ent/runtime.go (97%) rename backend/{ => internal/data}/ent/runtime/runtime.go (86%) rename backend/{ => internal/data}/ent/schema/attachment.go (91%) rename backend/{ => internal/data}/ent/schema/auth_tokens.go (92%) rename backend/{ => internal/data}/ent/schema/document.go (93%) rename backend/{ => internal/data}/ent/schema/document_token.go (92%) rename backend/{ => internal/data}/ent/schema/group.go (94%) rename backend/{ => internal/data}/ent/schema/group_invitation_token.go (92%) rename backend/{ => internal/data}/ent/schema/item.go (97%) rename backend/{ => internal/data}/ent/schema/item_field.go (92%) rename backend/{ => internal/data}/ent/schema/label.go (90%) rename backend/{ => internal/data}/ent/schema/location.go (91%) rename backend/{ => internal/data}/ent/schema/mixins/base.go (100%) rename backend/{ => internal/data}/ent/schema/templates/has_id.tmpl (100%) rename backend/{ => internal/data}/ent/schema/user.go (93%) rename backend/{ => internal/data}/ent/tx.go (100%) rename backend/{ => internal/data}/ent/user.go (98%) rename backend/{ => internal/data}/ent/user/user.go (100%) rename backend/{ => internal/data}/ent/user/where.go (99%) rename backend/{ => internal/data}/ent/user_create.go (98%) rename backend/{ => internal/data}/ent/user_delete.go (95%) rename backend/{ => internal/data}/ent/user_query.go (98%) rename backend/{ => internal/data}/ent/user_update.go (98%) rename backend/internal/{ => data}/migrations/migrations.go (100%) rename backend/internal/{ => data}/migrations/migrations/20220929052825_init.sql (100%) rename backend/internal/{ => data}/migrations/migrations/20221001210956_group_invitations.sql (100%) rename backend/internal/{ => data}/migrations/migrations/20221009173029_add_user_roles.sql (100%) rename backend/internal/{ => data}/migrations/migrations/20221020043305_allow_nesting_types.sql (100%) rename backend/internal/{ => data}/migrations/migrations/atlas.sum (100%) rename backend/internal/{ => data}/repo/id_set.go (100%) rename backend/internal/{ => data}/repo/main_test.go (94%) rename backend/internal/{ => data}/repo/map_helpers.go (100%) rename backend/internal/{ => data}/repo/pagination.go (100%) rename backend/internal/{ => data}/repo/repo_document_tokens.go (92%) rename backend/internal/{ => data}/repo/repo_document_tokens_test.go (96%) rename backend/internal/{ => data}/repo/repo_documents.go (92%) rename backend/internal/{ => data}/repo/repo_documents_test.go (97%) rename backend/internal/{ => data}/repo/repo_group.go (90%) rename backend/internal/{ => data}/repo/repo_group_test.go (95%) rename backend/internal/{ => data}/repo/repo_item_attachments.go (94%) rename backend/internal/{ => data}/repo/repo_item_attachments_test.go (95%) rename backend/internal/{ => data}/repo/repo_items.go (96%) rename backend/internal/{ => data}/repo/repo_items_test.go (100%) rename backend/internal/{ => data}/repo/repo_labels.go (73%) rename backend/internal/{ => data}/repo/repo_labels_test.go (100%) rename backend/internal/{ => data}/repo/repo_locations.go (77%) rename backend/internal/{ => data}/repo/repo_locations_test.go (100%) rename backend/internal/{ => data}/repo/repo_tokens.go (94%) rename backend/internal/{ => data}/repo/repo_tokens_test.go (100%) rename backend/internal/{ => data}/repo/repo_users.go (96%) rename backend/internal/{ => data}/repo/repo_users_test.go (100%) rename backend/internal/{ => data}/repo/repos_all.go (92%) delete mode 100644 backend/internal/mocks/chimocker/chimocker.go delete mode 100644 backend/internal/mocks/factories/users.go delete mode 100644 backend/internal/services/all.go delete mode 100644 backend/internal/services/service_labels.go delete mode 100644 backend/internal/services/service_locations.go rename backend/internal/{ => sys}/config/conf.go (100%) rename backend/internal/{ => sys}/config/conf_database.go (100%) rename backend/internal/{ => sys}/config/conf_logger.go (100%) rename backend/internal/{ => sys}/config/conf_mailer.go (100%) rename backend/internal/{ => sys}/config/conf_mailer_test.go (100%) create mode 100644 backend/internal/sys/validate/validate.go delete mode 100644 backend/static/favicon.ico diff --git a/Taskfile.yml b/Taskfile.yml index 48044ee..51a756b 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -29,12 +29,12 @@ tasks: - python3 ./scripts/process-types.py ./frontend/lib/api/types/data-contracts.ts sources: - "./backend/app/api/**/*" - - "./backend/internal/repo/**/*" + - "./backend/internal/data/**" - "./backend/internal/services/**/*" - "./scripts/process-types.py" generates: - "./frontend/lib/api/types/data-contracts.ts" - - "./backend/ent/schema" + - "./backend/internal/data/ent/schema" - "./backend/app/api/static/docs/swagger.json" - "./backend/app/api/static/docs/swagger.yaml" @@ -83,19 +83,19 @@ tasks: desc: Run Entgo.io Code Generation cmds: - | - cd backend && go generate ./... \ - --template=ent/schema/templates/has_id.tmpl + cd backend/internal/ && go generate ./... \ + --template=./data/ent/schema/templates/has_id.tmpl sources: - - "./backend/ent/schema/**/*" + - "./backend/internal/data/ent/schema/**/*" generates: - - "./backend/ent/" + - "./backend/internal/ent/" db:migration: desc: Runs the database diff engine to generate a SQL migration files deps: - db:generate cmds: - - cd backend && go run app/migrations/main.go {{ .CLI_ARGS }} + - cd backend && go run app/tools/migrations/main.go {{ .CLI_ARGS }} ui:watch: desc: Starts the vitest test runner in watch mode diff --git a/backend/app/api/app.go b/backend/app/api/app.go index 7f6b23f..854c4e5 100644 --- a/backend/app/api/app.go +++ b/backend/app/api/app.go @@ -3,10 +3,10 @@ package main import ( "time" - "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/internal/core/services" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/repo" + "github.com/hay-kot/homebox/backend/internal/sys/config" "github.com/hay-kot/homebox/backend/pkgs/mailer" "github.com/hay-kot/homebox/backend/pkgs/server" ) diff --git a/backend/app/api/demo.go b/backend/app/api/demo.go index a98f03d..538655d 100644 --- a/backend/app/api/demo.go +++ b/backend/app/api/demo.go @@ -5,7 +5,7 @@ import ( "encoding/csv" "strings" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/rs/zerolog/log" ) diff --git a/backend/app/api/handlers/v1/controller.go b/backend/app/api/handlers/v1/controller.go index 2c41bc1..4f7a73e 100644 --- a/backend/app/api/handlers/v1/controller.go +++ b/backend/app/api/handlers/v1/controller.go @@ -3,7 +3,8 @@ package v1 import ( "net/http" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/pkgs/server" ) @@ -26,6 +27,7 @@ func WithRegistration(allowRegistration bool) func(*V1Controller) { } type V1Controller struct { + repo *repo.AllRepos svc *services.AllServices maxUploadSize int64 isDemo bool @@ -57,8 +59,9 @@ func BaseUrlFunc(prefix string) func(s string) string { } } -func NewControllerV1(svc *services.AllServices, options ...func(*V1Controller)) *V1Controller { +func NewControllerV1(svc *services.AllServices, repos *repo.AllRepos, options ...func(*V1Controller)) *V1Controller { ctrl := &V1Controller{ + repo: repos, svc: svc, allowRegistration: true, } diff --git a/backend/app/api/handlers/v1/v1_ctrl_auth.go b/backend/app/api/handlers/v1/v1_ctrl_auth.go index 28ee0dc..b005a9d 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_auth.go +++ b/backend/app/api/handlers/v1/v1_ctrl_auth.go @@ -5,7 +5,7 @@ import ( "net/http" "time" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" diff --git a/backend/app/api/handlers/v1/v1_ctrl_group.go b/backend/app/api/handlers/v1/v1_ctrl_group.go index a403877..a3e8992 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_group.go +++ b/backend/app/api/handlers/v1/v1_ctrl_group.go @@ -2,11 +2,10 @@ package v1 import ( "net/http" - "strings" "time" - "github.com/hay-kot/homebox/backend/internal/repo" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" @@ -54,13 +53,12 @@ func (ctrl *V1Controller) handleGroupGeneral() server.HandlerFunc { switch r.Method { case http.MethodGet: - group, err := ctrl.svc.Group.Get(ctx) + group, err := ctrl.repo.Groups.GroupByID(ctx, ctx.GID) if err != nil { log.Err(err).Msg("failed to get group") return validate.NewRequestError(err, http.StatusInternalServerError) } - group.Currency = strings.ToUpper(group.Currency) // TODO: Hack to fix the currency enums being lower caseÍ return server.Respond(w, http.StatusOK, group) case http.MethodPut: @@ -74,7 +72,7 @@ func (ctrl *V1Controller) handleGroupGeneral() server.HandlerFunc { log.Err(err).Msg("failed to update group") return validate.NewRequestError(err, http.StatusInternalServerError) } - group.Currency = strings.ToUpper(group.Currency) // TODO: Hack to fix the currency enums being lower case + return server.Respond(w, http.StatusOK, group) } diff --git a/backend/app/api/handlers/v1/v1_ctrl_items.go b/backend/app/api/handlers/v1/v1_ctrl_items.go index 84591ca..b43333a 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items.go @@ -7,8 +7,8 @@ import ( "strconv" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/repo" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" @@ -61,7 +61,7 @@ func (ctrl *V1Controller) HandleItemsGetAll() server.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { ctx := services.NewContext(r.Context()) - items, err := ctrl.svc.Items.Query(ctx, extractQuery(r)) + items, err := ctrl.repo.Items.QueryByGroup(ctx, ctx.GID, extractQuery(r)) if err != nil { log.Err(err).Msg("failed to get items") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -87,7 +87,7 @@ func (ctrl *V1Controller) HandleItemsCreate() server.HandlerFunc { } user := services.UseUserCtx(r.Context()) - item, err := ctrl.svc.Items.Create(r.Context(), user.GroupID, createData) + item, err := ctrl.repo.Items.Create(r.Context(), user.GroupID, createData) if err != nil { log.Err(err).Msg("failed to create item") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -144,14 +144,14 @@ func (ctrl *V1Controller) handleItemsGeneral() server.HandlerFunc { switch r.Method { case http.MethodGet: - items, err := ctrl.svc.Items.GetOne(r.Context(), ctx.GID, ID) + items, err := ctrl.repo.Items.GetOneByGroup(r.Context(), ctx.GID, ID) if err != nil { log.Err(err).Msg("failed to get item") return validate.NewRequestError(err, http.StatusInternalServerError) } return server.Respond(w, http.StatusOK, items) case http.MethodDelete: - err = ctrl.svc.Items.Delete(r.Context(), ctx.GID, ID) + err = ctrl.repo.Items.DeleteByGroup(r.Context(), ctx.GID, ID) if err != nil { log.Err(err).Msg("failed to delete item") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -164,7 +164,7 @@ func (ctrl *V1Controller) handleItemsGeneral() server.HandlerFunc { return validate.NewRequestError(err, http.StatusInternalServerError) } body.ID = ID - result, err := ctrl.svc.Items.Update(r.Context(), ctx.GID, body) + result, err := ctrl.repo.Items.UpdateByGroup(r.Context(), ctx.GID, body) if err != nil { log.Err(err).Msg("failed to update item") return validate.NewRequestError(err, http.StatusInternalServerError) diff --git a/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go index 5d90157..e776e9a 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items_attachments.go @@ -5,9 +5,9 @@ import ( "fmt" "net/http" - "github.com/hay-kot/homebox/backend/ent/attachment" - "github.com/hay-kot/homebox/backend/internal/repo" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" diff --git a/backend/app/api/handlers/v1/v1_ctrl_labels.go b/backend/app/api/handlers/v1/v1_ctrl_labels.go index f02a929..2551b46 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_labels.go +++ b/backend/app/api/handlers/v1/v1_ctrl_labels.go @@ -3,9 +3,9 @@ package v1 import ( "net/http" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/internal/repo" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" @@ -21,7 +21,7 @@ import ( func (ctrl *V1Controller) HandleLabelsGetAll() server.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { user := services.UseUserCtx(r.Context()) - labels, err := ctrl.svc.Labels.GetAll(r.Context(), user.GroupID) + labels, err := ctrl.repo.Labels.GetAll(r.Context(), user.GroupID) if err != nil { log.Err(err).Msg("error getting labels") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -47,7 +47,7 @@ func (ctrl *V1Controller) HandleLabelsCreate() server.HandlerFunc { } user := services.UseUserCtx(r.Context()) - label, err := ctrl.svc.Labels.Create(r.Context(), user.GroupID, createData) + label, err := ctrl.repo.Labels.Create(r.Context(), user.GroupID, createData) if err != nil { log.Err(err).Msg("error creating label") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -103,7 +103,7 @@ func (ctrl *V1Controller) handleLabelsGeneral() server.HandlerFunc { switch r.Method { case http.MethodGet: - labels, err := ctrl.svc.Labels.Get(r.Context(), ctx.GID, ID) + labels, err := ctrl.repo.Labels.GetOneByGroup(r.Context(), ctx.GID, ID) if err != nil { if ent.IsNotFound(err) { log.Err(err). @@ -117,7 +117,7 @@ func (ctrl *V1Controller) handleLabelsGeneral() server.HandlerFunc { return server.Respond(w, http.StatusOK, labels) case http.MethodDelete: - err = ctrl.svc.Labels.Delete(r.Context(), ctx.GID, ID) + err = ctrl.repo.Labels.DeleteByGroup(ctx, ctx.GID, ID) if err != nil { log.Err(err).Msg("error deleting label") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -127,14 +127,12 @@ func (ctrl *V1Controller) handleLabelsGeneral() server.HandlerFunc { case http.MethodPut: body := repo.LabelUpdate{} if err := server.Decode(r, &body); err != nil { - log.Err(err).Msg("error decoding label update data") return validate.NewRequestError(err, http.StatusInternalServerError) } body.ID = ID - result, err := ctrl.svc.Labels.Update(r.Context(), ctx.GID, body) + result, err := ctrl.repo.Labels.UpdateByGroup(ctx, ctx.GID, body) if err != nil { - log.Err(err).Msg("error updating label") return validate.NewRequestError(err, http.StatusInternalServerError) } return server.Respond(w, http.StatusOK, result) diff --git a/backend/app/api/handlers/v1/v1_ctrl_locations.go b/backend/app/api/handlers/v1/v1_ctrl_locations.go index 775cf76..5e85766 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_locations.go +++ b/backend/app/api/handlers/v1/v1_ctrl_locations.go @@ -3,9 +3,9 @@ package v1 import ( "net/http" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/internal/repo" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" @@ -21,7 +21,7 @@ import ( func (ctrl *V1Controller) HandleLocationGetAll() server.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) error { user := services.UseUserCtx(r.Context()) - locations, err := ctrl.svc.Location.GetAll(r.Context(), user.GroupID) + locations, err := ctrl.repo.Locations.GetAll(r.Context(), user.GroupID) if err != nil { log.Err(err).Msg("failed to get locations") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -48,7 +48,7 @@ func (ctrl *V1Controller) HandleLocationCreate() server.HandlerFunc { } user := services.UseUserCtx(r.Context()) - location, err := ctrl.svc.Location.Create(r.Context(), user.GroupID, createData) + location, err := ctrl.repo.Locations.Create(r.Context(), user.GroupID, createData) if err != nil { log.Err(err).Msg("failed to create location") return validate.NewRequestError(err, http.StatusInternalServerError) @@ -105,7 +105,7 @@ func (ctrl *V1Controller) handleLocationGeneral() server.HandlerFunc { switch r.Method { case http.MethodGet: - location, err := ctrl.svc.Location.GetOne(r.Context(), ctx.GID, ID) + location, err := ctrl.repo.Locations.GetOneByGroup(r.Context(), ctx.GID, ID) if err != nil { l := log.Err(err). Str("ID", ID.String()). @@ -129,14 +129,14 @@ func (ctrl *V1Controller) handleLocationGeneral() server.HandlerFunc { body.ID = ID - result, err := ctrl.svc.Location.Update(r.Context(), ctx.GID, body) + result, err := ctrl.repo.Locations.UpdateOneByGroup(r.Context(), ctx.GID, ID, body) if err != nil { log.Err(err).Msg("failed to update location") return validate.NewRequestError(err, http.StatusInternalServerError) } return server.Respond(w, http.StatusOK, result) case http.MethodDelete: - err = ctrl.svc.Location.Delete(r.Context(), ctx.GID, ID) + err = ctrl.repo.Locations.DeleteByGroup(r.Context(), ctx.GID, ID) if err != nil { log.Err(err).Msg("failed to delete location") return validate.NewRequestError(err, http.StatusInternalServerError) diff --git a/backend/app/api/handlers/v1/v1_ctrl_user.go b/backend/app/api/handlers/v1/v1_ctrl_user.go index b7bf5ee..565a723 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_user.go +++ b/backend/app/api/handlers/v1/v1_ctrl_user.go @@ -4,8 +4,8 @@ import ( "net/http" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/repo" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog/log" diff --git a/backend/app/api/logger.go b/backend/app/api/logger.go index 86085a5..ddc574f 100644 --- a/backend/app/api/logger.go +++ b/backend/app/api/logger.go @@ -4,7 +4,7 @@ import ( "os" "strings" - "github.com/hay-kot/homebox/backend/internal/config" + "github.com/hay-kot/homebox/backend/internal/sys/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 e48ae04..c62d5df 100644 --- a/backend/app/api/main.go +++ b/backend/app/api/main.go @@ -10,11 +10,11 @@ import ( atlas "ariga.io/atlas/sql/migrate" "entgo.io/ent/dialect/sql/schema" "github.com/hay-kot/homebox/backend/app/api/static/docs" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/internal/config" - "github.com/hay-kot/homebox/backend/internal/migrations" - "github.com/hay-kot/homebox/backend/internal/repo" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/migrations" + "github.com/hay-kot/homebox/backend/internal/data/repo" + "github.com/hay-kot/homebox/backend/internal/sys/config" "github.com/hay-kot/homebox/backend/internal/web/mid" "github.com/hay-kot/homebox/backend/pkgs/server" _ "github.com/mattn/go-sqlite3" diff --git a/backend/app/api/middleware.go b/backend/app/api/middleware.go index 68bfde1..505ba40 100644 --- a/backend/app/api/middleware.go +++ b/backend/app/api/middleware.go @@ -5,7 +5,7 @@ import ( "net/http" "strings" - "github.com/hay-kot/homebox/backend/internal/services" + "github.com/hay-kot/homebox/backend/internal/core/services" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" ) diff --git a/backend/app/api/routes.go b/backend/app/api/routes.go index 02a7f74..9074838 100644 --- a/backend/app/api/routes.go +++ b/backend/app/api/routes.go @@ -13,7 +13,7 @@ import ( "github.com/hay-kot/homebox/backend/app/api/handlers/debughandlers" v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1" _ "github.com/hay-kot/homebox/backend/app/api/static/docs" - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/pkgs/server" httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware ) @@ -49,6 +49,7 @@ func (a *app) mountRoutes(repos *repo.AllRepos) { v1Ctrl := v1.NewControllerV1( a.services, + a.repos, v1.WithMaxUploadSize(a.conf.Web.MaxUploadSize), v1.WithRegistration(a.conf.AllowRegistration), v1.WithDemoStatus(a.conf.Demo), // Disable Password Change in Demo Mode diff --git a/backend/app/migrations/main.go b/backend/app/tools/migrations/main.go similarity index 90% rename from backend/app/migrations/main.go rename to backend/app/tools/migrations/main.go index bcbb0dd..a2f6624 100644 --- a/backend/app/migrations/main.go +++ b/backend/app/tools/migrations/main.go @@ -5,7 +5,7 @@ import ( "log" "os" - "github.com/hay-kot/homebox/backend/ent/migrate" + "github.com/hay-kot/homebox/backend/internal/data/ent/migrate" atlas "ariga.io/atlas/sql/migrate" _ "ariga.io/atlas/sql/sqlite" @@ -17,7 +17,7 @@ import ( func main() { ctx := context.Background() // Create a local migration directory able to understand Atlas migration file format for replay. - dir, err := atlas.NewLocalDir("internal/migrations/migrations") + dir, err := atlas.NewLocalDir("internal/data/migrations/migrations") if err != nil { log.Fatalf("failed creating atlas migration directory: %v", err) } diff --git a/backend/go.mod b/backend/go.mod index d9d7116..3127969 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -7,6 +7,7 @@ require ( entgo.io/ent v0.11.3 github.com/ardanlabs/conf/v2 v2.2.0 github.com/go-chi/chi/v5 v5.0.7 + github.com/go-playground/validator/v10 v10.11.1 github.com/google/uuid v1.3.0 github.com/mattn/go-sqlite3 v1.14.16 github.com/rs/zerolog v1.28.0 @@ -26,10 +27,12 @@ require ( github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/spec v0.20.7 // indirect github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-playground/locales v0.14.0 // indirect + github.com/go-playground/universal-translator v0.18.0 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/hashicorp/hcl/v2 v2.14.1 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/kr/pretty v0.3.0 // indirect + github.com/leodido/go-urn v1.2.1 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.16 // indirect diff --git a/backend/go.sum b/backend/go.sum index 3510f5d..a16fd64 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -31,6 +31,14 @@ github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= +github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -43,6 +51,7 @@ github.com/hashicorp/hcl/v2 v2.14.1/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0z github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -50,6 +59,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4= +github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= @@ -61,25 +72,32 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= @@ -92,16 +110,20 @@ github.com/swaggo/swag v1.8.7 h1:2K9ivTD3teEO+2fXV6zrZKDqk5IuU2aJtBDo8U7omWU= github.com/swaggo/swag v1.8.7/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk= github.com/zclconf/go-cty v1.11.0 h1:726SxLdi2SDnjY+BStqB9J1hNp4+2WlzyXLuimibIe0= github.com/zclconf/go-cty v1.11.0/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220923203811-8be639271d50 h1:vKyz8L3zkd+xrMeIaBsQ/MNVPVFSffdaU3ZyYlBGFnI= golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= @@ -117,11 +139,13 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/internal/core/services/all.go b/backend/internal/core/services/all.go new file mode 100644 index 0000000..5147b8a --- /dev/null +++ b/backend/internal/core/services/all.go @@ -0,0 +1,24 @@ +package services + +import "github.com/hay-kot/homebox/backend/internal/data/repo" + +type AllServices struct { + User *UserService + Group *GroupService + Items *ItemService +} + +func New(repos *repo.AllRepos) *AllServices { + if repos == nil { + panic("repos cannot be nil") + } + + return &AllServices{ + User: &UserService{repos}, + Group: &GroupService{repos}, + Items: &ItemService{ + repo: repos, + at: attachmentTokens{}, + }, + } +} diff --git a/backend/internal/services/contexts.go b/backend/internal/core/services/contexts.go similarity index 96% rename from backend/internal/services/contexts.go rename to backend/internal/core/services/contexts.go index 72ef84f..d82dcfa 100644 --- a/backend/internal/services/contexts.go +++ b/backend/internal/core/services/contexts.go @@ -4,7 +4,7 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/repo" ) type contextKeys struct { diff --git a/backend/internal/services/contexts_test.go b/backend/internal/core/services/contexts_test.go similarity index 92% rename from backend/internal/services/contexts_test.go rename to backend/internal/core/services/contexts_test.go index 2462258..8b7dfa4 100644 --- a/backend/internal/services/contexts_test.go +++ b/backend/internal/core/services/contexts_test.go @@ -5,7 +5,7 @@ import ( "testing" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/services/main_test.go b/backend/internal/core/services/main_test.go similarity index 92% rename from backend/internal/services/main_test.go rename to backend/internal/core/services/main_test.go index 37cb556..e1f7282 100644 --- a/backend/internal/services/main_test.go +++ b/backend/internal/core/services/main_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/pkgs/faker" _ "github.com/mattn/go-sqlite3" ) diff --git a/backend/internal/services/service_group.go b/backend/internal/core/services/service_group.go similarity index 77% rename from backend/internal/services/service_group.go rename to backend/internal/core/services/service_group.go index 4859f85..2ca3f86 100644 --- a/backend/internal/services/service_group.go +++ b/backend/internal/core/services/service_group.go @@ -2,10 +2,9 @@ package services import ( "errors" - "strings" "time" - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/pkgs/hasher" ) @@ -13,10 +12,6 @@ type GroupService struct { repos *repo.AllRepos } -func (svc *GroupService) Get(ctx Context) (repo.Group, error) { - return svc.repos.Groups.GroupByID(ctx.Context, ctx.GID) -} - func (svc *GroupService) UpdateGroup(ctx Context, data repo.GroupUpdate) (repo.Group, error) { if data.Name == "" { data.Name = ctx.User.GroupName @@ -26,8 +21,6 @@ func (svc *GroupService) UpdateGroup(ctx Context, data repo.GroupUpdate) (repo.G return repo.Group{}, errors.New("currency cannot be empty") } - data.Currency = strings.ToLower(data.Currency) - return svc.repos.Groups.GroupUpdate(ctx.Context, ctx.GID, data) } diff --git a/backend/internal/services/service_items.go b/backend/internal/core/services/service_items.go similarity index 80% rename from backend/internal/services/service_items.go rename to backend/internal/core/services/service_items.go index 7650a97..5c02724 100644 --- a/backend/internal/services/service_items.go +++ b/backend/internal/core/services/service_items.go @@ -5,7 +5,7 @@ import ( "errors" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/rs/zerolog/log" ) @@ -23,30 +23,6 @@ type ItemService struct { at attachmentTokens } -func (svc *ItemService) GetOne(ctx context.Context, gid uuid.UUID, id uuid.UUID) (repo.ItemOut, error) { - return svc.repo.Items.GetOneByGroup(ctx, gid, id) -} - -func (svc *ItemService) Query(ctx Context, q repo.ItemQuery) (repo.PaginationResult[repo.ItemSummary], error) { - return svc.repo.Items.QueryByGroup(ctx, ctx.GID, q) -} - -func (svc *ItemService) GetAll(ctx context.Context, gid uuid.UUID) ([]repo.ItemSummary, error) { - return svc.repo.Items.GetAll(ctx, gid) -} - -func (svc *ItemService) Create(ctx context.Context, gid uuid.UUID, data repo.ItemCreate) (repo.ItemOut, error) { - return svc.repo.Items.Create(ctx, gid, data) -} - -func (svc *ItemService) Delete(ctx context.Context, gid uuid.UUID, id uuid.UUID) error { - return svc.repo.Items.DeleteByGroup(ctx, gid, id) -} - -func (svc *ItemService) Update(ctx context.Context, gid uuid.UUID, data repo.ItemUpdate) (repo.ItemOut, error) { - return svc.repo.Items.UpdateByGroup(ctx, gid, data) -} - func (svc *ItemService) CsvImport(ctx context.Context, gid uuid.UUID, data [][]string) (int, error) { loaded := []csvRow{} diff --git a/backend/internal/services/service_items_attachments.go b/backend/internal/core/services/service_items_attachments.go similarity index 92% rename from backend/internal/services/service_items_attachments.go rename to backend/internal/core/services/service_items_attachments.go index 0f2afde..b5df5f8 100644 --- a/backend/internal/services/service_items_attachments.go +++ b/backend/internal/core/services/service_items_attachments.go @@ -7,9 +7,9 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/ent/attachment" - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/pkgs/hasher" "github.com/rs/zerolog/log" ) @@ -91,7 +91,7 @@ func (svc *ItemService) AttachmentUpdate(ctx Context, itemId uuid.UUID, data *re return repo.ItemOut{}, err } - return svc.GetOne(ctx, ctx.GID, itemId) + return svc.repo.Items.GetOneByGroup(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 @@ -118,7 +118,7 @@ func (svc *ItemService) AttachmentAdd(ctx Context, itemId uuid.UUID, filename st return repo.ItemOut{}, err } - return svc.GetOne(ctx, ctx.GID, itemId) + return svc.repo.Items.GetOneByGroup(ctx, ctx.GID, itemId) } func (svc *ItemService) AttachmentDelete(ctx context.Context, gid, itemId, attachmentId uuid.UUID) error { diff --git a/backend/internal/services/service_items_attachments_test.go b/backend/internal/core/services/service_items_attachments_test.go similarity index 84% rename from backend/internal/services/service_items_attachments_test.go rename to backend/internal/core/services/service_items_attachments_test.go index c3ab032..14e822e 100644 --- a/backend/internal/services/service_items_attachments_test.go +++ b/backend/internal/core/services/service_items_attachments_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/stretchr/testify/assert" ) @@ -19,7 +19,7 @@ func TestItemService_AddAttachment(t *testing.T) { filepath: temp, } - loc, err := tSvc.Location.Create(context.Background(), tGroup.ID, repo.LocationCreate{ + loc, err := tRepos.Locations.Create(context.Background(), tGroup.ID, repo.LocationCreate{ Description: "test", Name: "test", }) @@ -32,7 +32,7 @@ func TestItemService_AddAttachment(t *testing.T) { LocationID: loc.ID, } - itm, err := svc.Create(context.Background(), tGroup.ID, itmC) + itm, err := svc.repo.Items.Create(context.Background(), tGroup.ID, itmC) assert.NoError(t, err) assert.NotNil(t, itm) t.Cleanup(func() { diff --git a/backend/internal/services/service_items_csv.go b/backend/internal/core/services/service_items_csv.go similarity index 97% rename from backend/internal/services/service_items_csv.go rename to backend/internal/core/services/service_items_csv.go index c559386..c9748f7 100644 --- a/backend/internal/services/service_items_csv.go +++ b/backend/internal/core/services/service_items_csv.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/repo" ) var ErrInvalidCsv = errors.New("invalid csv") diff --git a/backend/internal/services/service_items_csv_test.go b/backend/internal/core/services/service_items_csv_test.go similarity index 100% rename from backend/internal/services/service_items_csv_test.go rename to backend/internal/core/services/service_items_csv_test.go diff --git a/backend/internal/services/service_items_test.go b/backend/internal/core/services/service_items_test.go similarity index 83% rename from backend/internal/services/service_items_test.go rename to backend/internal/core/services/service_items_test.go index 018dbc1..1daa0b7 100644 --- a/backend/internal/services/service_items_test.go +++ b/backend/internal/core/services/service_items_test.go @@ -22,7 +22,7 @@ func TestItemService_CsvImport(t *testing.T) { assert.Equal(t, 0, count) assert.NoError(t, err) - items, err := svc.GetAll(context.Background(), tGroup.ID) + items, err := svc.repo.Items.GetAll(context.Background(), tGroup.ID) assert.NoError(t, err) t.Cleanup(func() { for _, item := range items { @@ -38,22 +38,14 @@ func TestItemService_CsvImport(t *testing.T) { dataCsv = append(dataCsv, newCsvRow(item)) } - locationService := &LocationService{ - repos: tRepos, - } - - LabelService := &LabelService{ - repos: tRepos, - } - - allLocation, err := locationService.GetAll(context.Background(), tGroup.ID) + allLocation, err := tRepos.Locations.GetAll(context.Background(), tGroup.ID) assert.NoError(t, err) locNames := []string{} for _, loc := range allLocation { locNames = append(locNames, loc.Name) } - allLabels, err := LabelService.GetAll(context.Background(), tGroup.ID) + allLabels, err := tRepos.Labels.GetAll(context.Background(), tGroup.ID) assert.NoError(t, err) labelNames := []string{} for _, label := range allLabels { diff --git a/backend/internal/services/service_user.go b/backend/internal/core/services/service_user.go similarity index 99% rename from backend/internal/services/service_user.go rename to backend/internal/core/services/service_user.go index 3060ee7..e3d8f8a 100644 --- a/backend/internal/services/service_user.go +++ b/backend/internal/core/services/service_user.go @@ -6,7 +6,7 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/repo" "github.com/hay-kot/homebox/backend/pkgs/hasher" "github.com/rs/zerolog/log" ) diff --git a/backend/internal/services/service_user_defaults.go b/backend/internal/core/services/service_user_defaults.go similarity index 91% rename from backend/internal/services/service_user_defaults.go rename to backend/internal/core/services/service_user_defaults.go index 9882d5e..34344d1 100644 --- a/backend/internal/services/service_user_defaults.go +++ b/backend/internal/core/services/service_user_defaults.go @@ -1,7 +1,7 @@ package services import ( - "github.com/hay-kot/homebox/backend/internal/repo" + "github.com/hay-kot/homebox/backend/internal/data/repo" ) func defaultLocations() []repo.LocationCreate { diff --git a/backend/ent/attachment.go b/backend/internal/data/ent/attachment.go similarity index 97% rename from backend/ent/attachment.go rename to backend/internal/data/ent/attachment.go index e65f1e2..e5f738a 100644 --- a/backend/ent/attachment.go +++ b/backend/internal/data/ent/attachment.go @@ -9,9 +9,9 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "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/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" ) // Attachment is the model entity for the Attachment schema. diff --git a/backend/ent/attachment/attachment.go b/backend/internal/data/ent/attachment/attachment.go similarity index 100% rename from backend/ent/attachment/attachment.go rename to backend/internal/data/ent/attachment/attachment.go diff --git a/backend/ent/attachment/where.go b/backend/internal/data/ent/attachment/where.go similarity index 99% rename from backend/ent/attachment/where.go rename to backend/internal/data/ent/attachment/where.go index 28b806e..e2adb4f 100644 --- a/backend/ent/attachment/where.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/attachment_create.go b/backend/internal/data/ent/attachment_create.go similarity index 98% rename from backend/ent/attachment_create.go rename to backend/internal/data/ent/attachment_create.go index 75d6cec..8725984 100644 --- a/backend/ent/attachment_create.go +++ b/backend/internal/data/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/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/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" ) // AttachmentCreate is the builder for creating a Attachment entity. diff --git a/backend/ent/attachment_delete.go b/backend/internal/data/ent/attachment_delete.go similarity index 95% rename from backend/ent/attachment_delete.go rename to backend/internal/data/ent/attachment_delete.go index a1cda49..eeeca20 100644 --- a/backend/ent/attachment_delete.go +++ b/backend/internal/data/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/homebox/backend/ent/attachment" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // AttachmentDelete is the builder for deleting a Attachment entity. diff --git a/backend/ent/attachment_query.go b/backend/internal/data/ent/attachment_query.go similarity index 98% rename from backend/ent/attachment_query.go rename to backend/internal/data/ent/attachment_query.go index 5554bfb..2262c0b 100644 --- a/backend/ent/attachment_query.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // AttachmentQuery is the builder for querying Attachment entities. diff --git a/backend/ent/attachment_update.go b/backend/internal/data/ent/attachment_update.go similarity index 98% rename from backend/ent/attachment_update.go rename to backend/internal/data/ent/attachment_update.go index 1801c22..fbaf485 100644 --- a/backend/ent/attachment_update.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // AttachmentUpdate is the builder for updating Attachment entities. diff --git a/backend/ent/authtokens.go b/backend/internal/data/ent/authtokens.go similarity index 97% rename from backend/ent/authtokens.go rename to backend/internal/data/ent/authtokens.go index 285412f..6e8e53d 100644 --- a/backend/ent/authtokens.go +++ b/backend/internal/data/ent/authtokens.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/authtokens" - "github.com/hay-kot/homebox/backend/ent/user" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // AuthTokens is the model entity for the AuthTokens schema. diff --git a/backend/ent/authtokens/authtokens.go b/backend/internal/data/ent/authtokens/authtokens.go similarity index 100% rename from backend/ent/authtokens/authtokens.go rename to backend/internal/data/ent/authtokens/authtokens.go diff --git a/backend/ent/authtokens/where.go b/backend/internal/data/ent/authtokens/where.go similarity index 99% rename from backend/ent/authtokens/where.go rename to backend/internal/data/ent/authtokens/where.go index d54ebdd..5ef7df9 100644 --- a/backend/ent/authtokens/where.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/authtokens_create.go b/backend/internal/data/ent/authtokens_create.go similarity index 98% rename from backend/ent/authtokens_create.go rename to backend/internal/data/ent/authtokens_create.go index 491711a..e05e849 100644 --- a/backend/ent/authtokens_create.go +++ b/backend/internal/data/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/homebox/backend/ent/authtokens" - "github.com/hay-kot/homebox/backend/ent/user" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // AuthTokensCreate is the builder for creating a AuthTokens entity. diff --git a/backend/ent/authtokens_delete.go b/backend/internal/data/ent/authtokens_delete.go similarity index 95% rename from backend/ent/authtokens_delete.go rename to backend/internal/data/ent/authtokens_delete.go index 7b86122..5041362 100644 --- a/backend/ent/authtokens_delete.go +++ b/backend/internal/data/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/homebox/backend/ent/authtokens" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // AuthTokensDelete is the builder for deleting a AuthTokens entity. diff --git a/backend/ent/authtokens_query.go b/backend/internal/data/ent/authtokens_query.go similarity index 98% rename from backend/ent/authtokens_query.go rename to backend/internal/data/ent/authtokens_query.go index 672a368..77c13e2 100644 --- a/backend/ent/authtokens_query.go +++ b/backend/internal/data/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/homebox/backend/ent/authtokens" - "github.com/hay-kot/homebox/backend/ent/predicate" - "github.com/hay-kot/homebox/backend/ent/user" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // AuthTokensQuery is the builder for querying AuthTokens entities. diff --git a/backend/ent/authtokens_update.go b/backend/internal/data/ent/authtokens_update.go similarity index 98% rename from backend/ent/authtokens_update.go rename to backend/internal/data/ent/authtokens_update.go index 11e06f2..7d7c541 100644 --- a/backend/ent/authtokens_update.go +++ b/backend/internal/data/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/homebox/backend/ent/authtokens" - "github.com/hay-kot/homebox/backend/ent/predicate" - "github.com/hay-kot/homebox/backend/ent/user" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // AuthTokensUpdate is the builder for updating AuthTokens entities. diff --git a/backend/ent/client.go b/backend/internal/data/ent/client.go similarity index 98% rename from backend/ent/client.go rename to backend/internal/data/ent/client.go index a9a8168..8273e32 100644 --- a/backend/ent/client.go +++ b/backend/internal/data/ent/client.go @@ -9,19 +9,19 @@ import ( "log" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/migrate" + "github.com/hay-kot/homebox/backend/internal/data/ent/migrate" - "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/groupinvitationtoken" - "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" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" "entgo.io/ent/dialect" "entgo.io/ent/dialect/sql" diff --git a/backend/ent/config.go b/backend/internal/data/ent/config.go similarity index 100% rename from backend/ent/config.go rename to backend/internal/data/ent/config.go diff --git a/backend/ent/context.go b/backend/internal/data/ent/context.go similarity index 100% rename from backend/ent/context.go rename to backend/internal/data/ent/context.go diff --git a/backend/ent/document.go b/backend/internal/data/ent/document.go similarity index 98% rename from backend/ent/document.go rename to backend/internal/data/ent/document.go index bfc552e..0c84d7d 100644 --- a/backend/ent/document.go +++ b/backend/internal/data/ent/document.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/document" - "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" ) // Document is the model entity for the Document schema. diff --git a/backend/ent/document/document.go b/backend/internal/data/ent/document/document.go similarity index 100% rename from backend/ent/document/document.go rename to backend/internal/data/ent/document/document.go diff --git a/backend/ent/document/where.go b/backend/internal/data/ent/document/where.go similarity index 99% rename from backend/ent/document/where.go rename to backend/internal/data/ent/document/where.go index 0cb7139..dc02fa4 100644 --- a/backend/ent/document/where.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/document_create.go b/backend/internal/data/ent/document_create.go similarity index 97% rename from backend/ent/document_create.go rename to backend/internal/data/ent/document_create.go index 4411e16..b6577df 100644 --- a/backend/ent/document_create.go +++ b/backend/internal/data/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/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/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" ) // DocumentCreate is the builder for creating a Document entity. diff --git a/backend/ent/document_delete.go b/backend/internal/data/ent/document_delete.go similarity index 95% rename from backend/ent/document_delete.go rename to backend/internal/data/ent/document_delete.go index 06ccaf1..6e21bef 100644 --- a/backend/ent/document_delete.go +++ b/backend/internal/data/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/homebox/backend/ent/document" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // DocumentDelete is the builder for deleting a Document entity. diff --git a/backend/ent/document_query.go b/backend/internal/data/ent/document_query.go similarity index 98% rename from backend/ent/document_query.go rename to backend/internal/data/ent/document_query.go index fe439af..7505152 100644 --- a/backend/ent/document_query.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // DocumentQuery is the builder for querying Document entities. diff --git a/backend/ent/document_update.go b/backend/internal/data/ent/document_update.go similarity index 98% rename from backend/ent/document_update.go rename to backend/internal/data/ent/document_update.go index fb1b971..c6dd9fe 100644 --- a/backend/ent/document_update.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // DocumentUpdate is the builder for updating Document entities. diff --git a/backend/ent/documenttoken.go b/backend/internal/data/ent/documenttoken.go similarity index 97% rename from backend/ent/documenttoken.go rename to backend/internal/data/ent/documenttoken.go index f42a40f..c484a9e 100644 --- a/backend/ent/documenttoken.go +++ b/backend/internal/data/ent/documenttoken.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/document" - "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" ) // DocumentToken is the model entity for the DocumentToken schema. diff --git a/backend/ent/documenttoken/documenttoken.go b/backend/internal/data/ent/documenttoken/documenttoken.go similarity index 100% rename from backend/ent/documenttoken/documenttoken.go rename to backend/internal/data/ent/documenttoken/documenttoken.go diff --git a/backend/ent/documenttoken/where.go b/backend/internal/data/ent/documenttoken/where.go similarity index 99% rename from backend/ent/documenttoken/where.go rename to backend/internal/data/ent/documenttoken/where.go index 1d0949a..32dbb39 100644 --- a/backend/ent/documenttoken/where.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/documenttoken_create.go b/backend/internal/data/ent/documenttoken_create.go similarity index 98% rename from backend/ent/documenttoken_create.go rename to backend/internal/data/ent/documenttoken_create.go index b4585d5..2b29079 100644 --- a/backend/ent/documenttoken_create.go +++ b/backend/internal/data/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/homebox/backend/ent/document" - "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" ) // DocumentTokenCreate is the builder for creating a DocumentToken entity. diff --git a/backend/ent/documenttoken_delete.go b/backend/internal/data/ent/documenttoken_delete.go similarity index 95% rename from backend/ent/documenttoken_delete.go rename to backend/internal/data/ent/documenttoken_delete.go index fa9b7a1..722ec1b 100644 --- a/backend/ent/documenttoken_delete.go +++ b/backend/internal/data/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/homebox/backend/ent/documenttoken" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // DocumentTokenDelete is the builder for deleting a DocumentToken entity. diff --git a/backend/ent/documenttoken_query.go b/backend/internal/data/ent/documenttoken_query.go similarity index 98% rename from backend/ent/documenttoken_query.go rename to backend/internal/data/ent/documenttoken_query.go index a8f264e..6c5386c 100644 --- a/backend/ent/documenttoken_query.go +++ b/backend/internal/data/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/homebox/backend/ent/document" - "github.com/hay-kot/homebox/backend/ent/documenttoken" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // DocumentTokenQuery is the builder for querying DocumentToken entities. diff --git a/backend/ent/documenttoken_update.go b/backend/internal/data/ent/documenttoken_update.go similarity index 98% rename from backend/ent/documenttoken_update.go rename to backend/internal/data/ent/documenttoken_update.go index dc77dcc..c6b5e77 100644 --- a/backend/ent/documenttoken_update.go +++ b/backend/internal/data/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/homebox/backend/ent/document" - "github.com/hay-kot/homebox/backend/ent/documenttoken" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // DocumentTokenUpdate is the builder for updating DocumentToken entities. diff --git a/backend/ent/ent.go b/backend/internal/data/ent/ent.go similarity index 94% rename from backend/ent/ent.go rename to backend/internal/data/ent/ent.go index 66676f3..e2552db 100644 --- a/backend/ent/ent.go +++ b/backend/internal/data/ent/ent.go @@ -10,17 +10,17 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/sql" "entgo.io/ent/dialect/sql/sqlgraph" - "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/groupinvitationtoken" - "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" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // ent aliases to avoid import conflicts in user's code. diff --git a/backend/ent/enttest/enttest.go b/backend/internal/data/ent/enttest/enttest.go similarity index 90% rename from backend/ent/enttest/enttest.go rename to backend/internal/data/ent/enttest/enttest.go index f39fc09..495bddb 100644 --- a/backend/ent/enttest/enttest.go +++ b/backend/internal/data/ent/enttest/enttest.go @@ -5,12 +5,12 @@ package enttest import ( "context" - "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent" // required by schema hooks. - _ "github.com/hay-kot/homebox/backend/ent/runtime" + _ "github.com/hay-kot/homebox/backend/internal/data/ent/runtime" "entgo.io/ent/dialect/sql/schema" - "github.com/hay-kot/homebox/backend/ent/migrate" + "github.com/hay-kot/homebox/backend/internal/data/ent/migrate" ) type ( diff --git a/backend/ent/external.go b/backend/internal/data/ent/external.go similarity index 100% rename from backend/ent/external.go rename to backend/internal/data/ent/external.go diff --git a/backend/ent/generate.go b/backend/internal/data/ent/generate.go similarity index 100% rename from backend/ent/generate.go rename to backend/internal/data/ent/generate.go diff --git a/backend/ent/group.go b/backend/internal/data/ent/group.go similarity index 99% rename from backend/ent/group.go rename to backend/internal/data/ent/group.go index 814560c..8140104 100644 --- a/backend/ent/group.go +++ b/backend/internal/data/ent/group.go @@ -9,7 +9,7 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" ) // Group is the model entity for the Group schema. diff --git a/backend/ent/group/group.go b/backend/internal/data/ent/group/group.go similarity index 100% rename from backend/ent/group/group.go rename to backend/internal/data/ent/group/group.go diff --git a/backend/ent/group/where.go b/backend/internal/data/ent/group/where.go similarity index 99% rename from backend/ent/group/where.go rename to backend/internal/data/ent/group/where.go index b95fef7..62106cc 100644 --- a/backend/ent/group/where.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/group_create.go b/backend/internal/data/ent/group_create.go similarity index 97% rename from backend/ent/group_create.go rename to backend/internal/data/ent/group_create.go index cdb4619..37ca739 100644 --- a/backend/ent/group_create.go +++ b/backend/internal/data/ent/group_create.go @@ -11,13 +11,13 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/document" - "github.com/hay-kot/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/groupinvitationtoken" - "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" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // GroupCreate is the builder for creating a Group entity. diff --git a/backend/ent/group_delete.go b/backend/internal/data/ent/group_delete.go similarity index 95% rename from backend/ent/group_delete.go rename to backend/internal/data/ent/group_delete.go index 23dfa0c..4bcefc8 100644 --- a/backend/ent/group_delete.go +++ b/backend/internal/data/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/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // GroupDelete is the builder for deleting a Group entity. diff --git a/backend/ent/group_query.go b/backend/internal/data/ent/group_query.go similarity index 98% rename from backend/ent/group_query.go rename to backend/internal/data/ent/group_query.go index 13bfd9b..796f81d 100644 --- a/backend/ent/group_query.go +++ b/backend/internal/data/ent/group_query.go @@ -12,14 +12,14 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/document" - "github.com/hay-kot/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/groupinvitationtoken" - "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" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // GroupQuery is the builder for querying Group entities. diff --git a/backend/ent/group_update.go b/backend/internal/data/ent/group_update.go similarity index 98% rename from backend/ent/group_update.go rename to backend/internal/data/ent/group_update.go index 6400c1b..bc4dbf9 100644 --- a/backend/ent/group_update.go +++ b/backend/internal/data/ent/group_update.go @@ -12,14 +12,14 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/document" - "github.com/hay-kot/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/groupinvitationtoken" - "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" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // GroupUpdate is the builder for updating Group entities. diff --git a/backend/ent/groupinvitationtoken.go b/backend/internal/data/ent/groupinvitationtoken.go similarity index 98% rename from backend/ent/groupinvitationtoken.go rename to backend/internal/data/ent/groupinvitationtoken.go index 50346d8..248e40f 100644 --- a/backend/ent/groupinvitationtoken.go +++ b/backend/internal/data/ent/groupinvitationtoken.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" ) // GroupInvitationToken is the model entity for the GroupInvitationToken schema. diff --git a/backend/ent/groupinvitationtoken/groupinvitationtoken.go b/backend/internal/data/ent/groupinvitationtoken/groupinvitationtoken.go similarity index 100% rename from backend/ent/groupinvitationtoken/groupinvitationtoken.go rename to backend/internal/data/ent/groupinvitationtoken/groupinvitationtoken.go diff --git a/backend/ent/groupinvitationtoken/where.go b/backend/internal/data/ent/groupinvitationtoken/where.go similarity index 99% rename from backend/ent/groupinvitationtoken/where.go rename to backend/internal/data/ent/groupinvitationtoken/where.go index a613e6a..bf4ccaa 100644 --- a/backend/ent/groupinvitationtoken/where.go +++ b/backend/internal/data/ent/groupinvitationtoken/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/groupinvitationtoken_create.go b/backend/internal/data/ent/groupinvitationtoken_create.go similarity index 98% rename from backend/ent/groupinvitationtoken_create.go rename to backend/internal/data/ent/groupinvitationtoken_create.go index b36d623..34a3f48 100644 --- a/backend/ent/groupinvitationtoken_create.go +++ b/backend/internal/data/ent/groupinvitationtoken_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/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" ) // GroupInvitationTokenCreate is the builder for creating a GroupInvitationToken entity. diff --git a/backend/ent/groupinvitationtoken_delete.go b/backend/internal/data/ent/groupinvitationtoken_delete.go similarity index 95% rename from backend/ent/groupinvitationtoken_delete.go rename to backend/internal/data/ent/groupinvitationtoken_delete.go index 42fad8b..4fa2ceb 100644 --- a/backend/ent/groupinvitationtoken_delete.go +++ b/backend/internal/data/ent/groupinvitationtoken_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/homebox/backend/ent/groupinvitationtoken" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // GroupInvitationTokenDelete is the builder for deleting a GroupInvitationToken entity. diff --git a/backend/ent/groupinvitationtoken_query.go b/backend/internal/data/ent/groupinvitationtoken_query.go similarity index 98% rename from backend/ent/groupinvitationtoken_query.go rename to backend/internal/data/ent/groupinvitationtoken_query.go index ea380b0..4e8536b 100644 --- a/backend/ent/groupinvitationtoken_query.go +++ b/backend/internal/data/ent/groupinvitationtoken_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/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/groupinvitationtoken" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // GroupInvitationTokenQuery is the builder for querying GroupInvitationToken entities. diff --git a/backend/ent/groupinvitationtoken_update.go b/backend/internal/data/ent/groupinvitationtoken_update.go similarity index 98% rename from backend/ent/groupinvitationtoken_update.go rename to backend/internal/data/ent/groupinvitationtoken_update.go index 3459c4e..33cbef2 100644 --- a/backend/ent/groupinvitationtoken_update.go +++ b/backend/internal/data/ent/groupinvitationtoken_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/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/groupinvitationtoken" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // GroupInvitationTokenUpdate is the builder for updating GroupInvitationToken entities. diff --git a/backend/ent/has_id.go b/backend/internal/data/ent/has_id.go similarity index 100% rename from backend/ent/has_id.go rename to backend/internal/data/ent/has_id.go diff --git a/backend/ent/hook/hook.go b/backend/internal/data/ent/hook/hook.go similarity index 99% rename from backend/ent/hook/hook.go rename to backend/internal/data/ent/hook/hook.go index 0fbd6d1..c0a7378 100644 --- a/backend/ent/hook/hook.go +++ b/backend/internal/data/ent/hook/hook.go @@ -6,7 +6,7 @@ import ( "context" "fmt" - "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent" ) // The AttachmentFunc type is an adapter to allow the use of ordinary diff --git a/backend/ent/item.go b/backend/internal/data/ent/item.go similarity index 98% rename from backend/ent/item.go rename to backend/internal/data/ent/item.go index c1b1eff..d9d66b4 100644 --- a/backend/ent/item.go +++ b/backend/internal/data/ent/item.go @@ -9,9 +9,9 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "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/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" ) // Item is the model entity for the Item schema. diff --git a/backend/ent/item/item.go b/backend/internal/data/ent/item/item.go similarity index 100% rename from backend/ent/item/item.go rename to backend/internal/data/ent/item/item.go diff --git a/backend/ent/item/where.go b/backend/internal/data/ent/item/where.go similarity index 99% rename from backend/ent/item/where.go rename to backend/internal/data/ent/item/where.go index ec74275..cb4b0d9 100644 --- a/backend/ent/item/where.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/item_create.go b/backend/internal/data/ent/item_create.go similarity index 98% rename from backend/ent/item_create.go rename to backend/internal/data/ent/item_create.go index 6134705..5b0842d 100644 --- a/backend/ent/item_create.go +++ b/backend/internal/data/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/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/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" ) // ItemCreate is the builder for creating a Item entity. diff --git a/backend/ent/item_delete.go b/backend/internal/data/ent/item_delete.go similarity index 95% rename from backend/ent/item_delete.go rename to backend/internal/data/ent/item_delete.go index 1f8b6f8..56b7e03 100644 --- a/backend/ent/item_delete.go +++ b/backend/internal/data/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/homebox/backend/ent/item" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ItemDelete is the builder for deleting a Item entity. diff --git a/backend/ent/item_query.go b/backend/internal/data/ent/item_query.go similarity index 98% rename from backend/ent/item_query.go rename to backend/internal/data/ent/item_query.go index e6d1173..fba0917 100644 --- a/backend/ent/item_query.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ItemQuery is the builder for querying Item entities. diff --git a/backend/ent/item_update.go b/backend/internal/data/ent/item_update.go similarity index 99% rename from backend/ent/item_update.go rename to backend/internal/data/ent/item_update.go index 5b08da7..86dd6dd 100644 --- a/backend/ent/item_update.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ItemUpdate is the builder for updating Item entities. diff --git a/backend/ent/itemfield.go b/backend/internal/data/ent/itemfield.go similarity index 98% rename from backend/ent/itemfield.go rename to backend/internal/data/ent/itemfield.go index 84db86d..be68023 100644 --- a/backend/ent/itemfield.go +++ b/backend/internal/data/ent/itemfield.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/item" - "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" ) // ItemField is the model entity for the ItemField schema. diff --git a/backend/ent/itemfield/itemfield.go b/backend/internal/data/ent/itemfield/itemfield.go similarity index 100% rename from backend/ent/itemfield/itemfield.go rename to backend/internal/data/ent/itemfield/itemfield.go diff --git a/backend/ent/itemfield/where.go b/backend/internal/data/ent/itemfield/where.go similarity index 99% rename from backend/ent/itemfield/where.go rename to backend/internal/data/ent/itemfield/where.go index 39c2734..2af2d7a 100644 --- a/backend/ent/itemfield/where.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/itemfield_create.go b/backend/internal/data/ent/itemfield_create.go similarity index 99% rename from backend/ent/itemfield_create.go rename to backend/internal/data/ent/itemfield_create.go index ad9fd96..2a00749 100644 --- a/backend/ent/itemfield_create.go +++ b/backend/internal/data/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/homebox/backend/ent/item" - "github.com/hay-kot/homebox/backend/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" ) // ItemFieldCreate is the builder for creating a ItemField entity. diff --git a/backend/ent/itemfield_delete.go b/backend/internal/data/ent/itemfield_delete.go similarity index 95% rename from backend/ent/itemfield_delete.go rename to backend/internal/data/ent/itemfield_delete.go index e5ba38f..e1933d6 100644 --- a/backend/ent/itemfield_delete.go +++ b/backend/internal/data/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/homebox/backend/ent/itemfield" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ItemFieldDelete is the builder for deleting a ItemField entity. diff --git a/backend/ent/itemfield_query.go b/backend/internal/data/ent/itemfield_query.go similarity index 98% rename from backend/ent/itemfield_query.go rename to backend/internal/data/ent/itemfield_query.go index c72441e..fb9a5ea 100644 --- a/backend/ent/itemfield_query.go +++ b/backend/internal/data/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/homebox/backend/ent/item" - "github.com/hay-kot/homebox/backend/ent/itemfield" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ItemFieldQuery is the builder for querying ItemField entities. diff --git a/backend/ent/itemfield_update.go b/backend/internal/data/ent/itemfield_update.go similarity index 99% rename from backend/ent/itemfield_update.go rename to backend/internal/data/ent/itemfield_update.go index cac8fed..6b89324 100644 --- a/backend/ent/itemfield_update.go +++ b/backend/internal/data/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/homebox/backend/ent/item" - "github.com/hay-kot/homebox/backend/ent/itemfield" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ItemFieldUpdate is the builder for updating ItemField entities. diff --git a/backend/ent/label.go b/backend/internal/data/ent/label.go similarity index 98% rename from backend/ent/label.go rename to backend/internal/data/ent/label.go index 73e0714..9e65bfe 100644 --- a/backend/ent/label.go +++ b/backend/internal/data/ent/label.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" ) // Label is the model entity for the Label schema. diff --git a/backend/ent/label/label.go b/backend/internal/data/ent/label/label.go similarity index 100% rename from backend/ent/label/label.go rename to backend/internal/data/ent/label/label.go diff --git a/backend/ent/label/where.go b/backend/internal/data/ent/label/where.go similarity index 99% rename from backend/ent/label/where.go rename to backend/internal/data/ent/label/where.go index 05d24db..9279ee7 100644 --- a/backend/ent/label/where.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/label_create.go b/backend/internal/data/ent/label_create.go similarity index 98% rename from backend/ent/label_create.go rename to backend/internal/data/ent/label_create.go index 7330747..a000e35 100644 --- a/backend/ent/label_create.go +++ b/backend/internal/data/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/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/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" ) // LabelCreate is the builder for creating a Label entity. diff --git a/backend/ent/label_delete.go b/backend/internal/data/ent/label_delete.go similarity index 95% rename from backend/ent/label_delete.go rename to backend/internal/data/ent/label_delete.go index aef8be0..28e103c 100644 --- a/backend/ent/label_delete.go +++ b/backend/internal/data/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/homebox/backend/ent/label" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // LabelDelete is the builder for deleting a Label entity. diff --git a/backend/ent/label_query.go b/backend/internal/data/ent/label_query.go similarity index 98% rename from backend/ent/label_query.go rename to backend/internal/data/ent/label_query.go index 58fa534..fc53ec4 100644 --- a/backend/ent/label_query.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // LabelQuery is the builder for querying Label entities. diff --git a/backend/ent/label_update.go b/backend/internal/data/ent/label_update.go similarity index 98% rename from backend/ent/label_update.go rename to backend/internal/data/ent/label_update.go index ef0af15..16f4a0c 100644 --- a/backend/ent/label_update.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // LabelUpdate is the builder for updating Label entities. diff --git a/backend/ent/location.go b/backend/internal/data/ent/location.go similarity index 98% rename from backend/ent/location.go rename to backend/internal/data/ent/location.go index 337126b..67abd30 100644 --- a/backend/ent/location.go +++ b/backend/internal/data/ent/location.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" ) // Location is the model entity for the Location schema. diff --git a/backend/ent/location/location.go b/backend/internal/data/ent/location/location.go similarity index 100% rename from backend/ent/location/location.go rename to backend/internal/data/ent/location/location.go diff --git a/backend/ent/location/where.go b/backend/internal/data/ent/location/where.go similarity index 99% rename from backend/ent/location/where.go rename to backend/internal/data/ent/location/where.go index 20738b7..73f28bd 100644 --- a/backend/ent/location/where.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/location_create.go b/backend/internal/data/ent/location_create.go similarity index 98% rename from backend/ent/location_create.go rename to backend/internal/data/ent/location_create.go index ceff804..35081c2 100644 --- a/backend/ent/location_create.go +++ b/backend/internal/data/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/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/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" ) // LocationCreate is the builder for creating a Location entity. diff --git a/backend/ent/location_delete.go b/backend/internal/data/ent/location_delete.go similarity index 95% rename from backend/ent/location_delete.go rename to backend/internal/data/ent/location_delete.go index 8bc6db3..7fd8e84 100644 --- a/backend/ent/location_delete.go +++ b/backend/internal/data/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/homebox/backend/ent/location" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // LocationDelete is the builder for deleting a Location entity. diff --git a/backend/ent/location_query.go b/backend/internal/data/ent/location_query.go similarity index 98% rename from backend/ent/location_query.go rename to backend/internal/data/ent/location_query.go index 9cf0b55..ff3014b 100644 --- a/backend/ent/location_query.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // LocationQuery is the builder for querying Location entities. diff --git a/backend/ent/location_update.go b/backend/internal/data/ent/location_update.go similarity index 99% rename from backend/ent/location_update.go rename to backend/internal/data/ent/location_update.go index 785036a..eaeb530 100644 --- a/backend/ent/location_update.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // LocationUpdate is the builder for updating Location entities. diff --git a/backend/ent/migrate/migrate.go b/backend/internal/data/ent/migrate/migrate.go similarity index 100% rename from backend/ent/migrate/migrate.go rename to backend/internal/data/ent/migrate/migrate.go diff --git a/backend/ent/migrate/schema.go b/backend/internal/data/ent/migrate/schema.go similarity index 100% rename from backend/ent/migrate/schema.go rename to backend/internal/data/ent/migrate/schema.go diff --git a/backend/ent/mutation.go b/backend/internal/data/ent/mutation.go similarity index 99% rename from backend/ent/mutation.go rename to backend/internal/data/ent/mutation.go index eb2e853..c245719 100644 --- a/backend/ent/mutation.go +++ b/backend/internal/data/ent/mutation.go @@ -10,18 +10,18 @@ import ( "time" "github.com/google/uuid" - "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/groupinvitationtoken" - "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" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" "entgo.io/ent" ) diff --git a/backend/ent/predicate/predicate.go b/backend/internal/data/ent/predicate/predicate.go similarity index 100% rename from backend/ent/predicate/predicate.go rename to backend/internal/data/ent/predicate/predicate.go diff --git a/backend/ent/runtime.go b/backend/internal/data/ent/runtime.go similarity index 97% rename from backend/ent/runtime.go rename to backend/internal/data/ent/runtime.go index bfa73d1..3929dab 100644 --- a/backend/ent/runtime.go +++ b/backend/internal/data/ent/runtime.go @@ -6,18 +6,18 @@ import ( "time" "github.com/google/uuid" - "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/groupinvitationtoken" - "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" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // The init function reads all schema descriptors with runtime code diff --git a/backend/ent/runtime/runtime.go b/backend/internal/data/ent/runtime/runtime.go similarity index 86% rename from backend/ent/runtime/runtime.go rename to backend/internal/data/ent/runtime/runtime.go index 8dd480b..9be6acb 100644 --- a/backend/ent/runtime/runtime.go +++ b/backend/internal/data/ent/runtime/runtime.go @@ -2,7 +2,7 @@ package runtime -// The schema-stitching logic is generated in github.com/hay-kot/homebox/backend/ent/runtime.go +// The schema-stitching logic is generated in github.com/hay-kot/homebox/backend/internal/data/ent/runtime.go const ( Version = "v0.11.3" // Version of ent codegen. diff --git a/backend/ent/schema/attachment.go b/backend/internal/data/ent/schema/attachment.go similarity index 91% rename from backend/ent/schema/attachment.go rename to backend/internal/data/ent/schema/attachment.go index 7dc27d3..7f4673a 100644 --- a/backend/ent/schema/attachment.go +++ b/backend/internal/data/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/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // Attachment holds the schema definition for the Attachment entity. diff --git a/backend/ent/schema/auth_tokens.go b/backend/internal/data/ent/schema/auth_tokens.go similarity index 92% rename from backend/ent/schema/auth_tokens.go rename to backend/internal/data/ent/schema/auth_tokens.go index 41beafa..0cfd4d1 100644 --- a/backend/ent/schema/auth_tokens.go +++ b/backend/internal/data/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/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // AuthTokens holds the schema definition for the AuthTokens entity. diff --git a/backend/ent/schema/document.go b/backend/internal/data/ent/schema/document.go similarity index 93% rename from backend/ent/schema/document.go rename to backend/internal/data/ent/schema/document.go index f6b2c57..2293c39 100644 --- a/backend/ent/schema/document.go +++ b/backend/internal/data/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/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // Document holds the schema definition for the Document entity. diff --git a/backend/ent/schema/document_token.go b/backend/internal/data/ent/schema/document_token.go similarity index 92% rename from backend/ent/schema/document_token.go rename to backend/internal/data/ent/schema/document_token.go index 7423996..c5ec72f 100644 --- a/backend/ent/schema/document_token.go +++ b/backend/internal/data/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/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // DocumentToken holds the schema definition for the DocumentToken entity. diff --git a/backend/ent/schema/group.go b/backend/internal/data/ent/schema/group.go similarity index 94% rename from backend/ent/schema/group.go rename to backend/internal/data/ent/schema/group.go index a9d51ed..efd706c 100644 --- a/backend/ent/schema/group.go +++ b/backend/internal/data/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/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // Group holds the schema definition for the Group entity. diff --git a/backend/ent/schema/group_invitation_token.go b/backend/internal/data/ent/schema/group_invitation_token.go similarity index 92% rename from backend/ent/schema/group_invitation_token.go rename to backend/internal/data/ent/schema/group_invitation_token.go index 6ba41cd..1150db8 100644 --- a/backend/ent/schema/group_invitation_token.go +++ b/backend/internal/data/ent/schema/group_invitation_token.go @@ -6,7 +6,7 @@ import ( "entgo.io/ent" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" - "github.com/hay-kot/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // GroupInvitationToken holds the schema definition for the GroupInvitationToken entity. diff --git a/backend/ent/schema/item.go b/backend/internal/data/ent/schema/item.go similarity index 97% rename from backend/ent/schema/item.go rename to backend/internal/data/ent/schema/item.go index 25531d0..17021a5 100644 --- a/backend/ent/schema/item.go +++ b/backend/internal/data/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/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // Item holds the schema definition for the Item entity. diff --git a/backend/ent/schema/item_field.go b/backend/internal/data/ent/schema/item_field.go similarity index 92% rename from backend/ent/schema/item_field.go rename to backend/internal/data/ent/schema/item_field.go index 56be98a..405b99c 100644 --- a/backend/ent/schema/item_field.go +++ b/backend/internal/data/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/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // ItemField holds the schema definition for the ItemField entity. diff --git a/backend/ent/schema/label.go b/backend/internal/data/ent/schema/label.go similarity index 90% rename from backend/ent/schema/label.go rename to backend/internal/data/ent/schema/label.go index a8eb8d2..72d6078 100644 --- a/backend/ent/schema/label.go +++ b/backend/internal/data/ent/schema/label.go @@ -4,7 +4,7 @@ import ( "entgo.io/ent" "entgo.io/ent/schema/edge" "entgo.io/ent/schema/field" - "github.com/hay-kot/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // Label holds the schema definition for the Label entity. diff --git a/backend/ent/schema/location.go b/backend/internal/data/ent/schema/location.go similarity index 91% rename from backend/ent/schema/location.go rename to backend/internal/data/ent/schema/location.go index e8f2237..b3142b4 100644 --- a/backend/ent/schema/location.go +++ b/backend/internal/data/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/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // Location holds the schema definition for the Location entity. diff --git a/backend/ent/schema/mixins/base.go b/backend/internal/data/ent/schema/mixins/base.go similarity index 100% rename from backend/ent/schema/mixins/base.go rename to backend/internal/data/ent/schema/mixins/base.go diff --git a/backend/ent/schema/templates/has_id.tmpl b/backend/internal/data/ent/schema/templates/has_id.tmpl similarity index 100% rename from backend/ent/schema/templates/has_id.tmpl rename to backend/internal/data/ent/schema/templates/has_id.tmpl diff --git a/backend/ent/schema/user.go b/backend/internal/data/ent/schema/user.go similarity index 93% rename from backend/ent/schema/user.go rename to backend/internal/data/ent/schema/user.go index d522ddb..b3342a8 100644 --- a/backend/ent/schema/user.go +++ b/backend/internal/data/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/homebox/backend/ent/schema/mixins" + "github.com/hay-kot/homebox/backend/internal/data/ent/schema/mixins" ) // User holds the schema definition for the User entity. diff --git a/backend/ent/tx.go b/backend/internal/data/ent/tx.go similarity index 100% rename from backend/ent/tx.go rename to backend/internal/data/ent/tx.go diff --git a/backend/ent/user.go b/backend/internal/data/ent/user.go similarity index 98% rename from backend/ent/user.go rename to backend/internal/data/ent/user.go index 547e21f..48dbdcb 100644 --- a/backend/ent/user.go +++ b/backend/internal/data/ent/user.go @@ -9,8 +9,8 @@ import ( "entgo.io/ent/dialect/sql" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/user" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // User is the model entity for the User schema. diff --git a/backend/ent/user/user.go b/backend/internal/data/ent/user/user.go similarity index 100% rename from backend/ent/user/user.go rename to backend/internal/data/ent/user/user.go diff --git a/backend/ent/user/where.go b/backend/internal/data/ent/user/where.go similarity index 99% rename from backend/ent/user/where.go rename to backend/internal/data/ent/user/where.go index df4adbb..567187e 100644 --- a/backend/ent/user/where.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) // ID filters vertices based on their ID field. diff --git a/backend/ent/user_create.go b/backend/internal/data/ent/user_create.go similarity index 98% rename from backend/ent/user_create.go rename to backend/internal/data/ent/user_create.go index 5835244..317b43a 100644 --- a/backend/ent/user_create.go +++ b/backend/internal/data/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/homebox/backend/ent/authtokens" - "github.com/hay-kot/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/user" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // UserCreate is the builder for creating a User entity. diff --git a/backend/ent/user_delete.go b/backend/internal/data/ent/user_delete.go similarity index 95% rename from backend/ent/user_delete.go rename to backend/internal/data/ent/user_delete.go index 6d8b949..9013f6f 100644 --- a/backend/ent/user_delete.go +++ b/backend/internal/data/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/homebox/backend/ent/predicate" - "github.com/hay-kot/homebox/backend/ent/user" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // UserDelete is the builder for deleting a User entity. diff --git a/backend/ent/user_query.go b/backend/internal/data/ent/user_query.go similarity index 98% rename from backend/ent/user_query.go rename to backend/internal/data/ent/user_query.go index 09d951d..2178bd3 100644 --- a/backend/ent/user_query.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // UserQuery is the builder for querying User entities. diff --git a/backend/ent/user_update.go b/backend/internal/data/ent/user_update.go similarity index 98% rename from backend/ent/user_update.go rename to backend/internal/data/ent/user_update.go index 9316360..bfe8d3b 100644 --- a/backend/ent/user_update.go +++ b/backend/internal/data/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/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" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) // UserUpdate is the builder for updating User entities. diff --git a/backend/internal/migrations/migrations.go b/backend/internal/data/migrations/migrations.go similarity index 100% rename from backend/internal/migrations/migrations.go rename to backend/internal/data/migrations/migrations.go diff --git a/backend/internal/migrations/migrations/20220929052825_init.sql b/backend/internal/data/migrations/migrations/20220929052825_init.sql similarity index 100% rename from backend/internal/migrations/migrations/20220929052825_init.sql rename to backend/internal/data/migrations/migrations/20220929052825_init.sql diff --git a/backend/internal/migrations/migrations/20221001210956_group_invitations.sql b/backend/internal/data/migrations/migrations/20221001210956_group_invitations.sql similarity index 100% rename from backend/internal/migrations/migrations/20221001210956_group_invitations.sql rename to backend/internal/data/migrations/migrations/20221001210956_group_invitations.sql diff --git a/backend/internal/migrations/migrations/20221009173029_add_user_roles.sql b/backend/internal/data/migrations/migrations/20221009173029_add_user_roles.sql similarity index 100% rename from backend/internal/migrations/migrations/20221009173029_add_user_roles.sql rename to backend/internal/data/migrations/migrations/20221009173029_add_user_roles.sql diff --git a/backend/internal/migrations/migrations/20221020043305_allow_nesting_types.sql b/backend/internal/data/migrations/migrations/20221020043305_allow_nesting_types.sql similarity index 100% rename from backend/internal/migrations/migrations/20221020043305_allow_nesting_types.sql rename to backend/internal/data/migrations/migrations/20221020043305_allow_nesting_types.sql diff --git a/backend/internal/migrations/migrations/atlas.sum b/backend/internal/data/migrations/migrations/atlas.sum similarity index 100% rename from backend/internal/migrations/migrations/atlas.sum rename to backend/internal/data/migrations/migrations/atlas.sum diff --git a/backend/internal/repo/id_set.go b/backend/internal/data/repo/id_set.go similarity index 100% rename from backend/internal/repo/id_set.go rename to backend/internal/data/repo/id_set.go diff --git a/backend/internal/repo/main_test.go b/backend/internal/data/repo/main_test.go similarity index 94% rename from backend/internal/repo/main_test.go rename to backend/internal/data/repo/main_test.go index 92fe4be..221fbd5 100644 --- a/backend/internal/repo/main_test.go +++ b/backend/internal/data/repo/main_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/pkgs/faker" _ "github.com/mattn/go-sqlite3" ) diff --git a/backend/internal/repo/map_helpers.go b/backend/internal/data/repo/map_helpers.go similarity index 100% rename from backend/internal/repo/map_helpers.go rename to backend/internal/data/repo/map_helpers.go diff --git a/backend/internal/repo/pagination.go b/backend/internal/data/repo/pagination.go similarity index 100% rename from backend/internal/repo/pagination.go rename to backend/internal/data/repo/pagination.go diff --git a/backend/internal/repo/repo_document_tokens.go b/backend/internal/data/repo/repo_document_tokens.go similarity index 92% rename from backend/internal/repo/repo_document_tokens.go rename to backend/internal/data/repo/repo_document_tokens.go index 903240c..018ea61 100644 --- a/backend/internal/repo/repo_document_tokens.go +++ b/backend/internal/data/repo/repo_document_tokens.go @@ -5,8 +5,8 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" ) // DocumentTokensRepository is a repository for Document entity diff --git a/backend/internal/repo/repo_document_tokens_test.go b/backend/internal/data/repo/repo_document_tokens_test.go similarity index 96% rename from backend/internal/repo/repo_document_tokens_test.go rename to backend/internal/data/repo/repo_document_tokens_test.go index 34f0a17..6646eca 100644 --- a/backend/internal/repo/repo_document_tokens_test.go +++ b/backend/internal/data/repo/repo_document_tokens_test.go @@ -6,8 +6,8 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/ent/documenttoken" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/documenttoken" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repo_documents.go b/backend/internal/data/repo/repo_documents.go similarity index 92% rename from backend/internal/repo/repo_documents.go rename to backend/internal/data/repo/repo_documents.go index a9a5666..abe340d 100644 --- a/backend/internal/repo/repo_documents.go +++ b/backend/internal/data/repo/repo_documents.go @@ -8,9 +8,9 @@ import ( "path/filepath" "github.com/google/uuid" - "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/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/document" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" "github.com/hay-kot/homebox/backend/pkgs/pathlib" ) diff --git a/backend/internal/repo/repo_documents_test.go b/backend/internal/data/repo/repo_documents_test.go similarity index 97% rename from backend/internal/repo/repo_documents_test.go rename to backend/internal/data/repo/repo_documents_test.go index 06e631c..b58b3bb 100644 --- a/backend/internal/repo/repo_documents_test.go +++ b/backend/internal/data/repo/repo_documents_test.go @@ -9,7 +9,7 @@ import ( "testing" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repo_group.go b/backend/internal/data/repo/repo_group.go similarity index 90% rename from backend/internal/repo/repo_group.go rename to backend/internal/data/repo/repo_group.go index ac0e071..fa5b6b8 100644 --- a/backend/internal/repo/repo_group.go +++ b/backend/internal/data/repo/repo_group.go @@ -2,12 +2,13 @@ package repo import ( "context" + "strings" "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/groupinvitationtoken" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/groupinvitationtoken" ) type GroupRepository struct { @@ -52,7 +53,7 @@ func mapToGroup(g *ent.Group) Group { Name: g.Name, CreatedAt: g.CreatedAt, UpdatedAt: g.UpdatedAt, - Currency: g.Currency.String(), + Currency: strings.ToUpper(g.Currency.String()), } } @@ -76,7 +77,7 @@ func (r *GroupRepository) GroupCreate(ctx context.Context, name string) (Group, } func (r *GroupRepository) GroupUpdate(ctx context.Context, ID uuid.UUID, data GroupUpdate) (Group, error) { - currency := group.Currency(data.Currency) + currency := group.Currency(strings.ToLower(data.Currency)) entity, err := r.db.Group.UpdateOneID(ID). SetName(data.Name). diff --git a/backend/internal/repo/repo_group_test.go b/backend/internal/data/repo/repo_group_test.go similarity index 95% rename from backend/internal/repo/repo_group_test.go rename to backend/internal/data/repo/repo_group_test.go index 5f3faaf..941e06c 100644 --- a/backend/internal/repo/repo_group_test.go +++ b/backend/internal/data/repo/repo_group_test.go @@ -29,5 +29,5 @@ func Test_Group_Update(t *testing.T) { }) assert.NoError(t, err) assert.Equal(t, "test2", g.Name) - assert.Equal(t, "eur", g.Currency) + assert.Equal(t, "EUR", g.Currency) } diff --git a/backend/internal/repo/repo_item_attachments.go b/backend/internal/data/repo/repo_item_attachments.go similarity index 94% rename from backend/internal/repo/repo_item_attachments.go rename to backend/internal/data/repo/repo_item_attachments.go index 9b0f810..1e2ef7b 100644 --- a/backend/internal/repo/repo_item_attachments.go +++ b/backend/internal/data/repo/repo_item_attachments.go @@ -5,8 +5,8 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" ) // AttachmentRepo is a repository for Attachments table that links Items to Documents diff --git a/backend/internal/repo/repo_item_attachments_test.go b/backend/internal/data/repo/repo_item_attachments_test.go similarity index 95% rename from backend/internal/repo/repo_item_attachments_test.go rename to backend/internal/data/repo/repo_item_attachments_test.go index e861001..15f70c8 100644 --- a/backend/internal/repo/repo_item_attachments_test.go +++ b/backend/internal/data/repo/repo_item_attachments_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/ent/attachment" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/attachment" "github.com/stretchr/testify/assert" ) diff --git a/backend/internal/repo/repo_items.go b/backend/internal/data/repo/repo_items.go similarity index 96% rename from backend/internal/repo/repo_items.go rename to backend/internal/data/repo/repo_items.go index 27ddc4c..8eefb5f 100644 --- a/backend/internal/repo/repo_items.go +++ b/backend/internal/data/repo/repo_items.go @@ -5,13 +5,13 @@ import ( "time" "github.com/google/uuid" - "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/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/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/item" + "github.com/hay-kot/homebox/backend/internal/data/ent/itemfield" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) type ItemsRepository struct { diff --git a/backend/internal/repo/repo_items_test.go b/backend/internal/data/repo/repo_items_test.go similarity index 100% rename from backend/internal/repo/repo_items_test.go rename to backend/internal/data/repo/repo_items_test.go diff --git a/backend/internal/repo/repo_labels.go b/backend/internal/data/repo/repo_labels.go similarity index 73% rename from backend/internal/repo/repo_labels.go rename to backend/internal/data/repo/repo_labels.go index b899d68..353df17 100644 --- a/backend/internal/repo/repo_labels.go +++ b/backend/internal/data/repo/repo_labels.go @@ -5,10 +5,10 @@ import ( "time" "github.com/google/uuid" - "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/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/label" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) type LabelRepository struct { @@ -106,13 +106,30 @@ func (r *LabelRepository) Create(ctx context.Context, groupdId uuid.UUID, data L return mapLabelOut(label), err } -func (r *LabelRepository) Update(ctx context.Context, data LabelUpdate) (LabelOut, error) { - _, err := r.db.Label.UpdateOneID(data.ID). +func (r *LabelRepository) update(ctx context.Context, data LabelUpdate, where ...predicate.Label) (int, error) { + if len(where) == 0 { + panic("empty where not supported empty") + } + + return r.db.Label.Update(). + Where(where...). SetName(data.Name). SetDescription(data.Description). SetColor(data.Color). Save(ctx) +} +func (r *LabelRepository) Update(ctx context.Context, data LabelUpdate) (LabelOut, error) { + _, err := r.update(ctx, data, label.ID(data.ID)) + if err != nil { + return LabelOut{}, err + } + + return r.GetOne(ctx, data.ID) +} + +func (r *LabelRepository) UpdateByGroup(ctx context.Context, GID uuid.UUID, data LabelUpdate) (LabelOut, error) { + _, err := r.update(ctx, data, label.ID(data.ID), label.HasGroupWith(group.ID(GID))) if err != nil { return LabelOut{}, err } @@ -123,3 +140,13 @@ func (r *LabelRepository) Update(ctx context.Context, data LabelUpdate) (LabelOu func (r *LabelRepository) Delete(ctx context.Context, id uuid.UUID) error { return r.db.Label.DeleteOneID(id).Exec(ctx) } + +func (r *LabelRepository) DeleteByGroup(ctx context.Context, gid, id uuid.UUID) error { + _, err := r.db.Label.Delete(). + Where( + label.ID(id), + label.HasGroupWith(group.ID(gid)), + ).Exec(ctx) + + return err +} diff --git a/backend/internal/repo/repo_labels_test.go b/backend/internal/data/repo/repo_labels_test.go similarity index 100% rename from backend/internal/repo/repo_labels_test.go rename to backend/internal/data/repo/repo_labels_test.go diff --git a/backend/internal/repo/repo_locations.go b/backend/internal/data/repo/repo_locations.go similarity index 77% rename from backend/internal/repo/repo_locations.go rename to backend/internal/data/repo/repo_locations.go index f927431..9e5f36d 100644 --- a/backend/internal/repo/repo_locations.go +++ b/backend/internal/data/repo/repo_locations.go @@ -5,10 +5,10 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/ent/group" - "github.com/hay-kot/homebox/backend/ent/location" - "github.com/hay-kot/homebox/backend/ent/predicate" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/group" + "github.com/hay-kot/homebox/backend/internal/data/ent/location" + "github.com/hay-kot/homebox/backend/internal/data/ent/predicate" ) type LocationRepository struct { @@ -154,23 +154,24 @@ func (r *LocationRepository) GetOneByGroup(ctx context.Context, GID, ID uuid.UUI return r.getOne(ctx, location.ID(ID), location.HasGroupWith(group.ID(GID))) } -func (r *LocationRepository) Create(ctx context.Context, gid uuid.UUID, data LocationCreate) (LocationOut, error) { +func (r *LocationRepository) Create(ctx context.Context, GID uuid.UUID, data LocationCreate) (LocationOut, error) { location, err := r.db.Location.Create(). SetName(data.Name). SetDescription(data.Description). - SetGroupID(gid). + SetGroupID(GID). Save(ctx) if err != nil { return LocationOut{}, err } - location.Edges.Group = &ent.Group{ID: gid} // bootstrap group ID + location.Edges.Group = &ent.Group{ID: GID} // bootstrap group ID return mapLocationOut(location), nil } -func (r *LocationRepository) Update(ctx context.Context, data LocationUpdate) (LocationOut, error) { - q := r.db.Location.UpdateOneID(data.ID). +func (r *LocationRepository) update(ctx context.Context, data LocationUpdate, where ...predicate.Location) (LocationOut, error) { + q := r.db.Location.Update(). + Where(where...). SetName(data.Name). SetDescription(data.Description) @@ -181,7 +182,6 @@ func (r *LocationRepository) Update(ctx context.Context, data LocationUpdate) (L } _, err := q.Save(ctx) - if err != nil { return LocationOut{}, err } @@ -189,6 +189,19 @@ func (r *LocationRepository) Update(ctx context.Context, data LocationUpdate) (L return r.Get(ctx, data.ID) } -func (r *LocationRepository) Delete(ctx context.Context, id uuid.UUID) error { - return r.db.Location.DeleteOneID(id).Exec(ctx) +func (r *LocationRepository) Update(ctx context.Context, data LocationUpdate) (LocationOut, error) { + return r.update(ctx, data, location.ID(data.ID)) +} + +func (r *LocationRepository) UpdateOneByGroup(ctx context.Context, GID, ID uuid.UUID, data LocationUpdate) (LocationOut, error) { + return r.update(ctx, data, location.ID(ID), location.HasGroupWith(group.ID(GID))) +} + +func (r *LocationRepository) Delete(ctx context.Context, ID uuid.UUID) error { + return r.db.Location.DeleteOneID(ID).Exec(ctx) +} + +func (r *LocationRepository) DeleteByGroup(ctx context.Context, GID, ID uuid.UUID) error { + _, err := r.db.Location.Delete().Where(location.ID(ID), location.HasGroupWith(group.ID(GID))).Exec(ctx) + return err } diff --git a/backend/internal/repo/repo_locations_test.go b/backend/internal/data/repo/repo_locations_test.go similarity index 100% rename from backend/internal/repo/repo_locations_test.go rename to backend/internal/data/repo/repo_locations_test.go diff --git a/backend/internal/repo/repo_tokens.go b/backend/internal/data/repo/repo_tokens.go similarity index 94% rename from backend/internal/repo/repo_tokens.go rename to backend/internal/data/repo/repo_tokens.go index 38c7443..7d9115b 100644 --- a/backend/internal/repo/repo_tokens.go +++ b/backend/internal/data/repo/repo_tokens.go @@ -5,8 +5,8 @@ import ( "time" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/ent/authtokens" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/authtokens" ) type TokenRepository struct { diff --git a/backend/internal/repo/repo_tokens_test.go b/backend/internal/data/repo/repo_tokens_test.go similarity index 100% rename from backend/internal/repo/repo_tokens_test.go rename to backend/internal/data/repo/repo_tokens_test.go diff --git a/backend/internal/repo/repo_users.go b/backend/internal/data/repo/repo_users.go similarity index 96% rename from backend/internal/repo/repo_users.go rename to backend/internal/data/repo/repo_users.go index 828c4c2..0eaa127 100644 --- a/backend/internal/repo/repo_users.go +++ b/backend/internal/data/repo/repo_users.go @@ -4,8 +4,8 @@ import ( "context" "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/ent" - "github.com/hay-kot/homebox/backend/ent/user" + "github.com/hay-kot/homebox/backend/internal/data/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent/user" ) type UserRepository struct { diff --git a/backend/internal/repo/repo_users_test.go b/backend/internal/data/repo/repo_users_test.go similarity index 100% rename from backend/internal/repo/repo_users_test.go rename to backend/internal/data/repo/repo_users_test.go diff --git a/backend/internal/repo/repos_all.go b/backend/internal/data/repo/repos_all.go similarity index 92% rename from backend/internal/repo/repos_all.go rename to backend/internal/data/repo/repos_all.go index d01b402..e726e88 100644 --- a/backend/internal/repo/repos_all.go +++ b/backend/internal/data/repo/repos_all.go @@ -1,6 +1,6 @@ package repo -import "github.com/hay-kot/homebox/backend/ent" +import "github.com/hay-kot/homebox/backend/internal/data/ent" // AllRepos is a container for all the repository interfaces type AllRepos struct { diff --git a/backend/internal/mocks/chimocker/chimocker.go b/backend/internal/mocks/chimocker/chimocker.go deleted file mode 100644 index b918403..0000000 --- a/backend/internal/mocks/chimocker/chimocker.go +++ /dev/null @@ -1,30 +0,0 @@ -package chimocker - -import ( - "context" - "net/http" - - "github.com/go-chi/chi/v5" -) - -type Params map[string]string - -// WithUrlParam returns a pointer to a request object with the given URL params -// added to a new chi.Context object. -func WithUrlParam(r *http.Request, key, value string) *http.Request { - chiCtx := chi.NewRouteContext() - req := r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, chiCtx)) - chiCtx.URLParams.Add(key, value) - return req -} - -// WithUrlParams returns a pointer to a request object with the given URL params -// added to a new chi.Context object. for single param assignment see WithUrlParam -func WithUrlParams(r *http.Request, params Params) *http.Request { - chiCtx := chi.NewRouteContext() - req := r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, chiCtx)) - for key, value := range params { - chiCtx.URLParams.Add(key, value) - } - return req -} diff --git a/backend/internal/mocks/factories/users.go b/backend/internal/mocks/factories/users.go deleted file mode 100644 index 6f618fb..0000000 --- a/backend/internal/mocks/factories/users.go +++ /dev/null @@ -1,16 +0,0 @@ -package factories - -import ( - "github.com/hay-kot/homebox/backend/internal/repo" - "github.com/hay-kot/homebox/backend/pkgs/faker" -) - -func UserFactory() repo.UserCreate { - f := faker.NewFaker() - return repo.UserCreate{ - Name: f.Str(10), - Email: f.Email(), - Password: f.Str(10), - IsSuperuser: f.Bool(), - } -} diff --git a/backend/internal/services/all.go b/backend/internal/services/all.go deleted file mode 100644 index 20e377f..0000000 --- a/backend/internal/services/all.go +++ /dev/null @@ -1,28 +0,0 @@ -package services - -import "github.com/hay-kot/homebox/backend/internal/repo" - -type AllServices struct { - User *UserService - Group *GroupService - Location *LocationService - Labels *LabelService - Items *ItemService -} - -func New(repos *repo.AllRepos) *AllServices { - if repos == nil { - panic("repos cannot be nil") - } - - return &AllServices{ - User: &UserService{repos}, - Group: &GroupService{repos}, - Location: &LocationService{repos}, - Labels: &LabelService{repos}, - Items: &ItemService{ - repo: repos, - at: attachmentTokens{}, - }, - } -} diff --git a/backend/internal/services/service_labels.go b/backend/internal/services/service_labels.go deleted file mode 100644 index 34d67df..0000000 --- a/backend/internal/services/service_labels.go +++ /dev/null @@ -1,37 +0,0 @@ -package services - -import ( - "context" - - "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/repo" -) - -type LabelService struct { - repos *repo.AllRepos -} - -func (svc *LabelService) Create(ctx context.Context, groupId uuid.UUID, data repo.LabelCreate) (repo.LabelOut, error) { - return svc.repos.Labels.Create(ctx, groupId, data) -} - -func (svc *LabelService) Update(ctx context.Context, groupId uuid.UUID, data repo.LabelUpdate) (repo.LabelOut, error) { - return svc.repos.Labels.Update(ctx, data) -} - -func (svc *LabelService) Delete(ctx context.Context, gid uuid.UUID, id uuid.UUID) error { - _, err := svc.repos.Labels.GetOneByGroup(ctx, gid, id) - if err != nil { - return err - } - return svc.repos.Labels.Delete(ctx, id) -} - -func (svc *LabelService) Get(ctx context.Context, gid uuid.UUID, id uuid.UUID) (repo.LabelOut, error) { - return svc.repos.Labels.GetOneByGroup(ctx, gid, id) - -} - -func (svc *LabelService) GetAll(ctx context.Context, groupId uuid.UUID) ([]repo.LabelSummary, error) { - return svc.repos.Labels.GetAll(ctx, groupId) -} diff --git a/backend/internal/services/service_locations.go b/backend/internal/services/service_locations.go deleted file mode 100644 index 7152337..0000000 --- a/backend/internal/services/service_locations.go +++ /dev/null @@ -1,47 +0,0 @@ -package services - -import ( - "context" - "errors" - - "github.com/google/uuid" - "github.com/hay-kot/homebox/backend/internal/repo" -) - -var ( - ErrNotOwner = errors.New("not owner") -) - -type LocationService struct { - repos *repo.AllRepos -} - -func (svc *LocationService) GetOne(ctx context.Context, groupId uuid.UUID, id uuid.UUID) (repo.LocationOut, error) { - return svc.repos.Locations.GetOneByGroup(ctx, groupId, id) -} - -func (svc *LocationService) GetAll(ctx context.Context, groupId uuid.UUID) ([]repo.LocationOutCount, error) { - return svc.repos.Locations.GetAll(ctx, groupId) -} - -func (svc *LocationService) Create(ctx context.Context, groupId uuid.UUID, data repo.LocationCreate) (repo.LocationOut, error) { - return svc.repos.Locations.Create(ctx, groupId, data) -} - -func (svc *LocationService) Delete(ctx context.Context, groupId uuid.UUID, id uuid.UUID) error { - _, err := svc.repos.Locations.GetOneByGroup(ctx, groupId, id) - if err != nil { - return err - } - return svc.repos.Locations.Delete(ctx, id) -} - -func (svc *LocationService) Update(ctx context.Context, groupId uuid.UUID, data repo.LocationUpdate) (repo.LocationOut, error) { - location, err := svc.repos.Locations.GetOneByGroup(ctx, groupId, data.ID) - if err != nil { - return repo.LocationOut{}, err - } - - data.ID = location.ID - return svc.repos.Locations.Update(ctx, data) -} diff --git a/backend/internal/config/conf.go b/backend/internal/sys/config/conf.go similarity index 100% rename from backend/internal/config/conf.go rename to backend/internal/sys/config/conf.go diff --git a/backend/internal/config/conf_database.go b/backend/internal/sys/config/conf_database.go similarity index 100% rename from backend/internal/config/conf_database.go rename to backend/internal/sys/config/conf_database.go diff --git a/backend/internal/config/conf_logger.go b/backend/internal/sys/config/conf_logger.go similarity index 100% rename from backend/internal/config/conf_logger.go rename to backend/internal/sys/config/conf_logger.go diff --git a/backend/internal/config/conf_mailer.go b/backend/internal/sys/config/conf_mailer.go similarity index 100% rename from backend/internal/config/conf_mailer.go rename to backend/internal/sys/config/conf_mailer.go diff --git a/backend/internal/config/conf_mailer_test.go b/backend/internal/sys/config/conf_mailer_test.go similarity index 100% rename from backend/internal/config/conf_mailer_test.go rename to backend/internal/sys/config/conf_mailer_test.go diff --git a/backend/internal/sys/validate/validate.go b/backend/internal/sys/validate/validate.go new file mode 100644 index 0000000..ed22c0f --- /dev/null +++ b/backend/internal/sys/validate/validate.go @@ -0,0 +1,37 @@ +package validate + +import "github.com/go-playground/validator/v10" + +var validate *validator.Validate + +func init() { + validate = validator.New() +} + +// Checks a struct for validation errors and returns any errors the occur. This +// wraps the validate.Struct() function and provides some error wrapping. When +// a validator.ValidationErrors is returned, it is wrapped transformed into a +// FieldErrors array and returned. +func Check(val any) error { + err := validate.Struct(val) + + if err != nil { + verrors, ok := err.(validator.ValidationErrors) + if !ok { + return err + } + + fields := make(FieldErrors, 0, len(verrors)) + for _, verr := range verrors { + field := FieldError{ + Field: verr.Field(), + Error: verr.Error(), + } + + fields = append(fields, field) + } + return fields + } + + return nil +} diff --git a/backend/internal/web/mid/errors.go b/backend/internal/web/mid/errors.go index 0802a11..7aa659c 100644 --- a/backend/internal/web/mid/errors.go +++ b/backend/internal/web/mid/errors.go @@ -3,7 +3,7 @@ package mid import ( "net/http" - "github.com/hay-kot/homebox/backend/ent" + "github.com/hay-kot/homebox/backend/internal/data/ent" "github.com/hay-kot/homebox/backend/internal/sys/validate" "github.com/hay-kot/homebox/backend/pkgs/server" "github.com/rs/zerolog" diff --git a/backend/static/favicon.ico b/backend/static/favicon.ico deleted file mode 100644 index c6f7f740621c2f01f10b5c6614ed1960a7e66244..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1366 zcmZ`(c~DbF9DV{R9n_B1QhLm2I*Jz}NjyS8AhD#7LLLwjfk7mMaDyN@6!8d$RICDm zk`zQDI$kXj2q9FICT2=Uz)DdGhQmNWLKvw?5&|Ue^~LFo(?7cN?f!Ouzwi5Yc6Mh= z!@;1{E?>C-0I-@897sbV+TK5QM8?1y=em&KltQAC0HC>ir8NO%FD3@lr~q($GXMyR z0bmJ93G@KK!vKJR2>?DK0C3B>azA1p0664@htkOifx%$lL7I0M-45^r@F0C}7#$D@ z2=+V!0YWBFBfY`*phhCg4}2<}5c*ylMkmYd}{nJ3hwYCe+=Rd zTLR)!d>L_!%Ii@--Sv-4BC;}gBa1BQW3Z?)Z^+d8H#D*UPcFj!CRl8Mj*dasXP`gk z;a(#worMHCi1X4!zj*EN(`nAoLQemiG}RD=U&tApkGxPvE34yZ%*8sJVF^ZBj}b1= zL0SuJw!t;i5MK+WbPhz6iel=UlRNtPudIBn?d1Y&vB4#i5dC5USWuDqcwDH5OeRzO z!PxDa-Sdv}=a!+WDX72yFQT6>cIS>3iR95cI8`x7&N`MT>lRg4yRG|FsZjhd2{q3` zk>O#R(Cded%h`Q1H6o$vk&;0RcmHO?h{>AWXSl3~%w{v2#q{#ncKT%gTPu8V3L1Fv zg1n!E--T3Y@dTu|p9p%`-MbOJVf)rC>d_IS z4HoI4{BcOP2tPH!vO8kcdF~ljB!#dmbl;we^q7`biRvBvcph$=g-+|BykU#t0$*N! zf;YO%thsZd>XN+vlJaKFqg%C-D^AJ2@8J`0T7#V^cOW zm7U2-Pfku}WwKMnO)(Zw?l&^N*u;=- z%*|C664$UZYMm1%-3B!!ZiXH#=Jp*oSD~Qz`<`x(?Y6tbUPF!M{_&xb?^aVQ0%XS8 zeWZpbo}QkKS#QwEK_MY2!p7Rpz20c9v7?CC;73F~L@`k(Jw0vfGPf9J3SITnLsW-S z@G6d{;r{j|`gL!NbgEY-d!}~u=u^vObvmf2d&_P~ex3FHrhN3$A+%p4Muwse;PZ z`<8_iyeX}^1=jm>%uXPxt!)aKmTMCta>mAg4>{&4E{s5Nk-sGWoa3R~hIt}#d+uCv zG?$&gP4Y?1O+o^I!(a)XSez#YPsd?>uo$1+SPu-w2ZNd7Y{>YJAS;`lmYnzhg6f^O Q)QA9}kio!v` Date: Mon, 31 Oct 2022 18:43:30 -0800 Subject: [PATCH 077/435] fix: time-format-inconsistency (#120) * fix off by one date display * display dates in consistent format * use token or ci --- .github/workflows/partial-backend.yaml | 2 + .github/workflows/partial-frontend.yaml | 2 + .../core/services/service_items_csv_test.go | 43 ++++++++++++++++--- docs/docs/import-csv.md | 2 +- frontend/components/global/DateTime.vue | 4 +- frontend/lib/api/base/base-api.ts | 17 +++----- 6 files changed, 50 insertions(+), 20 deletions(-) diff --git a/.github/workflows/partial-backend.yaml b/.github/workflows/partial-backend.yaml index 1bb0dce..3e23d59 100644 --- a/.github/workflows/partial-backend.yaml +++ b/.github/workflows/partial-backend.yaml @@ -16,6 +16,8 @@ jobs: - name: Install Task uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} - name: golangci-lint uses: golangci/golangci-lint-action@v3 diff --git a/.github/workflows/partial-frontend.yaml b/.github/workflows/partial-frontend.yaml index fcbfcbd..c83a1bd 100644 --- a/.github/workflows/partial-frontend.yaml +++ b/.github/workflows/partial-frontend.yaml @@ -14,6 +14,8 @@ jobs: - name: Install Task uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Set up Go uses: actions/setup-go@v2 diff --git a/backend/internal/core/services/service_items_csv_test.go b/backend/internal/core/services/service_items_csv_test.go index 8c453e8..b5b488c 100644 --- a/backend/internal/core/services/service_items_csv_test.go +++ b/backend/internal/core/services/service_items_csv_test.go @@ -3,18 +3,22 @@ package services import ( "bytes" "encoding/csv" + "fmt" "reflect" "testing" + "time" + + "github.com/stretchr/testify/assert" ) const CSV_DATA = ` Import Ref,Location,Labels,Quantity,Name,Description,Insured,Serial Number,Mode Number,Manufacturer,Notes,Purchase From,Purchased Price,Purchased Time,Lifetime Warranty,Warranty Expires,Warranty Details,Sold To,Sold Price,Sold Time,Sold Notes -A,Garage,IOT;Home Assistant; Z-Wave,1,Zooz Universal Relay ZEN17,"Zooz 700 Series Z-Wave Universal Relay ZEN17 for Awnings, Garage Doors, Sprinklers, and More | 2 NO-C-NC Relays (20A, 10A) | Signal Repeater | Hub Required (Compatible with SmartThings and Hubitat)",,,ZEN17,Zooz,,Amazon,39.95,10/13/2021,,,,,,, -B,Living Room,IOT;Home Assistant; Z-Wave,1,Zooz Motion Sensor,"Zooz Z-Wave Plus S2 Motion Sensor ZSE18 with Magnetic Mount, Works with Vera and SmartThings",,,ZSE18,Zooz,,Amazon,29.95,10/15/2021,,,,,,, -C,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,"Zooz Z-Wave Plus Power Switch ZEN15 for 110V AC Units, Sump Pumps, Humidifiers, and More",,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,,,,,, -D,Downstairs,IOT;Home Assistant; Z-Wave,1,Ecolink Z-Wave PIR Motion Sensor,"Ecolink Z-Wave PIR Motion Detector Pet Immune, White (PIRZWAVE2.5-ECO)",,,PIRZWAVE2.5-ECO,Ecolink,,Amazon,35.58,10/21/2020,,,,,,, -E,Entry,IOT;Home Assistant; Z-Wave,1,Yale Security Touchscreen Deadbolt,"Yale Security YRD226-ZW2-619 YRD226ZW2619 Touchscreen Deadbolt, Satin Nickel",,,YRD226ZW2619,Yale,,Amazon,120.39,10/14/2020,,,,,,, -F,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,"UltraPro Z-Wave Smart Rocker Light Dimmer with QuickFit and SimpleWire, 3-Way Ready, Compatible with Alexa, Google Assistant, ZWave Hub Required, Repeater/Range Extender, White Paddle Only, 39351",,,39351,Honeywell,,Amazon,65.98,09/30/0202,,,,,,,` +A,Garage,IOT;Home Assistant; Z-Wave,1,Zooz Universal Relay ZEN17,Description 1,TRUE,,ZEN17,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021, +B,Living Room,IOT;Home Assistant; Z-Wave,1,Zooz Motion Sensor,Description 2,FALSE,,ZSE18,Zooz,,Amazon,29.95,10/15/2021,,10/15/2021,,,,10/15/2021, +C,Office,IOT;Home Assistant; Z-Wave,1,Zooz 110v Power Switch,Description 3,TRUE,,ZEN15,Zooz,,Amazon,39.95,10/13/2021,,10/13/2021,,,,10/13/2021, +D,Downstairs,IOT;Home Assistant; Z-Wave,1,Ecolink Z-Wave PIR Motion Sensor,Description 4,FALSE,,PIRZWAVE2.5-ECO,Ecolink,,Amazon,35.58,10/21/2020,,10/21/2020,,,,10/21/2020, +E,Entry,IOT;Home Assistant; Z-Wave,1,Yale Security Touchscreen Deadbolt,Description 5,TRUE,,YRD226ZW2619,Yale,,Amazon,120.39,10/14/2020,,10/14/2020,,,,10/14/2020, +F,Kitchen,IOT;Home Assistant; Z-Wave,1,Smart Rocker Light Dimmer,Description 6,FALSE,,39351,Honeywell,,Amazon,65.98,09/30/2020,,09/30/2020,,,,09/30/2020,` func loadcsv() [][]string { reader := csv.NewReader(bytes.NewBuffer([]byte(CSV_DATA))) @@ -27,6 +31,33 @@ func loadcsv() [][]string { return records } +func Test_CorrectDateParsing(t *testing.T) { + t.Parallel() + + expected := []time.Time{ + time.Date(2021, 10, 13, 0, 0, 0, 0, time.UTC), + time.Date(2021, 10, 15, 0, 0, 0, 0, time.UTC), + time.Date(2021, 10, 13, 0, 0, 0, 0, time.UTC), + time.Date(2020, 10, 21, 0, 0, 0, 0, time.UTC), + time.Date(2020, 10, 14, 0, 0, 0, 0, time.UTC), + time.Date(2020, 9, 30, 0, 0, 0, 0, time.UTC), + } + + records := loadcsv() + + for i, record := range records { + if i == 0 { + continue + } + entity := newCsvRow(record) + expected := expected[i-1] + + assert.Equal(t, expected, entity.Item.PurchaseTime, fmt.Sprintf("Failed on row %d", i)) + assert.Equal(t, expected, entity.Item.WarrantyExpires, fmt.Sprintf("Failed on row %d", i)) + assert.Equal(t, expected, entity.Item.SoldTime, fmt.Sprintf("Failed on row %d", i)) + } +} + func Test_csvRow_getLabels(t *testing.T) { type fields struct { LabelStr string diff --git a/docs/docs/import-csv.md b/docs/docs/import-csv.md index ea32b8f..67b1e1d 100644 --- a/docs/docs/import-csv.md +++ b/docs/docs/import-csv.md @@ -52,5 +52,5 @@ Import RefLocation Labels Quantity Name Description Insured Serial Number Model | Type | Format | | ------- | --------------------------------------------------- | | String | Max 255 Characters unless otherwise specified | -| Date | YYYY-MM-DD | +| Date | MM/DD/YYYY | | Boolean | true or false, yes or no, 1 or 0 - case insensitive | diff --git a/frontend/components/global/DateTime.vue b/frontend/components/global/DateTime.vue index bc57acc..940ee3e 100644 --- a/frontend/components/global/DateTime.vue +++ b/frontend/components/global/DateTime.vue @@ -27,9 +27,9 @@ case DateTimeFormat.RELATIVE: return useTimeAgo(dt).value + useDateFormat(dt, " (MM-DD-YYYY)").value; case DateTimeFormat.LONG: - return useDateFormat(dt, "YYYY-MM-DD (dddd)").value; + return useDateFormat(dt, "MM-DD-YYYY (dddd)").value; case DateTimeFormat.SHORT: - return useDateFormat(dt, "YYYY-MM-DD").value; + return useDateFormat(dt, "MM-DD-YYYY").value; default: return ""; } diff --git a/frontend/lib/api/base/base-api.ts b/frontend/lib/api/base/base-api.ts index c8da034..b48d10b 100644 --- a/frontend/lib/api/base/base-api.ts +++ b/frontend/lib/api/base/base-api.ts @@ -1,16 +1,10 @@ import { Requests } from "../../requests"; -// < -// TGetResult, -// TPostData, -// TPostResult, -// TPutData = TPostData, -// TPutResult = TPostResult, -// TDeleteResult = void -// > type BaseApiType = { createdAt: string; updatedAt: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [key: string]: any; }; export function hasKey(obj: object, key: string): obj is Required { @@ -20,10 +14,11 @@ export function hasKey(obj: object, key: string): obj is Required { export function parseDate(obj: T, keys: Array = []): T { const result = { ...obj }; [...keys, "createdAt", "updatedAt"].forEach(key => { - // @ts-ignore - we are checking for the key above + // @ts-ignore - TS doesn't know that we're checking for the key above if (hasKey(result, key)) { - // @ts-ignore - we are guarding against this above - result[key] = new Date(result[key]); + // Ensure date like format YYYY/MM/DD - otherwise results will be 1 day off + const dateStr: string = result[key].split("T")[0].replace(/-/g, "/"); + result[key] = new Date(dateStr); } }); From c722495fdd8cc407fdd926bfe1e22e25279c48cc Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Mon, 31 Oct 2022 19:07:01 -0800 Subject: [PATCH 078/435] feat: redirect to item on create (#121) * redirect on create * change to text area --- frontend/components/Item/CreateModal.vue | 6 ++++-- frontend/components/Label/CreateModal.vue | 3 ++- frontend/components/Location/CreateModal.vue | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/components/Item/CreateModal.vue b/frontend/components/Item/CreateModal.vue index b2ed85e..42bb6b7 100644 --- a/frontend/components/Item/CreateModal.vue +++ b/frontend/components/Item/CreateModal.vue @@ -10,7 +10,7 @@ :autofocus="true" label="Item Name" /> - +
diff --git a/frontend/pages/item/[id]/index/log.vue b/frontend/pages/item/[id]/index/log.vue index ab701db..b0f06b2 100644 --- a/frontend/pages/item/[id]/index/log.vue +++ b/frontend/pages/item/[id]/index/log.vue @@ -1,5 +1,6 @@ @@ -95,16 +112,32 @@ -
- - - Log Maintenance - -
-
-
+
+
+ + + Back + + + + Log Maintenance + +
+
+ +
+
@@ -137,37 +170,6 @@
-
-
-
-
{{ stat.title }}
-
{{ stat.value }}
-
{{ stat.subtitle }}
-
-
-
- - diff --git a/frontend/pages/items.vue b/frontend/pages/items.vue index 317a0f0..34d453d 100644 --- a/frontend/pages/items.vue +++ b/frontend/pages/items.vue @@ -135,7 +135,7 @@
diff --git a/frontend/pages/profile.vue b/frontend/pages/profile.vue index f2f32fe..fe3c3ef 100644 --- a/frontend/pages/profile.vue +++ b/frontend/pages/profile.vue @@ -22,8 +22,6 @@ if (group.value) { group.value.currency = currency.value.code; } - - console.log(group.value); }); const currencyExample = computed(() => { diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 8013d1b..1de5c6f 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -13,6 +13,7 @@ specifiers: '@typescript-eslint/parser': ^5.36.2 '@vueuse/nuxt': ^9.1.1 autoprefixer: ^10.4.8 + chart.js: ^4.0.1 daisyui: ^2.24.0 dompurify: ^2.4.1 eslint: ^8.23.0 @@ -30,6 +31,7 @@ specifiers: vite-plugin-eslint: ^1.8.1 vitest: ^0.22.1 vue: ^3.2.38 + vue-chartjs: ^4.1.2 dependencies: '@iconify/vue': 3.2.1_vue@3.2.45 @@ -40,6 +42,7 @@ dependencies: '@tailwindcss/typography': 0.5.8_tailwindcss@3.2.4 '@vueuse/nuxt': 9.6.0_nuxt@3.0.0+vue@3.2.45 autoprefixer: 10.4.13_postcss@8.4.19 + chart.js: 4.0.1 daisyui: 2.43.0_2lwn2upnx27dqeg6hqdu7sq75m dompurify: 2.4.1 markdown-it: 13.0.1 @@ -47,6 +50,7 @@ dependencies: postcss: 8.4.19 tailwindcss: 3.2.4_postcss@8.4.19 vue: 3.2.45 + vue-chartjs: 4.1.2_chart.js@4.0.1+vue@3.2.45 devDependencies: '@faker-js/faker': 7.6.0 @@ -1750,6 +1754,11 @@ packages: /chardet/0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + /chart.js/4.0.1: + resolution: {integrity: sha512-5/8/9eBivwBZK81mKvmIwTb2Pmw4D/5h1RK9fBWZLLZ8mCJ+kfYNmV9rMrGoa5Hgy2/wVDBMLSUDudul2/9ihA==} + engines: {pnpm: ^7.0.0} + dev: false + /check-error/1.0.2: resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} dev: true @@ -6412,6 +6421,16 @@ packages: dependencies: ufo: 1.0.1 + /vue-chartjs/4.1.2_chart.js@4.0.1+vue@3.2.45: + resolution: {integrity: sha512-QSggYjeFv/L4jFSBQpX8NzrAvX0B+Ha6nDgxkTG8tEXxYOOTwKI4phRLe+B4f+REnkmg7hgPY24R0cixZJyXBg==} + peerDependencies: + chart.js: ^3.7.0 + vue: ^3.0.0-0 || ^2.6.0 + dependencies: + chart.js: 4.0.1 + vue: 3.2.45 + dev: false + /vue-demi/0.13.11_vue@3.2.45: resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==} engines: {node: '>=12'} diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index fc78c6c..acb95bb 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -4,6 +4,52 @@ module.exports = { theme: { extend: {}, }, + daisyui: { + themes: [ + { + homebox: { + primary: "#5C7F67", + secondary: "#ECF4E7", + accent: "#FFDA56", + neutral: "#2C2E27", + "base-100": "#FFFFFF", + info: "#3ABFF8", + success: "#36D399", + warning: "#FBBD23", + error: "#F87272", + }, + }, + "light", + "dark", + "cupcake", + "bumblebee", + "emerald", + "corporate", + "synthwave", + "retro", + "cyberpunk", + "valentine", + "halloween", + "garden", + "forest", + "aqua", + "lofi", + "pastel", + "fantasy", + "wireframe", + "black", + "luxury", + "dracula", + "cmyk", + "autumn", + "business", + "acid", + "lemonade", + "night", + "coffee", + "winter", + ], + }, variants: { extend: {}, }, From 58d6f9a28c13a060fcad19385abe2712825cea2e Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Thu, 29 Dec 2022 21:18:49 -0800 Subject: [PATCH 105/435] Fix/mobile-layouts (#192) * partial fix for location card spacing * update header on mobile --- frontend/components/Location/Card.vue | 9 ++++++++- frontend/layouts/default.vue | 23 ++++++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/frontend/components/Location/Card.vue b/frontend/components/Location/Card.vue index 335a0f9..d0b6543 100644 --- a/frontend/components/Location/Card.vue +++ b/frontend/components/Location/Card.vue @@ -19,7 +19,14 @@ {{ location.name }} - {{ count }} + + {{ count }} + diff --git a/frontend/layouts/default.vue b/frontend/layouts/default.vue index 8dff148..ef1a8ca 100644 --- a/frontend/layouts/default.vue +++ b/frontend/layouts/default.vue @@ -13,14 +13,23 @@
-
- - - +
+
From 891d41b75f759348d9cae3839134656894e2922c Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sun, 1 Jan 2023 13:50:48 -0800 Subject: [PATCH 106/435] feat: new-card-design (#196) * card option 1 * UI updates for item card * fix test error * fix pagination issues on backend * add integer support * remove date from cards * implement pagination for search page * resolve search state problems * other fixes * fix broken datetime * attempt to fix scroll behavior --- backend/app/api/handlers/v1/v1_ctrl_items.go | 7 + backend/go.mod | 8 +- backend/go.sum | 42 ++++-- backend/internal/data/repo/repo_items.go | 20 +-- .../data/repo/repo_maintenance_entry_test.go | 23 +++- frontend/components/Chart/Line.vue | 1 - frontend/components/Item/Card.vue | 80 ++++++++--- frontend/components/global/DateTime.vue | 71 ++-------- frontend/composables/use-formatters.ts | 60 +++++++- frontend/composables/use-route-params.ts | 38 +++-- frontend/layouts/default.vue | 3 + frontend/lib/api/base/base-api.ts | 10 ++ frontend/nuxt.config.ts | 1 - frontend/package.json | 4 +- frontend/pages/items.vue | 130 +++++++++++++++--- frontend/pages/label/[id].vue | 2 +- frontend/pages/location/[id].vue | 2 +- frontend/plugins/scroll.client.ts | 7 + frontend/pnpm-lock.yaml | 26 ++++ 19 files changed, 393 insertions(+), 142 deletions(-) create mode 100644 frontend/plugins/scroll.client.ts diff --git a/backend/app/api/handlers/v1/v1_ctrl_items.go b/backend/app/api/handlers/v1/v1_ctrl_items.go index ea961f3..d7be19d 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_items.go +++ b/backend/app/api/handlers/v1/v1_ctrl_items.go @@ -1,6 +1,8 @@ package v1 import ( + "database/sql" + "errors" "net/http" "github.com/hay-kot/homebox/backend/internal/core/services" @@ -41,6 +43,11 @@ func (ctrl *V1Controller) HandleItemsGetAll() server.HandlerFunc { ctx := services.NewContext(r.Context()) items, err := ctrl.repo.Items.QueryByGroup(ctx, ctx.GID, extractQuery(r)) if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return server.Respond(w, http.StatusOK, repo.PaginationResult[repo.ItemSummary]{ + Items: []repo.ItemSummary{}, + }) + } log.Err(err).Msg("failed to get items") return validate.NewRequestError(err, http.StatusInternalServerError) } diff --git a/backend/go.mod b/backend/go.mod index 3f1f50f..275b010 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -35,15 +35,15 @@ require ( github.com/leodido/go-urn v1.2.1 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a // indirect + github.com/swaggo/files v1.0.0 // indirect github.com/zclconf/go-cty v1.12.1 // indirect golang.org/x/mod v0.7.0 // indirect - golang.org/x/net v0.3.0 // indirect + golang.org/x/net v0.4.0 // indirect golang.org/x/sys v0.3.0 // indirect golang.org/x/text v0.5.0 // indirect - golang.org/x/tools v0.3.0 // indirect + golang.org/x/tools v0.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index a5ad319..243b47a 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -70,13 +70,16 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -88,6 +91,8 @@ github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -98,40 +103,61 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a h1:kAe4YSu0O0UFn1DowNo2MY5p6xzqtJ/wQ7LZynSvGaY= -github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= +github.com/swaggo/files v1.0.0 h1:1gGXVIeUFCS/dta17rnP0iOpr6CXFwKD7EO5ID233e4= +github.com/swaggo/files v1.0.0/go.mod h1:N59U6URJLyU1PQgFqPM7wXLMhJx7QAolnvfQkqO13kc= github.com/swaggo/http-swagger v1.3.3 h1:Hu5Z0L9ssyBLofaama21iYaF2VbWyA8jdohaaCGpHsc= github.com/swaggo/http-swagger v1.3.3/go.mod h1:sE+4PjD89IxMPm77FnkDz0sdO+p5lbXzrVWT6OTVVGo= github.com/swaggo/swag v1.8.9 h1:kHtaBe/Ob9AZzAANfcn5c6RyCke9gG9QpH0jky0I/sA= github.com/swaggo/swag v1.8.9/go.mod h1:ezQVUUhly8dludpVk+/PuwJWvLLanB13ygV5Pr9enSk= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zclconf/go-cty v1.12.1 h1:PcupnljUm9EIvbgSHQnHhUr3fO6oFmkOrvs2BAFNXXY= github.com/zclconf/go-cty v1.12.1/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8= golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk= -golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM= -golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.4.0 h1:7mTAgkunk3fr4GAloyyCasadO6h9zSsQZbwvcaIciV4= +golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/backend/internal/data/repo/repo_items.go b/backend/internal/data/repo/repo_items.go index d8a3904..e22f30a 100644 --- a/backend/internal/data/repo/repo_items.go +++ b/backend/internal/data/repo/repo_items.go @@ -326,23 +326,23 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite ) } + count, err := qb.Count(ctx) + if err != nil { + return PaginationResult[ItemSummary]{}, err + } + + qb = qb.Order(ent.Asc(item.FieldName)). + WithLabel(). + WithLocation() + if q.Page != -1 || q.PageSize != -1 { qb = qb. Offset(calculateOffset(q.Page, q.PageSize)). Limit(q.PageSize) } - items, err := mapItemsSummaryErr( - qb.Order(ent.Asc(item.FieldName)). - WithLabel(). - WithLocation(). - All(ctx), - ) - if err != nil { - return PaginationResult[ItemSummary]{}, err - } + items, err := mapItemsSummaryErr(qb.All(ctx)) - count, err := qb.Count(ctx) if err != nil { return PaginationResult[ItemSummary]{}, err } diff --git a/backend/internal/data/repo/repo_maintenance_entry_test.go b/backend/internal/data/repo/repo_maintenance_entry_test.go index 8babefc..e3df3d0 100644 --- a/backend/internal/data/repo/repo_maintenance_entry_test.go +++ b/backend/internal/data/repo/repo_maintenance_entry_test.go @@ -8,14 +8,35 @@ import ( "github.com/stretchr/testify/assert" ) +// get the previous month from the current month, accounts for errors when run +// near the beginning or end of the month/year +func getPrevMonth(now time.Time) time.Time { + t := now.AddDate(0, -1, 0) + + // avoid infinite loop + max := 15 + for t.Month() == now.Month() { + println("month is the same") + t = t.AddDate(0, 0, -1) + println(t.String()) + + max-- + if max == 0 { + panic("max exceeded") + } + } + + return t +} + func TestMaintenanceEntryRepository_GetLog(t *testing.T) { item := useItems(t, 1)[0] // Create 10 maintenance entries for the item created := make([]MaintenanceEntryCreate, 10) - lastMonth := time.Now().AddDate(0, -1, 0) thisMonth := time.Now() + lastMonth := getPrevMonth(thisMonth) for i := 0; i < 10; i++ { dt := lastMonth diff --git a/frontend/components/Chart/Line.vue b/frontend/components/Chart/Line.vue index c74e759..c36ef93 100644 --- a/frontend/components/Chart/Line.vue +++ b/frontend/components/Chart/Line.vue @@ -56,7 +56,6 @@ const calcWidth = ref(0); function resize() { - console.log("resize", el.value?.offsetHeight, el.value?.offsetWidth); calcHeight.value = el.value?.offsetHeight || 0; calcWidth.value = el.value?.offsetWidth || 0; } diff --git a/frontend/components/Item/Card.vue b/frontend/components/Item/Card.vue index 7dfb62a..96b3b04 100644 --- a/frontend/components/Item/Card.vue +++ b/frontend/components/Item/Card.vue @@ -1,22 +1,38 @@ + + + + diff --git a/frontend/lib/api/types/data-contracts.ts b/frontend/lib/api/types/data-contracts.ts index 7e4fd54..a36df88 100644 --- a/frontend/lib/api/types/data-contracts.ts +++ b/frontend/lib/api/types/data-contracts.ts @@ -96,7 +96,7 @@ export interface ItemOut { /** @example "0" */ purchasePrice: string; /** Purchase */ - purchaseTime: Date; + purchaseTime: string; quantity: number; serialNumber: string; soldNotes: string; @@ -148,7 +148,7 @@ export interface ItemUpdate { /** @example "0" */ purchasePrice: string; /** Purchase */ - purchaseTime: Date; + purchaseTime: string; quantity: number; /** Identifications */ serialNumber: string; @@ -228,7 +228,7 @@ export interface LocationUpdate { export interface MaintenanceEntry { /** @example "0" */ cost: string; - date: Date; + date: string; description: string; id: string; name: string; @@ -237,7 +237,7 @@ export interface MaintenanceEntry { export interface MaintenanceEntryCreate { /** @example "0" */ cost: string; - date: Date; + date: string; description: string; name: string; } @@ -245,7 +245,7 @@ export interface MaintenanceEntryCreate { export interface MaintenanceEntryUpdate { /** @example "0" */ cost: string; - date: Date; + date: string; description: string; name: string; } @@ -257,7 +257,7 @@ export interface MaintenanceLog { itemId: string; } -export interface PaginationResultRepoItemSummary { +export interface PaginationResultItemSummary { items: ItemSummary[]; page: number; pageSize: number; @@ -294,7 +294,7 @@ export interface ValueOverTime { } export interface ValueOverTimeEntry { - date: Date; + date: string; name: string; value: number; } @@ -347,13 +347,13 @@ export interface EnsureAssetIDResult { } export interface GroupInvitation { - expiresAt: Date; + expiresAt: string; token: string; uses: number; } export interface GroupInvitationCreate { - expiresAt: Date; + expiresAt: string; uses: number; } @@ -363,6 +363,6 @@ export interface ItemAttachmentToken { export interface TokenResponse { attachmentToken: string; - expiresAt: Date; + expiresAt: string; token: string; } diff --git a/frontend/pages/item/[id]/index.vue b/frontend/pages/item/[id]/index.vue index 4bcef2c..42c4995 100644 --- a/frontend/pages/item/[id]/index.vue +++ b/frontend/pages/item/[id]/index.vue @@ -30,6 +30,15 @@ refresh(); }); + const lastRoute = ref(route.fullPath); + watchEffect(() => { + if (lastRoute.value.endsWith("edit")) { + refresh(); + } + + lastRoute.value = route.fullPath; + }); + type FilteredAttachments = { attachments: ItemAttachment[]; warranty: ItemAttachment[]; @@ -325,6 +334,30 @@ onClickOutside(refDialogBody, () => { closeDialog(); }); + + const currentPath = computed(() => { + return route.path; + }); + + const tabs = computed(() => { + return [ + { + id: "details", + name: "Details", + to: `/item/${itemId.value}`, + }, + { + id: "log", + name: "Log", + to: `/item/${itemId.value}/log`, + }, + { + id: "edit", + name: "Edit", + to: `/item/${itemId.value}/edit`, + }, + ]; + }); diff --git a/scripts/process-types/main.go b/scripts/process-types/main.go index 59c2530..06e3ec7 100644 --- a/scripts/process-types/main.go +++ b/scripts/process-types/main.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "io/ioutil" "os" "regexp" ) @@ -31,7 +30,7 @@ func main() { } text := "/* post-processed by ./scripts/process-types.go */\n" - data, err := ioutil.ReadFile(path) + data, err := os.ReadFile(path) if err != nil { fmt.Println(err) os.Exit(1) @@ -63,7 +62,7 @@ func main() { text = regex.ReplaceAllString(text, replace) } - err = ioutil.WriteFile(path, []byte(text), 0644) + err = os.WriteFile(path, []byte(text), 0644) if err != nil { fmt.Println(err) os.Exit(1) From 91d0c588d906e6008ca0c6ff993f8fd2fd43ee90 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sat, 21 Jan 2023 21:15:23 -0900 Subject: [PATCH 122/435] refactor: refactor item page UI (#235) * fix generated types * fix tailwind auto-complete * force lowercase buttons * add title and change style for items page * add copy button support for item details * empty state for log * fix duplicate padding * add option for create without closing the current dialog. * hide purchase price is not set * invert toggle for edit mode * update styles on item cards * add edit support for maintenance logs --- .vscode/settings.json | 9 +++ frontend/assets/css/main.css | 4 + frontend/components/Item/Card.vue | 18 ++--- frontend/components/Item/CreateModal.vue | 51 ++++++++----- frontend/components/global/CopyText.vue | 24 +++++- .../global/DetailsSection/DetailsSection.vue | 14 +++- .../components/global/DetailsSection/types.ts | 1 + frontend/composables/use-preferences.ts | 6 +- frontend/lib/api/types/data-contracts.ts | 14 ++-- frontend/pages/item/[id]/index.vue | 27 +++++-- frontend/pages/item/[id]/index/edit.vue | 20 ++--- frontend/pages/item/[id]/index/log.vue | 73 ++++++++++++++++++- frontend/pages/profile.vue | 4 +- 13 files changed, 197 insertions(+), 68 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5080f25..d0ae55d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,4 +21,13 @@ "editor.defaultFormatter": "dbaeumer.vscode-eslint" }, "eslint.format.enable": true, + "css.validate": false, + "tailwindCSS.includeLanguages": { + "vue": "html", + "vue-html": "html" + }, + "editor.quickSuggestions": { + "strings": true + }, + "tailwindCSS.experimental.configFile": "./frontend/tailwind.config.js" } diff --git a/frontend/assets/css/main.css b/frontend/assets/css/main.css index a3c199c..d83faf6 100644 --- a/frontend/assets/css/main.css +++ b/frontend/assets/css/main.css @@ -1,3 +1,7 @@ .text-no-transform { text-transform: none !important; +} + +.btn { + text-transform: none !important; } \ No newline at end of file diff --git a/frontend/components/Item/Card.vue b/frontend/components/Item/Card.vue index 6ca1704..c0b5b88 100644 --- a/frontend/components/Item/Card.vue +++ b/frontend/components/Item/Card.vue @@ -1,22 +1,18 @@