refactor: repositories (#28)

* cleanup unnecessary mocks

* refactor document storage location

* remove unused function

* move ownership to document types to repo package

* move types and mappers to repo package

* refactor sets to own package
This commit is contained in:
Hayden 2022-09-27 15:52:13 -08:00 committed by GitHub
parent 2e82398e5c
commit 343290a55a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
79 changed files with 3169 additions and 3160 deletions

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,302 @@
basePath: /api
definitions:
repo.DocumentOut:
properties:
id:
type: string
path:
type: string
title:
type: string
type: object
repo.ItemAttachment:
properties:
createdAt:
type: string
document:
$ref: '#/definitions/repo.DocumentOut'
id:
type: string
type:
type: string
updatedAt:
type: string
type: object
repo.ItemAttachmentUpdate:
properties:
title:
type: string
type:
type: string
type: object
repo.ItemCreate:
properties:
description:
type: string
labelIds:
items:
type: string
type: array
locationId:
description: Edges
type: string
name:
type: string
type: object
repo.ItemOut:
properties:
attachments:
items:
$ref: '#/definitions/repo.ItemAttachment'
type: array
createdAt:
type: string
description:
type: string
id:
type: string
insured:
type: boolean
labels:
items:
$ref: '#/definitions/repo.LabelSummary'
type: array
lifetimeWarranty:
description: Warranty
type: boolean
location:
$ref: '#/definitions/repo.LocationSummary'
description: Edges
manufacturer:
type: string
modelNumber:
type: string
name:
type: string
notes:
description: Extras
type: string
purchaseFrom:
type: string
purchasePrice:
example: "0"
type: string
purchaseTime:
description: Purchase
type: string
quantity:
type: integer
serialNumber:
type: string
soldNotes:
type: string
soldPrice:
example: "0"
type: string
soldTime:
description: Sold
type: string
soldTo:
type: string
updatedAt:
type: string
warrantyDetails:
type: string
warrantyExpires:
type: string
type: object
repo.ItemSummary:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
insured:
type: boolean
labels:
items:
$ref: '#/definitions/repo.LabelSummary'
type: array
location:
$ref: '#/definitions/repo.LocationSummary'
description: Edges
name:
type: string
quantity:
type: integer
updatedAt:
type: string
type: object
repo.ItemUpdate:
properties:
description:
type: string
id:
type: string
insured:
type: boolean
labelIds:
items:
type: string
type: array
lifetimeWarranty:
description: Warranty
type: boolean
locationId:
description: Edges
type: string
manufacturer:
type: string
modelNumber:
type: string
name:
type: string
notes:
description: Extras
type: string
purchaseFrom:
type: string
purchasePrice:
example: "0"
type: string
purchaseTime:
description: Purchase
type: string
quantity:
type: integer
serialNumber:
description: Identifications
type: string
soldNotes:
type: string
soldPrice:
example: "0"
type: string
soldTime:
description: Sold
type: string
soldTo:
type: string
warrantyDetails:
type: string
warrantyExpires:
type: string
type: object
repo.LabelCreate:
properties:
color:
type: string
description:
type: string
name:
type: string
type: object
repo.LabelOut:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
items:
items:
$ref: '#/definitions/repo.ItemSummary'
type: array
name:
type: string
updatedAt:
type: string
type: object
repo.LabelSummary:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
name:
type: string
updatedAt:
type: string
type: object
repo.LocationCreate:
properties:
description:
type: string
name:
type: string
type: object
repo.LocationOut:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
items:
items:
$ref: '#/definitions/repo.ItemSummary'
type: array
name:
type: string
updatedAt:
type: string
type: object
repo.LocationOutCount:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
itemCount:
type: integer
name:
type: string
updatedAt:
type: string
type: object
repo.LocationSummary:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
name:
type: string
updatedAt:
type: string
type: object
repo.UserOut:
properties:
email:
type: string
groupId:
type: string
groupName:
type: string
id:
type: string
isSuperuser:
type: boolean
name:
type: string
type: object
repo.UserUpdate:
properties:
email:
type: string
name:
type: string
type: object
server.Result:
properties:
details: {}
@ -21,10 +318,21 @@ definitions:
reason:
type: string
type: object
types.ApiSummary:
services.UserRegistration:
properties:
email:
type: string
groupName:
type: string
name:
type: string
password:
type: string
type: object
v1.ApiSummary:
properties:
build:
$ref: '#/definitions/types.Build'
$ref: '#/definitions/v1.Build'
health:
type: boolean
message:
@ -36,7 +344,7 @@ definitions:
type: string
type: array
type: object
types.Build:
v1.Build:
properties:
buildTime:
type: string
@ -45,367 +353,18 @@ definitions:
version:
type: string
type: object
types.DocumentOut:
properties:
id:
type: string
path:
type: string
title:
type: string
type: object
types.ItemAttachment:
properties:
createdAt:
type: string
document:
$ref: '#/definitions/types.DocumentOut'
id:
type: string
type:
type: string
updatedAt:
type: string
type: object
types.ItemAttachmentToken:
v1.ItemAttachmentToken:
properties:
token:
type: string
type: object
types.ItemAttachmentUpdate:
properties:
title:
type: string
type:
type: string
type: object
types.ItemCreate:
properties:
description:
type: string
labelIds:
items:
type: string
type: array
locationId:
description: Edges
type: string
name:
type: string
type: object
types.ItemOut:
properties:
attachments:
items:
$ref: '#/definitions/types.ItemAttachment'
type: array
createdAt:
type: string
description:
type: string
id:
type: string
insured:
type: boolean
labels:
items:
$ref: '#/definitions/types.LabelSummary'
type: array
lifetimeWarranty:
description: Warranty
type: boolean
location:
$ref: '#/definitions/types.LocationSummary'
description: Edges
manufacturer:
type: string
modelNumber:
type: string
name:
type: string
notes:
description: Extras
type: string
purchaseFrom:
type: string
purchasePrice:
example: "0"
type: string
purchaseTime:
description: Purchase
type: string
quantity:
type: integer
serialNumber:
description: Identifications
type: string
soldNotes:
type: string
soldPrice:
example: "0"
type: string
soldTime:
description: Sold
type: string
soldTo:
type: string
updatedAt:
type: string
warrantyDetails:
type: string
warrantyExpires:
type: string
type: object
types.ItemSummary:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
insured:
type: boolean
labels:
items:
$ref: '#/definitions/types.LabelSummary'
type: array
lifetimeWarranty:
description: Warranty
type: boolean
location:
$ref: '#/definitions/types.LocationSummary'
description: Edges
manufacturer:
type: string
modelNumber:
type: string
name:
type: string
notes:
description: Extras
type: string
purchaseFrom:
type: string
purchasePrice:
example: "0"
type: string
purchaseTime:
description: Purchase
type: string
quantity:
type: integer
serialNumber:
description: Identifications
type: string
soldNotes:
type: string
soldPrice:
example: "0"
type: string
soldTime:
description: Sold
type: string
soldTo:
type: string
updatedAt:
type: string
warrantyDetails:
type: string
warrantyExpires:
type: string
type: object
types.ItemUpdate:
properties:
description:
type: string
id:
type: string
insured:
type: boolean
labelIds:
items:
type: string
type: array
lifetimeWarranty:
description: Warranty
type: boolean
locationId:
description: Edges
type: string
manufacturer:
type: string
modelNumber:
type: string
name:
type: string
notes:
description: Extras
type: string
purchaseFrom:
type: string
purchasePrice:
example: "0"
type: string
purchaseTime:
description: Purchase
type: string
quantity:
type: integer
serialNumber:
description: Identifications
type: string
soldNotes:
type: string
soldPrice:
example: "0"
type: string
soldTime:
description: Sold
type: string
soldTo:
type: string
warrantyDetails:
type: string
warrantyExpires:
type: string
type: object
types.LabelCreate:
properties:
color:
type: string
description:
type: string
name:
type: string
type: object
types.LabelOut:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
items:
items:
$ref: '#/definitions/types.ItemSummary'
type: array
name:
type: string
updatedAt:
type: string
type: object
types.LabelSummary:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
name:
type: string
updatedAt:
type: string
type: object
types.LocationCount:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
itemCount:
type: integer
name:
type: string
updatedAt:
type: string
type: object
types.LocationCreate:
properties:
description:
type: string
name:
type: string
type: object
types.LocationOut:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
items:
items:
$ref: '#/definitions/types.ItemSummary'
type: array
name:
type: string
updatedAt:
type: string
type: object
types.LocationSummary:
properties:
createdAt:
type: string
description:
type: string
id:
type: string
name:
type: string
updatedAt:
type: string
type: object
types.TokenResponse:
v1.TokenResponse:
properties:
expiresAt:
type: string
token:
type: string
type: object
types.UserIn:
properties:
email:
type: string
name:
type: string
password:
type: string
type: object
types.UserOut:
properties:
email:
type: string
groupId:
type: string
groupName:
type: string
id:
type: string
isSuperuser:
type: boolean
name:
type: string
type: object
types.UserRegistration:
properties:
groupName:
type: string
user:
$ref: '#/definitions/types.UserIn'
type: object
types.UserUpdate:
properties:
email:
type: string
name:
type: string
type: object
info:
contact:
name: Don't
@ -430,7 +389,7 @@ paths:
- properties:
items:
items:
$ref: '#/definitions/types.ItemSummary'
$ref: '#/definitions/repo.ItemSummary'
type: array
type: object
security:
@ -445,14 +404,14 @@ paths:
name: payload
required: true
schema:
$ref: '#/definitions/types.ItemCreate'
$ref: '#/definitions/repo.ItemCreate'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/types.ItemSummary'
$ref: '#/definitions/repo.ItemSummary'
security:
- Bearer: []
summary: Create a new item
@ -489,7 +448,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/types.ItemOut'
$ref: '#/definitions/repo.ItemOut'
security:
- Bearer: []
summary: Gets a item and fields
@ -507,14 +466,14 @@ paths:
name: payload
required: true
schema:
$ref: '#/definitions/types.ItemUpdate'
$ref: '#/definitions/repo.ItemUpdate'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/types.ItemOut'
$ref: '#/definitions/repo.ItemOut'
security:
- Bearer: []
summary: updates a item
@ -549,7 +508,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/types.ItemOut'
$ref: '#/definitions/repo.ItemOut'
"422":
description: Unprocessable Entity
schema:
@ -600,7 +559,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/types.ItemAttachmentToken'
$ref: '#/definitions/v1.ItemAttachmentToken'
security:
- Bearer: []
summary: retrieves an attachment for an item
@ -623,12 +582,12 @@ paths:
name: payload
required: true
schema:
$ref: '#/definitions/types.ItemAttachmentUpdate'
$ref: '#/definitions/repo.ItemAttachmentUpdate'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/types.ItemOut'
$ref: '#/definitions/repo.ItemOut'
security:
- Bearer: []
summary: retrieves an attachment for an item
@ -688,7 +647,7 @@ paths:
- properties:
items:
items:
$ref: '#/definitions/types.LabelOut'
$ref: '#/definitions/repo.LabelOut'
type: array
type: object
security:
@ -703,14 +662,14 @@ paths:
name: payload
required: true
schema:
$ref: '#/definitions/types.LabelCreate'
$ref: '#/definitions/repo.LabelCreate'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/types.LabelSummary'
$ref: '#/definitions/repo.LabelSummary'
security:
- Bearer: []
summary: Create a new label
@ -747,7 +706,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/types.LabelOut'
$ref: '#/definitions/repo.LabelOut'
security:
- Bearer: []
summary: Gets a label and fields
@ -766,7 +725,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/types.LabelOut'
$ref: '#/definitions/repo.LabelOut'
security:
- Bearer: []
summary: updates a label
@ -785,7 +744,7 @@ paths:
- properties:
items:
items:
$ref: '#/definitions/types.LocationCount'
$ref: '#/definitions/repo.LocationOutCount'
type: array
type: object
security:
@ -800,14 +759,14 @@ paths:
name: payload
required: true
schema:
$ref: '#/definitions/types.LocationCreate'
$ref: '#/definitions/repo.LocationCreate'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/types.LocationSummary'
$ref: '#/definitions/repo.LocationSummary'
security:
- Bearer: []
summary: Create a new location
@ -844,7 +803,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/types.LocationOut'
$ref: '#/definitions/repo.LocationOut'
security:
- Bearer: []
summary: Gets a location and fields
@ -863,7 +822,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/types.LocationOut'
$ref: '#/definitions/repo.LocationOut'
security:
- Bearer: []
summary: updates a location
@ -877,7 +836,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/types.ApiSummary'
$ref: '#/definitions/v1.ApiSummary'
summary: Retrieves the basic information about the API
tags:
- Base
@ -903,7 +862,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/types.TokenResponse'
$ref: '#/definitions/v1.TokenResponse'
summary: User Login
tags:
- Authentication
@ -938,7 +897,7 @@ paths:
name: payload
required: true
schema:
$ref: '#/definitions/types.UserRegistration'
$ref: '#/definitions/services.UserRegistration'
produces:
- application/json
responses:
@ -970,7 +929,7 @@ paths:
- $ref: '#/definitions/server.Result'
- properties:
item:
$ref: '#/definitions/types.UserOut'
$ref: '#/definitions/repo.UserOut'
type: object
security:
- Bearer: []
@ -984,7 +943,7 @@ paths:
name: payload
required: true
schema:
$ref: '#/definitions/types.UserUpdate'
$ref: '#/definitions/repo.UserUpdate'
produces:
- application/json
responses:
@ -995,7 +954,7 @@ paths:
- $ref: '#/definitions/server.Result'
- properties:
item:
$ref: '#/definitions/types.UserUpdate'
$ref: '#/definitions/repo.UserUpdate'
type: object
security:
- Bearer: []

View file

@ -81,8 +81,8 @@ func run(cfg *config.Config) error {
}
app.db = c
app.repos = repo.EntAllRepos(c)
app.services = services.NewServices(app.repos, cfg.Storage.Data)
app.repos = repo.EntAllRepos(c, cfg.Storage.Data)
app.services = services.NewServices(app.repos)
// =========================================================================
// Start Server

View file

@ -57,7 +57,7 @@ func (a *app) mwAuthToken(next http.Handler) http.Handler {
return
}
r = r.WithContext(services.SetUserCtx(r.Context(), usr, requestToken))
r = r.WithContext(services.SetUserCtx(r.Context(), &usr, requestToken))
next.ServeHTTP(w, r)
})

View file

@ -14,7 +14,6 @@ import (
_ "github.com/hay-kot/homebox/backend/app/api/docs"
v1 "github.com/hay-kot/homebox/backend/app/api/v1"
"github.com/hay-kot/homebox/backend/internal/repo"
"github.com/hay-kot/homebox/backend/internal/types"
"github.com/rs/zerolog/log"
httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware
)
@ -45,7 +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))
{
r.Get(v1Base("/status"), v1Ctrl.HandleBase(func() bool { return true }, types.Build{
r.Get(v1Base("/status"), v1Ctrl.HandleBase(func() bool { return true }, v1.Build{
Version: Version,
Commit: Commit,
BuildTime: BuildTime,

View file

@ -4,7 +4,6 @@ import (
"net/http"
"github.com/hay-kot/homebox/backend/internal/services"
"github.com/hay-kot/homebox/backend/internal/types"
"github.com/hay-kot/homebox/backend/pkgs/server"
)
@ -19,6 +18,22 @@ type V1Controller struct {
maxUploadSize int64
}
type (
Build struct {
Version string `json:"version"`
Commit string `json:"commit"`
BuildTime string `json:"buildTime"`
}
ApiSummary struct {
Healthy bool `json:"health"`
Versions []string `json:"versions"`
Title string `json:"title"`
Message string `json:"message"`
Build Build
}
)
func BaseUrlFunc(prefix string) func(s string) string {
v1Base := prefix + "/v1"
prefixFunc := func(s string) string {
@ -42,11 +57,11 @@ type ReadyFunc func() bool
// @Summary Retrieves the basic information about the API
// @Tags Base
// @Produce json
// @Success 200 {object} types.ApiSummary
// @Success 200 {object} ApiSummary
// @Router /v1/status [GET]
func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build types.Build) http.HandlerFunc {
func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
server.Respond(w, http.StatusOK, types.ApiSummary{
server.Respond(w, http.StatusOK, ApiSummary{
Healthy: ready(),
Title: "Go API Template",
Message: "Welcome to the Go API Template Application!",

View file

@ -1,47 +0,0 @@
package v1
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/hay-kot/homebox/backend/internal/types"
"github.com/stretchr/testify/assert"
)
func Test_NewHandlerV1(t *testing.T) {
v1Base := BaseUrlFunc("/testing/v1")
ctrl := NewControllerV1(mockHandler.svc)
assert.NotNil(t, ctrl)
assert.Equal(t, "/testing/v1/v1/abc123", v1Base("/abc123"))
assert.Equal(t, "/testing/v1/v1/abc123", v1Base("/abc123"))
}
func TestHandlersv1_HandleBase(t *testing.T) {
// Setup
hdlrFunc := mockHandler.HandleBase(func() bool { return true }, types.Build{
Version: "0.1.0",
Commit: "HEAD",
BuildTime: "now",
})
// Call Handler Func
rr := httptest.NewRecorder()
hdlrFunc(rr, nil)
// Validate Status Code
if rr.Code != http.StatusOK {
t.Errorf("Expected status code to be %d, got %d", http.StatusOK, rr.Code)
}
// Validate Json Payload
expected := `{"health":true,"versions":null,"title":"Go API Template","message":"Welcome to the Go API Template Application!","Build":{"version":"0.1.0","commit":"HEAD","buildTime":"now"}}`
if rr.Body.String() != expected {
t.Errorf("Expected json to be %s, got %s", expected, rr.Body.String())
}
}

View file

@ -1,53 +0,0 @@
package v1
import (
"context"
"testing"
"github.com/hay-kot/homebox/backend/ent"
"github.com/hay-kot/homebox/backend/internal/mocks"
"github.com/hay-kot/homebox/backend/internal/mocks/factories"
"github.com/hay-kot/homebox/backend/internal/types"
)
var mockHandler = &V1Controller{}
var users = []*ent.User{}
func userPool() func() {
create := []types.UserCreate{
factories.UserFactory(),
factories.UserFactory(),
factories.UserFactory(),
factories.UserFactory(),
}
userOut := []*ent.User{}
for _, user := range create {
usrOut, _ := mockHandler.svc.Admin.Create(context.Background(), user)
userOut = append(userOut, usrOut)
}
users = userOut
purge := func() {
_ = mockHandler.svc.Admin.DeleteAll(context.Background())
}
return purge
}
func TestMain(m *testing.M) {
// Set Handler Vars
repos, closeDb := mocks.GetEntRepos()
mockHandler.svc = mocks.GetMockServices(repos)
defer func() {
_ = closeDb()
}()
purge := userPool()
defer purge()
m.Run()
}

View file

@ -5,8 +5,8 @@ import (
"github.com/go-chi/chi/v5"
"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/types"
"github.com/hay-kot/homebox/backend/pkgs/server"
"github.com/rs/zerolog/log"
)
@ -21,12 +21,12 @@ and makes it a little more consistent when error handling and logging.
// from the context. If either of these fail, it will return an error. When an error
// occurs it will also write the error to the response. As such, if an error is returned
// from this function you can return immediately without writing to the response.
func (ctrl *V1Controller) partialParseIdAndUser(w http.ResponseWriter, r *http.Request) (uuid.UUID, *types.UserOut, error) {
func (ctrl *V1Controller) partialParseIdAndUser(w http.ResponseWriter, r *http.Request) (uuid.UUID, *repo.UserOut, error) {
uid, 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, nil, err
return uuid.Nil, &repo.UserOut{}, err
}
user := services.UseUserCtx(r.Context())

View file

@ -3,13 +3,25 @@ package v1
import (
"errors"
"net/http"
"time"
"github.com/hay-kot/homebox/backend/internal/services"
"github.com/hay-kot/homebox/backend/internal/types"
"github.com/hay-kot/homebox/backend/pkgs/server"
"github.com/rs/zerolog/log"
)
type (
TokenResponse struct {
Token string `json:"token"`
ExpiresAt time.Time `json:"expiresAt"`
}
LoginForm struct {
Username string `json:"username"`
Password string `json:"password"`
}
)
// HandleAuthLogin godoc
// @Summary User Login
// @Tags Authentication
@ -18,11 +30,11 @@ import (
// @Param username formData string false "string" example(admin@admin.com)
// @Param password formData string false "string" example(admin)
// @Produce json
// @Success 200 {object} types.TokenResponse
// @Success 200 {object} TokenResponse
// @Router /v1/users/login [POST]
func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
loginForm := &types.LoginForm{}
loginForm := &LoginForm{}
if r.Header.Get("Content-Type") == server.ContentFormUrlEncoded {
err := r.ParseForm()
@ -59,9 +71,9 @@ func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc {
return
}
server.Respond(w, http.StatusOK, types.TokenResponse{
BearerToken: "Bearer " + newToken.Raw,
ExpiresAt: newToken.ExpiresAt,
server.Respond(w, http.StatusOK, TokenResponse{
Token: "Bearer " + newToken.Raw,
ExpiresAt: newToken.ExpiresAt,
})
}
}

View file

@ -4,8 +4,8 @@ import (
"encoding/csv"
"net/http"
"github.com/hay-kot/homebox/backend/internal/repo"
"github.com/hay-kot/homebox/backend/internal/services"
"github.com/hay-kot/homebox/backend/internal/types"
"github.com/hay-kot/homebox/backend/pkgs/server"
"github.com/rs/zerolog/log"
)
@ -14,7 +14,7 @@ import (
// @Summary Get All Items
// @Tags Items
// @Produce json
// @Success 200 {object} server.Results{items=[]types.ItemSummary}
// @Success 200 {object} server.Results{items=[]repo.ItemSummary}
// @Router /v1/items [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemsGetAll() http.HandlerFunc {
@ -34,13 +34,13 @@ func (ctrl *V1Controller) HandleItemsGetAll() http.HandlerFunc {
// @Summary Create a new item
// @Tags Items
// @Produce json
// @Param payload body types.ItemCreate true "Item Data"
// @Success 200 {object} types.ItemSummary
// @Param payload body repo.ItemCreate true "Item Data"
// @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) {
createData := types.ItemCreate{}
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)
@ -90,7 +90,7 @@ func (ctrl *V1Controller) HandleItemDelete() http.HandlerFunc {
// @Tags Items
// @Produce json
// @Param id path string true "Item ID"
// @Success 200 {object} types.ItemOut
// @Success 200 {object} repo.ItemOut
// @Router /v1/items/{id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc {
@ -114,14 +114,14 @@ func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc {
// @Summary updates a item
// @Tags Items
// @Produce json
// @Param id path string true "Item ID"
// @Param payload body types.ItemUpdate true "Item Data"
// @Success 200 {object} types.ItemOut
// @Param id path string true "Item ID"
// @Param payload body repo.ItemUpdate true "Item Data"
// @Success 200 {object} repo.ItemOut
// @Router /v1/items/{id} [PUT]
// @Security Bearer
func (ctrl *V1Controller) HandleItemUpdate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
body := types.ItemUpdate{}
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)

View file

@ -4,17 +4,22 @@ import (
"errors"
"fmt"
"net/http"
"path/filepath"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/ent/attachment"
"github.com/hay-kot/homebox/backend/internal/repo"
"github.com/hay-kot/homebox/backend/internal/services"
"github.com/hay-kot/homebox/backend/internal/types"
"github.com/hay-kot/homebox/backend/pkgs/server"
"github.com/rs/zerolog/log"
)
type (
ItemAttachmentToken struct {
Token string `json:"token"`
}
)
// HandleItemsImport godocs
// @Summary imports items into the database
// @Tags Items
@ -23,7 +28,7 @@ import (
// @Param file formData file true "File attachment"
// @Param type formData string true "Type of file"
// @Param name formData string true "name of the file including extension"
// @Success 200 {object} types.ItemOut
// @Success 200 {object} repo.ItemOut
// @Failure 422 {object} []server.ValidationError
// @Router /v1/items/{id}/attachments [POST]
// @Security Bearer
@ -105,7 +110,7 @@ func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
token := server.GetParam(r, "token", "")
path, err := ctrl.svc.Items.AttachmentPath(r.Context(), token)
doc, err := ctrl.svc.Items.AttachmentPath(r.Context(), token)
if err != nil {
log.Err(err).Msg("failed to get attachment")
@ -113,9 +118,9 @@ func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc {
return
}
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filepath.Base(path)))
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", doc.Title))
w.Header().Set("Content-Type", "application/octet-stream")
http.ServeFile(w, r, path)
http.ServeFile(w, r, doc.Path)
}
}
@ -125,7 +130,7 @@ func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc {
// @Produce application/octet-stream
// @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID"
// @Success 200 {object} types.ItemAttachmentToken
// @Success 200 {object} ItemAttachmentToken
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentToken() http.HandlerFunc {
@ -147,10 +152,10 @@ func (ctrl *V1Controller) HandleItemAttachmentDelete() http.HandlerFunc {
// HandleItemAttachmentUpdate godocs
// @Summary retrieves an attachment for an item
// @Tags Items
// @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID"
// @Param payload body types.ItemAttachmentUpdate true "Attachment Update"
// @Success 200 {object} types.ItemOut
// @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID"
// @Param payload body repo.ItemAttachmentUpdate true "Attachment Update"
// @Success 200 {object} repo.ItemOut
// @Router /v1/items/{id}/attachments/{attachment_id} [PUT]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentUpdate() http.HandlerFunc {
@ -201,7 +206,7 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
}
}
server.Respond(w, http.StatusOK, types.ItemAttachmentToken{Token: token})
server.Respond(w, http.StatusOK, ItemAttachmentToken{Token: token})
// Delete Attachment Handler
case http.MethodDelete:
@ -216,7 +221,7 @@ func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r
// Update Attachment Handler
case http.MethodPut:
var attachment types.ItemAttachmentUpdate
var attachment repo.ItemAttachmentUpdate
err = server.Decode(r, &attachment)
if err != nil {
log.Err(err).Msg("failed to decode attachment")

View file

@ -4,8 +4,8 @@ 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/types"
"github.com/hay-kot/homebox/backend/pkgs/server"
"github.com/rs/zerolog/log"
)
@ -14,7 +14,7 @@ import (
// @Summary Get All Labels
// @Tags Labels
// @Produce json
// @Success 200 {object} server.Results{items=[]types.LabelOut}
// @Success 200 {object} server.Results{items=[]repo.LabelOut}
// @Router /v1/labels [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleLabelsGetAll() http.HandlerFunc {
@ -34,13 +34,13 @@ func (ctrl *V1Controller) HandleLabelsGetAll() http.HandlerFunc {
// @Summary Create a new label
// @Tags Labels
// @Produce json
// @Param payload body types.LabelCreate true "Label Data"
// @Success 200 {object} types.LabelSummary
// @Param payload body repo.LabelCreate true "Label Data"
// @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) {
createData := types.LabelCreate{}
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)
@ -90,7 +90,7 @@ func (ctrl *V1Controller) HandleLabelDelete() http.HandlerFunc {
// @Tags Labels
// @Produce json
// @Param id path string true "Label ID"
// @Success 200 {object} types.LabelOut
// @Success 200 {object} repo.LabelOut
// @Router /v1/labels/{id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleLabelGet() http.HandlerFunc {
@ -122,12 +122,12 @@ func (ctrl *V1Controller) HandleLabelGet() http.HandlerFunc {
// @Tags Labels
// @Produce json
// @Param id path string true "Label ID"
// @Success 200 {object} types.LabelOut
// @Success 200 {object} repo.LabelOut
// @Router /v1/labels/{id} [PUT]
// @Security Bearer
func (ctrl *V1Controller) HandleLabelUpdate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
body := types.LabelUpdate{}
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)

View file

@ -4,8 +4,8 @@ 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/types"
"github.com/hay-kot/homebox/backend/pkgs/server"
"github.com/rs/zerolog/log"
)
@ -14,7 +14,7 @@ import (
// @Summary Get All Locations
// @Tags Locations
// @Produce json
// @Success 200 {object} server.Results{items=[]types.LocationCount}
// @Success 200 {object} server.Results{items=[]repo.LocationOutCount}
// @Router /v1/locations [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleLocationGetAll() http.HandlerFunc {
@ -35,13 +35,13 @@ func (ctrl *V1Controller) HandleLocationGetAll() http.HandlerFunc {
// @Summary Create a new location
// @Tags Locations
// @Produce json
// @Param payload body types.LocationCreate true "Location Data"
// @Success 200 {object} types.LocationSummary
// @Param payload body repo.LocationCreate true "Location Data"
// @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) {
createData := types.LocationCreate{}
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)
@ -90,7 +90,7 @@ func (ctrl *V1Controller) HandleLocationDelete() http.HandlerFunc {
// @Tags Locations
// @Produce json
// @Param id path string true "Location ID"
// @Success 200 {object} types.LocationOut
// @Success 200 {object} repo.LocationOut
// @Router /v1/locations/{id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc {
@ -105,12 +105,16 @@ func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc {
if ent.IsNotFound(err) {
log.Err(err).
Str("id", uid.String()).
Str("gid", user.GroupID.String()).
Msg("location not found")
server.RespondError(w, http.StatusNotFound, err)
return
}
log.Err(err).Msg("failed to get location")
log.Err(err).
Str("id", uid.String()).
Str("gid", user.GroupID.String()).
Msg("failed to get location")
server.RespondServerError(w)
return
}
@ -123,12 +127,12 @@ func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc {
// @Tags Locations
// @Produce json
// @Param id path string true "Location ID"
// @Success 200 {object} types.LocationOut
// @Success 200 {object} repo.LocationOut
// @Router /v1/locations/{id} [PUT]
// @Security Bearer
func (ctrl *V1Controller) HandleLocationUpdate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
body := types.LocationUpdate{}
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)

View file

@ -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/types"
"github.com/hay-kot/homebox/backend/pkgs/server"
"github.com/rs/zerolog/log"
)
@ -14,12 +14,12 @@ import (
// @Summary Get the current user
// @Tags User
// @Produce json
// @Param payload body types.UserRegistration true "User Data"
// @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) {
regData := types.UserRegistration{}
regData := services.UserRegistration{}
if err := server.Decode(r, &regData); err != nil {
log.Err(err).Msg("failed to decode user registration data")
@ -29,6 +29,7 @@ func (ctrl *V1Controller) HandleUserRegistration() http.HandlerFunc {
_, 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
}
@ -41,7 +42,7 @@ func (ctrl *V1Controller) HandleUserRegistration() http.HandlerFunc {
// @Summary Get the current user
// @Tags User
// @Produce json
// @Success 200 {object} server.Result{item=types.UserOut}
// @Success 200 {object} server.Result{item=repo.UserOut}
// @Router /v1/users/self [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleUserSelf() http.HandlerFunc {
@ -62,13 +63,13 @@ func (ctrl *V1Controller) HandleUserSelf() http.HandlerFunc {
// @Summary Update the current user
// @Tags User
// @Produce json
// @Param payload body types.UserUpdate true "User Data"
// @Success 200 {object} server.Result{item=types.UserUpdate}
// @Param payload body repo.UserUpdate true "User Data"
// @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) {
updateData := types.UserUpdate{}
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)