implement pagination for items

This commit is contained in:
Hayden 2022-10-12 21:08:22 -08:00
parent 85a96cde91
commit baa352d7ad
19 changed files with 435 additions and 327 deletions

View file

@ -77,6 +77,18 @@ const docTemplate = `{
"name": "q", "name": "q",
"in": "query" "in": "query"
}, },
{
"type": "integer",
"description": "page number",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "items per page",
"name": "pageSize",
"in": "query"
},
{ {
"type": "array", "type": "array",
"items": { "items": {
@ -102,22 +114,7 @@ const docTemplate = `{
"200": { "200": {
"description": "OK", "description": "OK",
"schema": { "schema": {
"allOf": [ "$ref": "#/definitions/repo.PaginationResult-repo_ItemSummary"
{
"$ref": "#/definitions/server.Results"
},
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
}
}
}
]
} }
} }
} }
@ -181,7 +178,7 @@ const docTemplate = `{
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -282,7 +279,7 @@ const docTemplate = `{
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -382,7 +379,7 @@ const docTemplate = `{
], ],
"responses": { "responses": {
"200": { "200": {
"description": "" "description": "OK"
} }
} }
} }
@ -498,7 +495,7 @@ const docTemplate = `{
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -662,7 +659,7 @@ const docTemplate = `{
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -826,7 +823,7 @@ const docTemplate = `{
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -874,7 +871,7 @@ const docTemplate = `{
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -931,7 +928,7 @@ const docTemplate = `{
"summary": "User Logout", "summary": "User Logout",
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -950,7 +947,7 @@ const docTemplate = `{
"summary": "User Token Refresh", "summary": "User Token Refresh",
"responses": { "responses": {
"200": { "200": {
"description": "" "description": "OK"
} }
} }
} }
@ -977,7 +974,7 @@ const docTemplate = `{
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -1077,7 +1074,7 @@ const docTemplate = `{
"summary": "Deletes the user account", "summary": "Deletes the user account",
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -1098,7 +1095,7 @@ const docTemplate = `{
"summary": "Update the current user's password // TODO:", "summary": "Update the current user's password // TODO:",
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -1516,6 +1513,26 @@ const docTemplate = `{
} }
} }
}, },
"repo.PaginationResult-repo_ItemSummary": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
},
"repo.UserOut": { "repo.UserOut": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -1569,9 +1586,7 @@ const docTemplate = `{
"server.Results": { "server.Results": {
"type": "object", "type": "object",
"properties": { "properties": {
"items": { "items": {}
"type": "any"
}
} }
}, },
"server.ValidationError": { "server.ValidationError": {

View file

@ -69,6 +69,18 @@
"name": "q", "name": "q",
"in": "query" "in": "query"
}, },
{
"type": "integer",
"description": "page number",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "items per page",
"name": "pageSize",
"in": "query"
},
{ {
"type": "array", "type": "array",
"items": { "items": {
@ -94,22 +106,7 @@
"200": { "200": {
"description": "OK", "description": "OK",
"schema": { "schema": {
"allOf": [ "$ref": "#/definitions/repo.PaginationResult-repo_ItemSummary"
{
"$ref": "#/definitions/server.Results"
},
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
}
}
}
]
} }
} }
} }
@ -173,7 +170,7 @@
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -274,7 +271,7 @@
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -374,7 +371,7 @@
], ],
"responses": { "responses": {
"200": { "200": {
"description": "" "description": "OK"
} }
} }
} }
@ -490,7 +487,7 @@
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -654,7 +651,7 @@
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -818,7 +815,7 @@
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -866,7 +863,7 @@
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -923,7 +920,7 @@
"summary": "User Logout", "summary": "User Logout",
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -942,7 +939,7 @@
"summary": "User Token Refresh", "summary": "User Token Refresh",
"responses": { "responses": {
"200": { "200": {
"description": "" "description": "OK"
} }
} }
} }
@ -969,7 +966,7 @@
], ],
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -1069,7 +1066,7 @@
"summary": "Deletes the user account", "summary": "Deletes the user account",
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -1090,7 +1087,7 @@
"summary": "Update the current user's password // TODO:", "summary": "Update the current user's password // TODO:",
"responses": { "responses": {
"204": { "204": {
"description": "" "description": "No Content"
} }
} }
} }
@ -1508,6 +1505,26 @@
} }
} }
}, },
"repo.PaginationResult-repo_ItemSummary": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "#/definitions/repo.ItemSummary"
}
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
},
"repo.UserOut": { "repo.UserOut": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -1561,9 +1578,7 @@
"server.Results": { "server.Results": {
"type": "object", "type": "object",
"properties": { "properties": {
"items": { "items": {}
"type": "any"
}
} }
}, },
"server.ValidationError": { "server.ValidationError": {

View file

@ -275,6 +275,19 @@ definitions:
updatedAt: updatedAt:
type: string type: string
type: object type: object
repo.PaginationResult-repo_ItemSummary:
properties:
items:
items:
$ref: '#/definitions/repo.ItemSummary'
type: array
page:
type: integer
pageSize:
type: integer
total:
type: integer
type: object
repo.UserOut: repo.UserOut:
properties: properties:
email: email:
@ -310,8 +323,7 @@ definitions:
type: object type: object
server.Results: server.Results:
properties: properties:
items: items: {}
type: any
type: object type: object
server.ValidationError: server.ValidationError:
properties: properties:
@ -431,6 +443,14 @@ paths:
in: query in: query
name: q name: q
type: string type: string
- description: page number
in: query
name: page
type: integer
- description: items per page
in: query
name: pageSize
type: integer
- collectionFormat: multi - collectionFormat: multi
description: label Ids description: label Ids
in: query in: query
@ -451,14 +471,7 @@ paths:
"200": "200":
description: OK description: OK
schema: schema:
allOf: $ref: '#/definitions/repo.PaginationResult-repo_ItemSummary'
- $ref: '#/definitions/server.Results'
- properties:
items:
items:
$ref: '#/definitions/repo.ItemSummary'
type: array
type: object
security: security:
- Bearer: [] - Bearer: []
summary: Get All Items summary: Get All Items
@ -496,7 +509,7 @@ paths:
- application/json - application/json
responses: responses:
"204": "204":
description: "" description: No Content
security: security:
- Bearer: [] - Bearer: []
summary: deletes a item summary: deletes a item
@ -602,7 +615,7 @@ paths:
type: string type: string
responses: responses:
"204": "204":
description: "" description: No Content
security: security:
- Bearer: [] - Bearer: []
summary: retrieves an attachment for an item summary: retrieves an attachment for an item
@ -677,7 +690,7 @@ paths:
- application/octet-stream - application/octet-stream
responses: responses:
"200": "200":
description: "" description: OK
security: security:
- Bearer: [] - Bearer: []
summary: retrieves an attachment for an item summary: retrieves an attachment for an item
@ -695,7 +708,7 @@ paths:
- application/json - application/json
responses: responses:
"204": "204":
description: "" description: No Content
security: security:
- Bearer: [] - Bearer: []
summary: imports items into the database summary: imports items into the database
@ -754,7 +767,7 @@ paths:
- application/json - application/json
responses: responses:
"204": "204":
description: "" description: No Content
security: security:
- Bearer: [] - Bearer: []
summary: deletes a label summary: deletes a label
@ -851,7 +864,7 @@ paths:
- application/json - application/json
responses: responses:
"204": "204":
description: "" description: No Content
security: security:
- Bearer: [] - Bearer: []
summary: deletes a location summary: deletes a location
@ -918,7 +931,7 @@ paths:
$ref: '#/definitions/v1.ChangePassword' $ref: '#/definitions/v1.ChangePassword'
responses: responses:
"204": "204":
description: "" description: No Content
security: security:
- Bearer: [] - Bearer: []
summary: Updates the users password summary: Updates the users password
@ -954,7 +967,7 @@ paths:
post: post:
responses: responses:
"204": "204":
description: "" description: No Content
security: security:
- Bearer: [] - Bearer: []
summary: User Logout summary: User Logout
@ -967,7 +980,7 @@ paths:
This does not validate that the user still exists within the database. This does not validate that the user still exists within the database.
responses: responses:
"200": "200":
description: "" description: OK
security: security:
- Bearer: [] - Bearer: []
summary: User Token Refresh summary: User Token Refresh
@ -986,7 +999,7 @@ paths:
- application/json - application/json
responses: responses:
"204": "204":
description: "" description: No Content
summary: Get the current user summary: Get the current user
tags: tags:
- User - User
@ -996,7 +1009,7 @@ paths:
- application/json - application/json
responses: responses:
"204": "204":
description: "" description: No Content
security: security:
- Bearer: [] - Bearer: []
summary: Deletes the user account summary: Deletes the user account
@ -1051,7 +1064,7 @@ paths:
- application/json - application/json
responses: responses:
"204": "204":
description: "" description: No Content
security: security:
- Bearer: [] - Bearer: []
summary: 'Update the current user''s password // TODO:' summary: 'Update the current user''s password // TODO:'

View file

@ -25,16 +25,16 @@ var (
BuildTime = "now" BuildTime = "now"
) )
// @title Go API Templates // @title Go API Templates
// @version 1.0 // @version 1.0
// @description This is a simple Rest API Server Template that implements some basic User and Authentication patterns to help you get started and bootstrap your next project!. // @description This is a simple Rest API Server Template that implements some basic User and Authentication patterns to help you get started and bootstrap your next project!.
// @contact.name Don't // @contact.name Don't
// @license.name MIT // @license.name MIT
// @BasePath /api // @BasePath /api
// @securityDefinitions.apikey Bearer // @securityDefinitions.apikey Bearer
// @in header // @in header
// @name Authorization // @name Authorization
// @description "Type 'Bearer TOKEN' to correctly set the API Key" // @description "Type 'Bearer TOKEN' to correctly set the API Key"
func main() { func main() {
cfg, err := config.New() cfg, err := config.New()
if err != nil { if err != nil {

View file

@ -66,11 +66,11 @@ func NewControllerV1(svc *services.AllServices, options ...func(*V1Controller))
type ReadyFunc func() bool type ReadyFunc func() bool
// HandleBase godoc // HandleBase godoc
// @Summary Retrieves the basic information about the API // @Summary Retrieves the basic information about the API
// @Tags Base // @Tags Base
// @Produce json // @Produce json
// @Success 200 {object} ApiSummary // @Success 200 {object} ApiSummary
// @Router /v1/status [GET] // @Router /v1/status [GET]
func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) http.HandlerFunc { func (ctrl *V1Controller) HandleBase(ready ReadyFunc, build Build) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
server.Respond(w, http.StatusOK, ApiSummary{ server.Respond(w, http.StatusOK, ApiSummary{

View file

@ -23,15 +23,15 @@ type (
) )
// HandleAuthLogin godoc // HandleAuthLogin godoc
// @Summary User Login // @Summary User Login
// @Tags Authentication // @Tags Authentication
// @Accept x-www-form-urlencoded // @Accept x-www-form-urlencoded
// @Accept application/json // @Accept application/json
// @Param username formData string false "string" example(admin@admin.com) // @Param username formData string false "string" example(admin@admin.com)
// @Param password formData string false "string" example(admin) // @Param password formData string false "string" example(admin)
// @Produce json // @Produce json
// @Success 200 {object} TokenResponse // @Success 200 {object} TokenResponse
// @Router /v1/users/login [POST] // @Router /v1/users/login [POST]
func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc { func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
loginForm := &LoginForm{} loginForm := &LoginForm{}
@ -80,11 +80,11 @@ func (ctrl *V1Controller) HandleAuthLogin() http.HandlerFunc {
} }
// HandleAuthLogout godoc // HandleAuthLogout godoc
// @Summary User Logout // @Summary User Logout
// @Tags Authentication // @Tags Authentication
// @Success 204 // @Success 204
// @Router /v1/users/logout [POST] // @Router /v1/users/logout [POST]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleAuthLogout() http.HandlerFunc { func (ctrl *V1Controller) HandleAuthLogout() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
token := services.UseTokenCtx(r.Context()) token := services.UseTokenCtx(r.Context())
@ -106,13 +106,13 @@ func (ctrl *V1Controller) HandleAuthLogout() http.HandlerFunc {
} }
// HandleAuthLogout godoc // HandleAuthLogout godoc
// @Summary User Token Refresh // @Summary User Token Refresh
// @Description handleAuthRefresh returns a handler that will issue a new token from an existing token. // @Description handleAuthRefresh returns a handler that will issue a new token from an existing token.
// @Description This does not validate that the user still exists within the database. // @Description This does not validate that the user still exists within the database.
// @Tags Authentication // @Tags Authentication
// @Success 200 // @Success 200
// @Router /v1/users/refresh [GET] // @Router /v1/users/refresh [GET]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleAuthRefresh() http.HandlerFunc { func (ctrl *V1Controller) HandleAuthRefresh() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
requestToken := services.UseTokenCtx(r.Context()) requestToken := services.UseTokenCtx(r.Context())

View file

@ -23,13 +23,13 @@ type (
) )
// HandleUserSelf godoc // HandleUserSelf godoc
// @Summary Get the current user // @Summary Get the current user
// @Tags User // @Tags User
// @Produce json // @Produce json
// @Param payload body GroupInvitationCreate true "User Data" // @Param payload body GroupInvitationCreate true "User Data"
// @Success 200 {object} GroupInvitation // @Success 200 {object} GroupInvitation
// @Router /v1/groups/invitations [Post] // @Router /v1/groups/invitations [Post]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleGroupInvitationsCreate() http.HandlerFunc { func (ctrl *V1Controller) HandleGroupInvitationsCreate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
data := GroupInvitationCreate{} data := GroupInvitationCreate{}

View file

@ -4,6 +4,7 @@ import (
"encoding/csv" "encoding/csv"
"net/http" "net/http"
"net/url" "net/url"
"strconv"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/repo" "github.com/hay-kot/homebox/backend/internal/repo"
@ -24,10 +25,23 @@ func uuidList(params url.Values, key string) []uuid.UUID {
return ids return ids
} }
func intOrNegativeOne(s string) int {
i, err := strconv.Atoi(s)
if err != nil {
return -1
}
return i
}
func extractQuery(r *http.Request) repo.ItemQuery { func extractQuery(r *http.Request) repo.ItemQuery {
params := r.URL.Query() params := r.URL.Query()
page := intOrNegativeOne(params.Get("page"))
perPage := intOrNegativeOne(params.Get("perPage"))
return repo.ItemQuery{ return repo.ItemQuery{
Page: page,
PageSize: perPage,
Search: params.Get("q"), Search: params.Get("q"),
LocationIDs: uuidList(params, "locations"), LocationIDs: uuidList(params, "locations"),
LabelIDs: uuidList(params, "labels"), LabelIDs: uuidList(params, "labels"),
@ -35,15 +49,17 @@ func extractQuery(r *http.Request) repo.ItemQuery {
} }
// HandleItemsGetAll godoc // HandleItemsGetAll godoc
// @Summary Get All Items // @Summary Get All Items
// @Tags Items // @Tags Items
// @Produce json // @Produce json
// @Param q query string false "search string" // @Param q query string false "search string"
// @Param labels query []string false "label Ids" collectionFormat(multi) // @Param page query int false "page number"
// @Param locations query []string false "location Ids" collectionFormat(multi) // @Param pageSize query int false "items per page"
// @Success 200 {object} server.Results{items=[]repo.ItemSummary} // @Param labels query []string false "label Ids" collectionFormat(multi)
// @Router /v1/items [GET] // @Param locations query []string false "location Ids" collectionFormat(multi)
// @Security Bearer // @Success 200 {object} repo.PaginationResult[repo.ItemSummary]{}
// @Router /v1/items [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemsGetAll() http.HandlerFunc { func (ctrl *V1Controller) HandleItemsGetAll() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
ctx := services.NewContext(r.Context()) ctx := services.NewContext(r.Context())
@ -53,18 +69,18 @@ func (ctrl *V1Controller) HandleItemsGetAll() http.HandlerFunc {
server.RespondServerError(w) server.RespondServerError(w)
return return
} }
server.Respond(w, http.StatusOK, server.Results{Items: items}) server.Respond(w, http.StatusOK, items)
} }
} }
// HandleItemsCreate godoc // HandleItemsCreate godoc
// @Summary Create a new item // @Summary Create a new item
// @Tags Items // @Tags Items
// @Produce json // @Produce json
// @Param payload body repo.ItemCreate true "Item Data" // @Param payload body repo.ItemCreate true "Item Data"
// @Success 200 {object} repo.ItemSummary // @Success 200 {object} repo.ItemSummary
// @Router /v1/items [POST] // @Router /v1/items [POST]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc { func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
createData := repo.ItemCreate{} createData := repo.ItemCreate{}
@ -87,13 +103,13 @@ func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc {
} }
// HandleItemDelete godocs // HandleItemDelete godocs
// @Summary deletes a item // @Summary deletes a item
// @Tags Items // @Tags Items
// @Produce json // @Produce json
// @Param id path string true "Item ID" // @Param id path string true "Item ID"
// @Success 204 // @Success 204
// @Router /v1/items/{id} [DELETE] // @Router /v1/items/{id} [DELETE]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleItemDelete() http.HandlerFunc { func (ctrl *V1Controller) HandleItemDelete() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
uid, user, err := ctrl.partialParseIdAndUser(w, r) uid, user, err := ctrl.partialParseIdAndUser(w, r)
@ -112,13 +128,13 @@ func (ctrl *V1Controller) HandleItemDelete() http.HandlerFunc {
} }
// HandleItemGet godocs // HandleItemGet godocs
// @Summary Gets a item and fields // @Summary Gets a item and fields
// @Tags Items // @Tags Items
// @Produce json // @Produce json
// @Param id path string true "Item ID" // @Param id path string true "Item ID"
// @Success 200 {object} repo.ItemOut // @Success 200 {object} repo.ItemOut
// @Router /v1/items/{id} [GET] // @Router /v1/items/{id} [GET]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc { func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
uid, user, err := ctrl.partialParseIdAndUser(w, r) uid, user, err := ctrl.partialParseIdAndUser(w, r)
@ -137,14 +153,14 @@ func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc {
} }
// HandleItemUpdate godocs // HandleItemUpdate godocs
// @Summary updates a item // @Summary updates a item
// @Tags Items // @Tags Items
// @Produce json // @Produce json
// @Param id path string true "Item ID" // @Param id path string true "Item ID"
// @Param payload body repo.ItemUpdate true "Item Data" // @Param payload body repo.ItemUpdate true "Item Data"
// @Success 200 {object} repo.ItemOut // @Success 200 {object} repo.ItemOut
// @Router /v1/items/{id} [PUT] // @Router /v1/items/{id} [PUT]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleItemUpdate() http.HandlerFunc { func (ctrl *V1Controller) HandleItemUpdate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
body := repo.ItemUpdate{} body := repo.ItemUpdate{}
@ -170,13 +186,13 @@ func (ctrl *V1Controller) HandleItemUpdate() http.HandlerFunc {
} }
// HandleItemsImport godocs // HandleItemsImport godocs
// @Summary imports items into the database // @Summary imports items into the database
// @Tags Items // @Tags Items
// @Produce json // @Produce json
// @Success 204 // @Success 204
// @Param csv formData file true "Image to upload" // @Param csv formData file true "Image to upload"
// @Router /v1/items/import [Post] // @Router /v1/items/import [Post]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleItemsImport() http.HandlerFunc { func (ctrl *V1Controller) HandleItemsImport() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {

View file

@ -21,17 +21,17 @@ type (
) )
// HandleItemsImport godocs // HandleItemsImport godocs
// @Summary imports items into the database // @Summary imports items into the database
// @Tags Items // @Tags Items
// @Produce json // @Produce json
// @Param id path string true "Item ID" // @Param id path string true "Item ID"
// @Param file formData file true "File attachment" // @Param file formData file true "File attachment"
// @Param type formData string true "Type of file" // @Param type formData string true "Type of file"
// @Param name formData string true "name of the file including extension" // @Param name formData string true "name of the file including extension"
// @Success 200 {object} repo.ItemOut // @Success 200 {object} repo.ItemOut
// @Failure 422 {object} []server.ValidationError // @Failure 422 {object} []server.ValidationError
// @Router /v1/items/{id}/attachments [POST] // @Router /v1/items/{id}/attachments [POST]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc { func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(ctrl.maxUploadSize << 20) err := r.ParseMultipartForm(ctrl.maxUploadSize << 20)
@ -98,14 +98,14 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc {
} }
// HandleItemAttachmentGet godocs // HandleItemAttachmentGet godocs
// @Summary retrieves an attachment for an item // @Summary retrieves an attachment for an item
// @Tags Items // @Tags Items
// @Produce application/octet-stream // @Produce application/octet-stream
// @Param id path string true "Item ID" // @Param id path string true "Item ID"
// @Param token query string true "Attachment token" // @Param token query string true "Attachment token"
// @Success 200 // @Success 200
// @Router /v1/items/{id}/attachments/download [GET] // @Router /v1/items/{id}/attachments/download [GET]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc { func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
token := server.GetParam(r, "token", "") token := server.GetParam(r, "token", "")
@ -125,39 +125,39 @@ func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc {
} }
// HandleItemAttachmentToken godocs // HandleItemAttachmentToken godocs
// @Summary retrieves an attachment for an item // @Summary retrieves an attachment for an item
// @Tags Items // @Tags Items
// @Produce application/octet-stream // @Produce application/octet-stream
// @Param id path string true "Item ID" // @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID" // @Param attachment_id path string true "Attachment ID"
// @Success 200 {object} ItemAttachmentToken // @Success 200 {object} ItemAttachmentToken
// @Router /v1/items/{id}/attachments/{attachment_id} [GET] // @Router /v1/items/{id}/attachments/{attachment_id} [GET]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentToken() http.HandlerFunc { func (ctrl *V1Controller) HandleItemAttachmentToken() http.HandlerFunc {
return ctrl.handleItemAttachmentsHandler return ctrl.handleItemAttachmentsHandler
} }
// HandleItemAttachmentDelete godocs // HandleItemAttachmentDelete godocs
// @Summary retrieves an attachment for an item // @Summary retrieves an attachment for an item
// @Tags Items // @Tags Items
// @Param id path string true "Item ID" // @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID" // @Param attachment_id path string true "Attachment ID"
// @Success 204 // @Success 204
// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE] // @Router /v1/items/{id}/attachments/{attachment_id} [DELETE]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentDelete() http.HandlerFunc { func (ctrl *V1Controller) HandleItemAttachmentDelete() http.HandlerFunc {
return ctrl.handleItemAttachmentsHandler return ctrl.handleItemAttachmentsHandler
} }
// HandleItemAttachmentUpdate godocs // HandleItemAttachmentUpdate godocs
// @Summary retrieves an attachment for an item // @Summary retrieves an attachment for an item
// @Tags Items // @Tags Items
// @Param id path string true "Item ID" // @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID" // @Param attachment_id path string true "Attachment ID"
// @Param payload body repo.ItemAttachmentUpdate true "Attachment Update" // @Param payload body repo.ItemAttachmentUpdate true "Attachment Update"
// @Success 200 {object} repo.ItemOut // @Success 200 {object} repo.ItemOut
// @Router /v1/items/{id}/attachments/{attachment_id} [PUT] // @Router /v1/items/{id}/attachments/{attachment_id} [PUT]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentUpdate() http.HandlerFunc { func (ctrl *V1Controller) HandleItemAttachmentUpdate() http.HandlerFunc {
return ctrl.handleItemAttachmentsHandler return ctrl.handleItemAttachmentsHandler
} }

View file

@ -11,12 +11,12 @@ import (
) )
// HandleLabelsGetAll godoc // HandleLabelsGetAll godoc
// @Summary Get All Labels // @Summary Get All Labels
// @Tags Labels // @Tags Labels
// @Produce json // @Produce json
// @Success 200 {object} server.Results{items=[]repo.LabelOut} // @Success 200 {object} server.Results{items=[]repo.LabelOut}
// @Router /v1/labels [GET] // @Router /v1/labels [GET]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleLabelsGetAll() http.HandlerFunc { func (ctrl *V1Controller) HandleLabelsGetAll() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
user := services.UseUserCtx(r.Context()) user := services.UseUserCtx(r.Context())
@ -31,13 +31,13 @@ func (ctrl *V1Controller) HandleLabelsGetAll() http.HandlerFunc {
} }
// HandleLabelsCreate godoc // HandleLabelsCreate godoc
// @Summary Create a new label // @Summary Create a new label
// @Tags Labels // @Tags Labels
// @Produce json // @Produce json
// @Param payload body repo.LabelCreate true "Label Data" // @Param payload body repo.LabelCreate true "Label Data"
// @Success 200 {object} repo.LabelSummary // @Success 200 {object} repo.LabelSummary
// @Router /v1/labels [POST] // @Router /v1/labels [POST]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleLabelsCreate() http.HandlerFunc { func (ctrl *V1Controller) HandleLabelsCreate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
createData := repo.LabelCreate{} createData := repo.LabelCreate{}
@ -61,13 +61,13 @@ func (ctrl *V1Controller) HandleLabelsCreate() http.HandlerFunc {
} }
// HandleLabelDelete godocs // HandleLabelDelete godocs
// @Summary deletes a label // @Summary deletes a label
// @Tags Labels // @Tags Labels
// @Produce json // @Produce json
// @Param id path string true "Label ID" // @Param id path string true "Label ID"
// @Success 204 // @Success 204
// @Router /v1/labels/{id} [DELETE] // @Router /v1/labels/{id} [DELETE]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleLabelDelete() http.HandlerFunc { func (ctrl *V1Controller) HandleLabelDelete() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
uid, user, err := ctrl.partialParseIdAndUser(w, r) uid, user, err := ctrl.partialParseIdAndUser(w, r)
@ -86,13 +86,13 @@ func (ctrl *V1Controller) HandleLabelDelete() http.HandlerFunc {
} }
// HandleLabelGet godocs // HandleLabelGet godocs
// @Summary Gets a label and fields // @Summary Gets a label and fields
// @Tags Labels // @Tags Labels
// @Produce json // @Produce json
// @Param id path string true "Label ID" // @Param id path string true "Label ID"
// @Success 200 {object} repo.LabelOut // @Success 200 {object} repo.LabelOut
// @Router /v1/labels/{id} [GET] // @Router /v1/labels/{id} [GET]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleLabelGet() http.HandlerFunc { func (ctrl *V1Controller) HandleLabelGet() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
uid, user, err := ctrl.partialParseIdAndUser(w, r) uid, user, err := ctrl.partialParseIdAndUser(w, r)
@ -118,13 +118,13 @@ func (ctrl *V1Controller) HandleLabelGet() http.HandlerFunc {
} }
// HandleLabelUpdate godocs // HandleLabelUpdate godocs
// @Summary updates a label // @Summary updates a label
// @Tags Labels // @Tags Labels
// @Produce json // @Produce json
// @Param id path string true "Label ID" // @Param id path string true "Label ID"
// @Success 200 {object} repo.LabelOut // @Success 200 {object} repo.LabelOut
// @Router /v1/labels/{id} [PUT] // @Router /v1/labels/{id} [PUT]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleLabelUpdate() http.HandlerFunc { func (ctrl *V1Controller) HandleLabelUpdate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
body := repo.LabelUpdate{} body := repo.LabelUpdate{}

View file

@ -11,12 +11,12 @@ import (
) )
// HandleLocationGetAll godoc // HandleLocationGetAll godoc
// @Summary Get All Locations // @Summary Get All Locations
// @Tags Locations // @Tags Locations
// @Produce json // @Produce json
// @Success 200 {object} server.Results{items=[]repo.LocationOutCount} // @Success 200 {object} server.Results{items=[]repo.LocationOutCount}
// @Router /v1/locations [GET] // @Router /v1/locations [GET]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleLocationGetAll() http.HandlerFunc { func (ctrl *V1Controller) HandleLocationGetAll() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
user := services.UseUserCtx(r.Context()) user := services.UseUserCtx(r.Context())
@ -32,13 +32,13 @@ func (ctrl *V1Controller) HandleLocationGetAll() http.HandlerFunc {
} }
// HandleLocationCreate godoc // HandleLocationCreate godoc
// @Summary Create a new location // @Summary Create a new location
// @Tags Locations // @Tags Locations
// @Produce json // @Produce json
// @Param payload body repo.LocationCreate true "Location Data" // @Param payload body repo.LocationCreate true "Location Data"
// @Success 200 {object} repo.LocationSummary // @Success 200 {object} repo.LocationSummary
// @Router /v1/locations [POST] // @Router /v1/locations [POST]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleLocationCreate() http.HandlerFunc { func (ctrl *V1Controller) HandleLocationCreate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
createData := repo.LocationCreate{} createData := repo.LocationCreate{}
@ -61,13 +61,13 @@ func (ctrl *V1Controller) HandleLocationCreate() http.HandlerFunc {
} }
// HandleLocationDelete godocs // HandleLocationDelete godocs
// @Summary deletes a location // @Summary deletes a location
// @Tags Locations // @Tags Locations
// @Produce json // @Produce json
// @Param id path string true "Location ID" // @Param id path string true "Location ID"
// @Success 204 // @Success 204
// @Router /v1/locations/{id} [DELETE] // @Router /v1/locations/{id} [DELETE]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleLocationDelete() http.HandlerFunc { func (ctrl *V1Controller) HandleLocationDelete() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
uid, user, err := ctrl.partialParseIdAndUser(w, r) uid, user, err := ctrl.partialParseIdAndUser(w, r)
@ -86,13 +86,13 @@ func (ctrl *V1Controller) HandleLocationDelete() http.HandlerFunc {
} }
// HandleLocationGet godocs // HandleLocationGet godocs
// @Summary Gets a location and fields // @Summary Gets a location and fields
// @Tags Locations // @Tags Locations
// @Produce json // @Produce json
// @Param id path string true "Location ID" // @Param id path string true "Location ID"
// @Success 200 {object} repo.LocationOut // @Success 200 {object} repo.LocationOut
// @Router /v1/locations/{id} [GET] // @Router /v1/locations/{id} [GET]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc { func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
uid, user, err := ctrl.partialParseIdAndUser(w, r) uid, user, err := ctrl.partialParseIdAndUser(w, r)
@ -123,13 +123,13 @@ func (ctrl *V1Controller) HandleLocationGet() http.HandlerFunc {
} }
// HandleLocationUpdate godocs // HandleLocationUpdate godocs
// @Summary updates a location // @Summary updates a location
// @Tags Locations // @Tags Locations
// @Produce json // @Produce json
// @Param id path string true "Location ID" // @Param id path string true "Location ID"
// @Success 200 {object} repo.LocationOut // @Success 200 {object} repo.LocationOut
// @Router /v1/locations/{id} [PUT] // @Router /v1/locations/{id} [PUT]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleLocationUpdate() http.HandlerFunc { func (ctrl *V1Controller) HandleLocationUpdate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
body := repo.LocationUpdate{} body := repo.LocationUpdate{}

View file

@ -11,12 +11,12 @@ import (
) )
// HandleUserSelf godoc // HandleUserSelf godoc
// @Summary Get the current user // @Summary Get the current user
// @Tags User // @Tags User
// @Produce json // @Produce json
// @Param payload body services.UserRegistration true "User Data" // @Param payload body services.UserRegistration true "User Data"
// @Success 204 // @Success 204
// @Router /v1/users/register [Post] // @Router /v1/users/register [Post]
func (ctrl *V1Controller) HandleUserRegistration() http.HandlerFunc { func (ctrl *V1Controller) HandleUserRegistration() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
regData := services.UserRegistration{} regData := services.UserRegistration{}
@ -39,12 +39,12 @@ func (ctrl *V1Controller) HandleUserRegistration() http.HandlerFunc {
} }
// HandleUserSelf godoc // HandleUserSelf godoc
// @Summary Get the current user // @Summary Get the current user
// @Tags User // @Tags User
// @Produce json // @Produce json
// @Success 200 {object} server.Result{item=repo.UserOut} // @Success 200 {object} server.Result{item=repo.UserOut}
// @Router /v1/users/self [GET] // @Router /v1/users/self [GET]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleUserSelf() http.HandlerFunc { func (ctrl *V1Controller) HandleUserSelf() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
token := services.UseTokenCtx(r.Context()) token := services.UseTokenCtx(r.Context())
@ -60,13 +60,13 @@ func (ctrl *V1Controller) HandleUserSelf() http.HandlerFunc {
} }
// HandleUserSelfUpdate godoc // HandleUserSelfUpdate godoc
// @Summary Update the current user // @Summary Update the current user
// @Tags User // @Tags User
// @Produce json // @Produce json
// @Param payload body repo.UserUpdate true "User Data" // @Param payload body repo.UserUpdate true "User Data"
// @Success 200 {object} server.Result{item=repo.UserUpdate} // @Success 200 {object} server.Result{item=repo.UserUpdate}
// @Router /v1/users/self [PUT] // @Router /v1/users/self [PUT]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleUserSelfUpdate() http.HandlerFunc { func (ctrl *V1Controller) HandleUserSelfUpdate() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
updateData := repo.UserUpdate{} updateData := repo.UserUpdate{}
@ -90,24 +90,24 @@ func (ctrl *V1Controller) HandleUserSelfUpdate() http.HandlerFunc {
} }
// HandleUserUpdatePassword godoc // HandleUserUpdatePassword godoc
// @Summary Update the current user's password // TODO: // @Summary Update the current user's password // TODO:
// @Tags User // @Tags User
// @Produce json // @Produce json
// @Success 204 // @Success 204
// @Router /v1/users/self/password [PUT] // @Router /v1/users/self/password [PUT]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleUserUpdatePassword() http.HandlerFunc { func (ctrl *V1Controller) HandleUserUpdatePassword() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
} }
} }
// HandleUserSelfDelete godoc // HandleUserSelfDelete godoc
// @Summary Deletes the user account // @Summary Deletes the user account
// @Tags User // @Tags User
// @Produce json // @Produce json
// @Success 204 // @Success 204
// @Router /v1/users/self [DELETE] // @Router /v1/users/self [DELETE]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleUserSelfDelete() http.HandlerFunc { func (ctrl *V1Controller) HandleUserSelfDelete() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
actor := services.UseUserCtx(r.Context()) actor := services.UseUserCtx(r.Context())
@ -128,12 +128,12 @@ type (
) )
// HandleUserSelfChangePassword godoc // HandleUserSelfChangePassword godoc
// @Summary Updates the users password // @Summary Updates the users password
// @Tags User // @Tags User
// @Success 204 // @Success 204
// @Param payload body ChangePassword true "Password Payload" // @Param payload body ChangePassword true "Password Payload"
// @Router /v1/users/change-password [PUT] // @Router /v1/users/change-password [PUT]
// @Security Bearer // @Security Bearer
func (ctrl *V1Controller) HandleUserSelfChangePassword() http.HandlerFunc { func (ctrl *V1Controller) HandleUserSelfChangePassword() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
if ctrl.isDemo { if ctrl.isDemo {

View file

@ -0,0 +1,12 @@
package repo
type PaginationResult[T any] struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
Total int `json:"total"`
Items []T `json:"items"`
}
func calculateOffset(page, pageSize int) int {
return (page - 1) * pageSize
}

View file

@ -19,6 +19,8 @@ type ItemsRepository struct {
type ( type (
ItemQuery struct { ItemQuery struct {
Page int
PageSize int
Search string `json:"search"` Search string `json:"search"`
LocationIDs []uuid.UUID `json:"locationIds"` LocationIDs []uuid.UUID `json:"locationIds"`
LabelIDs []uuid.UUID `json:"labelIds"` LabelIDs []uuid.UUID `json:"labelIds"`
@ -215,7 +217,7 @@ func (e *ItemsRepository) GetOneByGroup(ctx context.Context, gid, id uuid.UUID)
} }
// QueryByGroup returns a list of items that belong to a specific group based on the provided query. // QueryByGroup returns a list of items that belong to a specific group based on the provided query.
func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q ItemQuery) ([]ItemSummary, error) { func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q ItemQuery) (PaginationResult[ItemSummary], error) {
qb := e.db.Item.Query().Where(item.HasGroupWith(group.ID(gid))) qb := e.db.Item.Query().Where(item.HasGroupWith(group.ID(gid)))
if len(q.LabelIDs) > 0 { if len(q.LabelIDs) > 0 {
@ -243,9 +245,33 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite
) )
} }
return mapItemsSummaryErr(qb.WithLabel(). if q.Page != -1 || q.PageSize != -1 {
WithLocation(). qb = qb.
All(ctx)) Offset(calculateOffset(q.Page, q.PageSize)).
Limit(q.PageSize)
}
items, err := mapItemsSummaryErr(
qb.WithLabel().
WithLocation().
All(ctx),
)
if err != nil {
return PaginationResult[ItemSummary]{}, err
}
count, err := qb.Count(ctx)
if err != nil {
return PaginationResult[ItemSummary]{}, err
}
return PaginationResult[ItemSummary]{
Page: q.Page,
PageSize: q.PageSize,
Total: count,
Items: items,
}, nil
} }
// GetAll returns all the items in the database with the Labels and Locations eager loaded. // GetAll returns all the items in the database with the Labels and Locations eager loaded.

View file

@ -28,7 +28,7 @@ func (svc *ItemService) GetOne(ctx context.Context, gid uuid.UUID, id uuid.UUID)
return svc.repo.Items.GetOneByGroup(ctx, gid, id) return svc.repo.Items.GetOneByGroup(ctx, gid, id)
} }
func (svc *ItemService) Query(ctx Context, q repo.ItemQuery) ([]repo.ItemSummary, error) { func (svc *ItemService) Query(ctx Context, q repo.ItemQuery) (repo.PaginationResult[repo.ItemSummary], error) {
return svc.repo.Items.QueryByGroup(ctx, ctx.GID, q) return svc.repo.Items.QueryByGroup(ctx, ctx.GID, q)
} }

View file

@ -8,9 +8,11 @@ import {
ItemSummary, ItemSummary,
ItemUpdate, ItemUpdate,
} from "../types/data-contracts"; } from "../types/data-contracts";
import { AttachmentTypes, Results } from "../types/non-generated"; import { AttachmentTypes, PaginationResult } from "../types/non-generated";
export type ItemsQuery = { export type ItemsQuery = {
page?: number;
pageSize?: number;
locations?: string[]; locations?: string[];
labels?: string[]; labels?: string[];
q?: string; q?: string;
@ -18,7 +20,7 @@ export type ItemsQuery = {
export class ItemsApi extends BaseAPI { export class ItemsApi extends BaseAPI {
getAll(q: ItemsQuery = {}) { getAll(q: ItemsQuery = {}) {
return this.http.get<Results<ItemSummary>>({ url: route("/items", q) }); return this.http.get<PaginationResult<ItemSummary>>({ url: route("/items", q) });
} }
create(item: ItemCreate) { create(item: ItemCreate) {

View file

@ -187,6 +187,7 @@ export interface LocationSummary {
updatedAt: Date; updatedAt: Date;
} }
export interface UserOut { export interface UserOut {
email: string; email: string;
groupId: string; groupId: string;

View file

@ -12,3 +12,10 @@ export type Result<T> = {
export type Results<T> = { export type Results<T> = {
items: T[]; items: T[];
}; };
export interface PaginationResult<T> {
items: T[];
page: number;
pageSize: number;
total: number;
}

View file

@ -22,6 +22,7 @@ def date_types(*names: list[str]) -> dict[re.Pattern, str]:
regex_replace: dict[re.Pattern, str] = { regex_replace: dict[re.Pattern, str] = {
re.compile(r" PaginationResultRepo"): "PaginationResult",
re.compile(r" Repo"): " ", re.compile(r" Repo"): " ",
re.compile(r" Services"): " ", re.compile(r" Services"): " ",
re.compile(r" V1"): " ", re.compile(r" V1"): " ",