forked from mirrors/homebox
Compare commits
2 commits
main
...
fix/web-so
Author | SHA1 | Date | |
---|---|---|---|
|
2cd107b8bd | ||
|
a3cce59a2a |
57 changed files with 324 additions and 903 deletions
12
Dockerfile
12
Dockerfile
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
# Build Nuxt
|
# Build Nuxt
|
||||||
FROM r.batts.cloud/node:18 as frontend-builder
|
FROM node:18-alpine as frontend-builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN npm install -g pnpm
|
RUN npm install -g pnpm
|
||||||
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
COPY frontend/package.json frontend/pnpm-lock.yaml ./
|
||||||
|
@ -9,12 +9,13 @@ COPY frontend .
|
||||||
RUN pnpm build
|
RUN pnpm build
|
||||||
|
|
||||||
# Build API
|
# Build API
|
||||||
FROM r.batts.cloud/golang:1.21 AS builder
|
FROM golang:alpine AS builder
|
||||||
ARG BUILD_TIME
|
ARG BUILD_TIME
|
||||||
ARG COMMIT
|
ARG COMMIT
|
||||||
ARG VERSION
|
ARG VERSION
|
||||||
RUN apt update && \
|
RUN apk update && \
|
||||||
apt install -y git build-essential gcc g++
|
apk upgrade && \
|
||||||
|
apk add --update git build-base gcc g++
|
||||||
|
|
||||||
WORKDIR /go/src/app
|
WORKDIR /go/src/app
|
||||||
COPY ./backend .
|
COPY ./backend .
|
||||||
|
@ -27,12 +28,13 @@ RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||||
-v ./app/api/*.go
|
-v ./app/api/*.go
|
||||||
|
|
||||||
# Production Stage
|
# Production Stage
|
||||||
FROM r.batts.cloud/debian:bookworm
|
FROM alpine:latest
|
||||||
|
|
||||||
ENV HBOX_MODE=production
|
ENV HBOX_MODE=production
|
||||||
ENV HBOX_STORAGE_DATA=/data/
|
ENV HBOX_STORAGE_DATA=/data/
|
||||||
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1
|
ENV HBOX_STORAGE_SQLITE_URL=/data/homebox.db?_fk=1
|
||||||
|
|
||||||
|
RUN apk --no-cache add ca-certificates
|
||||||
RUN mkdir /app
|
RUN mkdir /app
|
||||||
COPY --from=builder /go/bin/api /app
|
COPY --from=builder /go/bin/api /app
|
||||||
|
|
||||||
|
|
|
@ -49,14 +49,7 @@ func WithRegistration(allowRegistration bool) func(*V1Controller) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithSecureCookies(secure bool) func(*V1Controller) {
|
|
||||||
return func(ctrl *V1Controller) {
|
|
||||||
ctrl.cookieSecure = secure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type V1Controller struct {
|
type V1Controller struct {
|
||||||
cookieSecure bool
|
|
||||||
repo *repo.AllRepos
|
repo *repo.AllRepos
|
||||||
svc *services.AllServices
|
svc *services.AllServices
|
||||||
maxUploadSize int64
|
maxUploadSize int64
|
||||||
|
|
|
@ -68,16 +68,3 @@ func (ctrl *V1Controller) HandleEnsureImportRefs() errchain.HandlerFunc {
|
||||||
func (ctrl *V1Controller) HandleItemDateZeroOut() errchain.HandlerFunc {
|
func (ctrl *V1Controller) HandleItemDateZeroOut() errchain.HandlerFunc {
|
||||||
return actionHandlerFactory("zero out date time", ctrl.repo.Items.ZeroOutTimeFields)
|
return actionHandlerFactory("zero out date time", ctrl.repo.Items.ZeroOutTimeFields)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleSetPrimaryPhotos godoc
|
|
||||||
//
|
|
||||||
// @Summary Set Primary Photos
|
|
||||||
// @Description Sets the first photo of each item as the primary photo
|
|
||||||
// @Tags Actions
|
|
||||||
// @Produce json
|
|
||||||
// @Success 200 {object} ActionAmountResult
|
|
||||||
// @Router /v1/actions/set-primary-photos [Post]
|
|
||||||
// @Security Bearer
|
|
||||||
func (ctrl *V1Controller) HandleSetPrimaryPhotos() errchain.HandlerFunc {
|
|
||||||
return actionHandlerFactory("ensure asset IDs", ctrl.repo.Items.SetPrimaryPhotos)
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package v1
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -14,12 +13,6 @@ import (
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
cookieNameToken = "hb.auth.token"
|
|
||||||
cookieNameRemember = "hb.auth.remember"
|
|
||||||
cookieNameSession = "hb.auth.session"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
type (
|
||||||
TokenResponse struct {
|
TokenResponse struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
@ -34,30 +27,6 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type CookieContents struct {
|
|
||||||
Token string
|
|
||||||
ExpiresAt time.Time
|
|
||||||
Remember bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetCookies(r *http.Request) (*CookieContents, error) {
|
|
||||||
cookie, err := r.Cookie(cookieNameToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("authorization cookie is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
rememberCookie, err := r.Cookie(cookieNameRemember)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("remember cookie is required")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &CookieContents{
|
|
||||||
Token: cookie.Value,
|
|
||||||
ExpiresAt: cookie.Expires,
|
|
||||||
Remember: rememberCookie.Value == "true",
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleAuthLogin godoc
|
// HandleAuthLogin godoc
|
||||||
//
|
//
|
||||||
// @Summary User Login
|
// @Summary User Login
|
||||||
|
@ -112,7 +81,6 @@ func (ctrl *V1Controller) HandleAuthLogin() errchain.HandlerFunc {
|
||||||
return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError)
|
return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl.setCookies(w, noPort(r.Host), newToken.Raw, newToken.ExpiresAt, loginForm.StayLoggedIn)
|
|
||||||
return server.JSON(w, http.StatusOK, TokenResponse{
|
return server.JSON(w, http.StatusOK, TokenResponse{
|
||||||
Token: "Bearer " + newToken.Raw,
|
Token: "Bearer " + newToken.Raw,
|
||||||
ExpiresAt: newToken.ExpiresAt,
|
ExpiresAt: newToken.ExpiresAt,
|
||||||
|
@ -140,7 +108,6 @@ func (ctrl *V1Controller) HandleAuthLogout() errchain.HandlerFunc {
|
||||||
return validate.NewRequestError(err, http.StatusInternalServerError)
|
return validate.NewRequestError(err, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl.unsetCookies(w, noPort(r.Host))
|
|
||||||
return server.JSON(w, http.StatusNoContent, nil)
|
return server.JSON(w, http.StatusNoContent, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,78 +133,6 @@ func (ctrl *V1Controller) HandleAuthRefresh() errchain.HandlerFunc {
|
||||||
return validate.NewUnauthorizedError()
|
return validate.NewUnauthorizedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl.setCookies(w, noPort(r.Host), newToken.Raw, newToken.ExpiresAt, false)
|
|
||||||
return server.JSON(w, http.StatusOK, newToken)
|
return server.JSON(w, http.StatusOK, newToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func noPort(host string) string {
|
|
||||||
return strings.Split(host, ":")[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctrl *V1Controller) setCookies(w http.ResponseWriter, domain, token string, expires time.Time, remember bool) {
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: cookieNameRemember,
|
|
||||||
Value: strconv.FormatBool(remember),
|
|
||||||
Expires: expires,
|
|
||||||
Domain: domain,
|
|
||||||
Secure: ctrl.cookieSecure,
|
|
||||||
HttpOnly: true,
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
|
|
||||||
// Set HTTP only cookie
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: cookieNameToken,
|
|
||||||
Value: token,
|
|
||||||
Expires: expires,
|
|
||||||
Domain: domain,
|
|
||||||
Secure: ctrl.cookieSecure,
|
|
||||||
HttpOnly: true,
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
|
|
||||||
// Set Fake Session cookie
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: cookieNameSession,
|
|
||||||
Value: "true",
|
|
||||||
Expires: expires,
|
|
||||||
Domain: domain,
|
|
||||||
Secure: ctrl.cookieSecure,
|
|
||||||
HttpOnly: false,
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ctrl *V1Controller) unsetCookies(w http.ResponseWriter, domain string) {
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: cookieNameToken,
|
|
||||||
Value: "",
|
|
||||||
Expires: time.Unix(0, 0),
|
|
||||||
Domain: domain,
|
|
||||||
Secure: ctrl.cookieSecure,
|
|
||||||
HttpOnly: true,
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: cookieNameRemember,
|
|
||||||
Value: "false",
|
|
||||||
Expires: time.Unix(0, 0),
|
|
||||||
Domain: domain,
|
|
||||||
Secure: ctrl.cookieSecure,
|
|
||||||
HttpOnly: true,
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
|
|
||||||
// Set Fake Session cookie
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: cookieNameSession,
|
|
||||||
Value: "false",
|
|
||||||
Expires: time.Unix(0, 0),
|
|
||||||
Domain: domain,
|
|
||||||
Secure: ctrl.cookieSecure,
|
|
||||||
HttpOnly: false,
|
|
||||||
Path: "/",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -231,7 +231,7 @@ func (ctrl *V1Controller) HandleGetAllCustomFieldValues() errchain.HandlerFunc {
|
||||||
return ctrl.repo.Items.GetAllCustomFieldValues(auth, auth.GID, q.Field)
|
return ctrl.repo.Items.GetAllCustomFieldValues(auth, auth.GID, q.Field)
|
||||||
}
|
}
|
||||||
|
|
||||||
return adapters.Query(fn, http.StatusOK)
|
return adapters.Action(fn, http.StatusOK)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
v1 "github.com/hay-kot/homebox/backend/app/api/handlers/v1"
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/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/internal/sys/validate"
|
||||||
"github.com/hay-kot/httpkit/errchain"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
|
@ -95,6 +94,20 @@ func getQuery(r *http.Request) (string, error) {
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCookie(r *http.Request) (string, error) {
|
||||||
|
cookie, err := r.Cookie("hb.auth.token")
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("access_token cookie is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := url.QueryUnescape(cookie.Value)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("access_token cookie is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
// mwAuthToken is a middleware that will check the database for a stateful token
|
// mwAuthToken is a middleware that will check the database for a stateful token
|
||||||
// and attach it's user to the request context, or return an appropriate error.
|
// and attach it's user to the request context, or return an appropriate error.
|
||||||
// Authorization support is by token via Headers or Query Parameter
|
// Authorization support is by token via Headers or Query Parameter
|
||||||
|
@ -102,30 +115,21 @@ func getQuery(r *http.Request) (string, error) {
|
||||||
// Example:
|
// Example:
|
||||||
// - header = "Bearer 1234567890"
|
// - header = "Bearer 1234567890"
|
||||||
// - query = "?access_token=1234567890"
|
// - query = "?access_token=1234567890"
|
||||||
|
// - cookie = hb.auth.token = 1234567890
|
||||||
func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler {
|
func (a *app) mwAuthToken(next errchain.Handler) errchain.Handler {
|
||||||
return errchain.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
return errchain.HandlerFunc(func(w http.ResponseWriter, r *http.Request) error {
|
||||||
var requestToken string
|
keyFuncs := [...]KeyFunc{
|
||||||
|
getBearer,
|
||||||
// We ignore the error to allow the next strategy to be attempted
|
getCookie,
|
||||||
{
|
getQuery,
|
||||||
cookies, _ := v1.GetCookies(r)
|
|
||||||
if cookies != nil {
|
|
||||||
requestToken = cookies.Token
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if requestToken == "" {
|
var requestToken string
|
||||||
keyFuncs := [...]KeyFunc{
|
for _, keyFunc := range keyFuncs {
|
||||||
getBearer,
|
token, err := keyFunc(r)
|
||||||
getQuery,
|
if err == nil {
|
||||||
}
|
requestToken = token
|
||||||
|
break
|
||||||
for _, keyFunc := range keyFuncs {
|
|
||||||
token, err := keyFunc(r)
|
|
||||||
if err == nil {
|
|
||||||
requestToken = token
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,6 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
|
||||||
r.Post(v1Base("/actions/ensure-asset-ids"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureAssetID(), userMW...))
|
r.Post(v1Base("/actions/ensure-asset-ids"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureAssetID(), userMW...))
|
||||||
r.Post(v1Base("/actions/zero-item-time-fields"), chain.ToHandlerFunc(v1Ctrl.HandleItemDateZeroOut(), userMW...))
|
r.Post(v1Base("/actions/zero-item-time-fields"), chain.ToHandlerFunc(v1Ctrl.HandleItemDateZeroOut(), userMW...))
|
||||||
r.Post(v1Base("/actions/ensure-import-refs"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureImportRefs(), userMW...))
|
r.Post(v1Base("/actions/ensure-import-refs"), chain.ToHandlerFunc(v1Ctrl.HandleEnsureImportRefs(), userMW...))
|
||||||
r.Post(v1Base("/actions/set-primary-photos"), chain.ToHandlerFunc(v1Ctrl.HandleSetPrimaryPhotos(), userMW...))
|
|
||||||
|
|
||||||
r.Get(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationGetAll(), userMW...))
|
r.Get(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationGetAll(), userMW...))
|
||||||
r.Post(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationCreate(), userMW...))
|
r.Post(v1Base("/locations"), chain.ToHandlerFunc(v1Ctrl.HandleLocationCreate(), userMW...))
|
||||||
|
|
|
@ -68,31 +68,6 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/actions/set-primary-photos": {
|
|
||||||
"post": {
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"Bearer": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Sets the first photo of each item as the primary photo",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Actions"
|
|
||||||
],
|
|
||||||
"summary": "Set Primary Photos",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/v1.ActionAmountResult"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/v1/actions/zero-item-time-fields": {
|
"/v1/actions/zero-item-time-fields": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -1904,9 +1879,6 @@ const docTemplate = `{
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"primary": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -1918,9 +1890,6 @@ const docTemplate = `{
|
||||||
"repo.ItemAttachmentUpdate": {
|
"repo.ItemAttachmentUpdate": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"primary": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -2020,9 +1989,6 @@ const docTemplate = `{
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"imageId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"insured": {
|
"insured": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -2130,9 +2096,6 @@ const docTemplate = `{
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"imageId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"insured": {
|
"insured": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -2292,6 +2255,12 @@ const docTemplate = `{
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.ItemSummary"
|
||||||
|
}
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -2353,6 +2322,12 @@ const docTemplate = `{
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.ItemSummary"
|
||||||
|
}
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
|
@ -60,31 +60,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/actions/set-primary-photos": {
|
|
||||||
"post": {
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"Bearer": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Sets the first photo of each item as the primary photo",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Actions"
|
|
||||||
],
|
|
||||||
"summary": "Set Primary Photos",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/v1.ActionAmountResult"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/v1/actions/zero-item-time-fields": {
|
"/v1/actions/zero-item-time-fields": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -1896,9 +1871,6 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"primary": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -1910,9 +1882,6 @@
|
||||||
"repo.ItemAttachmentUpdate": {
|
"repo.ItemAttachmentUpdate": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"primary": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -2012,9 +1981,6 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"imageId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"insured": {
|
"insured": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -2122,9 +2088,6 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"imageId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"insured": {
|
"insured": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -2284,6 +2247,12 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.ItemSummary"
|
||||||
|
}
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -2345,6 +2314,12 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.ItemSummary"
|
||||||
|
}
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
|
@ -52,8 +52,6 @@ definitions:
|
||||||
$ref: '#/definitions/repo.DocumentOut'
|
$ref: '#/definitions/repo.DocumentOut'
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
primary:
|
|
||||||
type: boolean
|
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
updatedAt:
|
updatedAt:
|
||||||
|
@ -61,8 +59,6 @@ definitions:
|
||||||
type: object
|
type: object
|
||||||
repo.ItemAttachmentUpdate:
|
repo.ItemAttachmentUpdate:
|
||||||
properties:
|
properties:
|
||||||
primary:
|
|
||||||
type: boolean
|
|
||||||
title:
|
title:
|
||||||
type: string
|
type: string
|
||||||
type:
|
type:
|
||||||
|
@ -130,8 +126,6 @@ definitions:
|
||||||
type: array
|
type: array
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
imageId:
|
|
||||||
type: string
|
|
||||||
insured:
|
insured:
|
||||||
type: boolean
|
type: boolean
|
||||||
labels:
|
labels:
|
||||||
|
@ -207,8 +201,6 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
imageId:
|
|
||||||
type: string
|
|
||||||
insured:
|
insured:
|
||||||
type: boolean
|
type: boolean
|
||||||
labels:
|
labels:
|
||||||
|
@ -320,6 +312,10 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
|
items:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/repo.ItemSummary'
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
updatedAt:
|
updatedAt:
|
||||||
|
@ -360,6 +356,10 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
id:
|
id:
|
||||||
type: string
|
type: string
|
||||||
|
items:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/repo.ItemSummary'
|
||||||
|
type: array
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
parent:
|
parent:
|
||||||
|
@ -742,21 +742,6 @@ paths:
|
||||||
summary: Ensures Import Refs
|
summary: Ensures Import Refs
|
||||||
tags:
|
tags:
|
||||||
- Actions
|
- Actions
|
||||||
/v1/actions/set-primary-photos:
|
|
||||||
post:
|
|
||||||
description: Sets the first photo of each item as the primary photo
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/v1.ActionAmountResult'
|
|
||||||
security:
|
|
||||||
- Bearer: []
|
|
||||||
summary: Set Primary Photos
|
|
||||||
tags:
|
|
||||||
- Actions
|
|
||||||
/v1/actions/zero-item-time-fields:
|
/v1/actions/zero-item-time-fields:
|
||||||
post:
|
post:
|
||||||
description: Resets all item date fields to the beginning of the day
|
description: Resets all item date fields to the beginning of the day
|
||||||
|
|
|
@ -6,24 +6,24 @@ require (
|
||||||
ariga.io/atlas v0.12.0
|
ariga.io/atlas v0.12.0
|
||||||
entgo.io/ent v0.12.3
|
entgo.io/ent v0.12.3
|
||||||
github.com/ardanlabs/conf/v3 v3.1.6
|
github.com/ardanlabs/conf/v3 v3.1.6
|
||||||
github.com/containrrr/shoutrrr v0.8.0
|
github.com/containrrr/shoutrrr v0.7.1
|
||||||
github.com/go-chi/chi/v5 v5.0.10
|
github.com/go-chi/chi/v5 v5.0.10
|
||||||
github.com/go-playground/validator/v10 v10.15.5
|
github.com/go-playground/validator/v10 v10.14.1
|
||||||
github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d
|
github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d
|
||||||
github.com/google/uuid v1.3.1
|
github.com/google/uuid v1.3.0
|
||||||
github.com/gorilla/schema v1.2.0
|
github.com/gorilla/schema v1.2.0
|
||||||
github.com/hay-kot/httpkit v0.0.3
|
github.com/hay-kot/httpkit v0.0.3
|
||||||
github.com/mattn/go-sqlite3 v1.14.17
|
github.com/mattn/go-sqlite3 v1.14.17
|
||||||
github.com/olahol/melody v1.1.4
|
github.com/olahol/melody v1.1.4
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rs/zerolog v1.31.0
|
github.com/rs/zerolog v1.29.1
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/swaggo/http-swagger v1.3.4
|
github.com/swaggo/http-swagger v1.3.4
|
||||||
github.com/swaggo/swag v1.16.2
|
github.com/swaggo/swag v1.16.1
|
||||||
github.com/yeqown/go-qrcode/v2 v2.2.2
|
github.com/yeqown/go-qrcode/v2 v2.2.2
|
||||||
github.com/yeqown/go-qrcode/writer/standard v1.2.2
|
github.com/yeqown/go-qrcode/writer/standard v1.2.1
|
||||||
golang.org/x/crypto v0.14.0
|
golang.org/x/crypto v0.11.0
|
||||||
modernc.org/sqlite v1.26.0
|
modernc.org/sqlite v1.24.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -61,8 +61,8 @@ require (
|
||||||
golang.org/x/image v0.9.0 // indirect
|
golang.org/x/image v0.9.0 // indirect
|
||||||
golang.org/x/mod v0.12.0 // indirect
|
golang.org/x/mod v0.12.0 // indirect
|
||||||
golang.org/x/net v0.12.0 // indirect
|
golang.org/x/net v0.12.0 // indirect
|
||||||
golang.org/x/sys v0.13.0 // indirect
|
golang.org/x/sys v0.10.0 // indirect
|
||||||
golang.org/x/text v0.13.0 // indirect
|
golang.org/x/text v0.11.0 // indirect
|
||||||
golang.org/x/tools v0.11.0 // indirect
|
golang.org/x/tools v0.11.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
lukechampine.com/uint128 v1.3.0 // indirect
|
lukechampine.com/uint128 v1.3.0 // indirect
|
||||||
|
|
|
@ -235,8 +235,6 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH
|
||||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/containrrr/shoutrrr v0.7.1 h1:19j+YbYXRgj3PJHMzqdQ4dEoQ6teapGdjx0aB8asyho=
|
github.com/containrrr/shoutrrr v0.7.1 h1:19j+YbYXRgj3PJHMzqdQ4dEoQ6teapGdjx0aB8asyho=
|
||||||
github.com/containrrr/shoutrrr v0.7.1/go.mod h1:wz7j7NfcSA+HUlOIj4sDKYXYpgKopfgxcCYGuto8J3s=
|
github.com/containrrr/shoutrrr v0.7.1/go.mod h1:wz7j7NfcSA+HUlOIj4sDKYXYpgKopfgxcCYGuto8J3s=
|
||||||
github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec=
|
|
||||||
github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o=
|
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
|
@ -309,8 +307,6 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
|
github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
|
||||||
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/go-playground/validator/v10 v10.15.5 h1:LEBecTWb/1j5TNY1YYG2RcOUN3R7NLylN+x8TTueE24=
|
|
||||||
github.com/go-playground/validator/v10 v10.15.5/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||||
|
@ -396,9 +392,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe
|
||||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
|
||||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||||
|
@ -518,8 +513,6 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
|
||||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
|
||||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
@ -547,8 +540,6 @@ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI
|
||||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/olahol/melody v1.1.4 h1:RQHfKZkQmDxI0+SLZRNBCn4LiXdqxLKRGSkT8Dyoe/E=
|
github.com/olahol/melody v1.1.4 h1:RQHfKZkQmDxI0+SLZRNBCn4LiXdqxLKRGSkT8Dyoe/E=
|
||||||
github.com/olahol/melody v1.1.4/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4=
|
github.com/olahol/melody v1.1.4/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||||
|
@ -604,11 +595,9 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
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.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.30.0 h1:SymVODrcRsaRaSInD9yQtKbtWqwsfoPcRff/oRXLj4c=
|
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
|
||||||
github.com/rs/zerolog v1.30.0/go.mod h1:/tk+P47gFdPXq4QYjvCmT5/Gsug2nagsFWBWhAiSi1w=
|
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
|
||||||
github.com/rs/zerolog v1.31.0 h1:FcTR3NnLWW+NnTwwhFWiJSZr4ECLpqCm6QsEnyvbV4A=
|
|
||||||
github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
|
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
|
@ -622,10 +611,7 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
|
||||||
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
|
||||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
|
github.com/spf13/viper v1.14.0/go.mod h1:WT//axPky3FdvXHzGw33dNdXXXfFQqmEalje+egj8As=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
@ -650,15 +636,13 @@ github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
|
||||||
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
|
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
|
||||||
github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww=
|
github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww=
|
||||||
github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ=
|
github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ=
|
||||||
github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04=
|
github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg=
|
||||||
github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E=
|
github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto=
|
||||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||||
github.com/yeqown/go-qrcode/v2 v2.2.2 h1:0comk6jEwi0oWNhKEmzx4JI+Q7XIneAApmFSMKWmSVc=
|
github.com/yeqown/go-qrcode/v2 v2.2.2 h1:0comk6jEwi0oWNhKEmzx4JI+Q7XIneAApmFSMKWmSVc=
|
||||||
github.com/yeqown/go-qrcode/v2 v2.2.2/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24=
|
github.com/yeqown/go-qrcode/v2 v2.2.2/go.mod h1:2Qsk2APUCPne0TsRo40DIkI5MYnbzYKCnKGEFWrxd24=
|
||||||
github.com/yeqown/go-qrcode/writer/standard v1.2.1 h1:FMRZiur5yApUIe4fqtqmcdl/XQTZAZWt2DhkPx4VIW0=
|
github.com/yeqown/go-qrcode/writer/standard v1.2.1 h1:FMRZiur5yApUIe4fqtqmcdl/XQTZAZWt2DhkPx4VIW0=
|
||||||
github.com/yeqown/go-qrcode/writer/standard v1.2.1/go.mod h1:ZelyDFiVymrauRjUn454iF7bjsabmB1vixkDA5kq2bw=
|
github.com/yeqown/go-qrcode/writer/standard v1.2.1/go.mod h1:ZelyDFiVymrauRjUn454iF7bjsabmB1vixkDA5kq2bw=
|
||||||
github.com/yeqown/go-qrcode/writer/standard v1.2.2 h1:gyzunKXgC0ZUpKqQFUImbAEwewAiwNCkxFEKZV80Kt4=
|
|
||||||
github.com/yeqown/go-qrcode/writer/standard v1.2.2/go.mod h1:bbVRiBJSRPj4UBZP/biLG7JSd9kHqXjErk1eakAMnRA=
|
|
||||||
github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0=
|
github.com/yeqown/reedsolomon v1.0.0 h1:x1h/Ej/uJnNu8jaX7GLHBWmZKCAWjEJTetkqaabr4B0=
|
||||||
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
|
github.com/yeqown/reedsolomon v1.0.0/go.mod h1:P76zpcn2TCuL0ul1Fso373qHRc69LKwAw/Iy6g1WiiM=
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
@ -701,10 +685,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
|
||||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||||
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
|
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
|
||||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -945,10 +927,8 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
|
||||||
golang.org/x/sys v0.13.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-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.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
@ -964,9 +944,8 @@ 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.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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -1301,10 +1280,8 @@ modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o=
|
||||||
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA=
|
modernc.org/sqlite v1.24.0 h1:EsClRIWHGhLTCX44p+Ri/JLD+vFGo0QGjasg2/F9TlI=
|
||||||
modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
|
modernc.org/sqlite v1.24.0/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
|
||||||
modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw=
|
|
||||||
modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
|
|
||||||
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
||||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
||||||
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
|
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
|
||||||
|
|
|
@ -23,7 +23,7 @@ func (svc *ItemService) AttachmentPath(ctx context.Context, attachmentId uuid.UU
|
||||||
|
|
||||||
func (svc *ItemService) AttachmentUpdate(ctx Context, itemId uuid.UUID, data *repo.ItemAttachmentUpdate) (repo.ItemOut, error) {
|
func (svc *ItemService) AttachmentUpdate(ctx Context, itemId uuid.UUID, data *repo.ItemAttachmentUpdate) (repo.ItemOut, error) {
|
||||||
// Update Attachment
|
// Update Attachment
|
||||||
attachment, err := svc.repo.Attachments.Update(ctx, data.ID, data)
|
attachment, err := svc.repo.Attachments.Update(ctx, data.ID, attachment.Type(data.Type))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return repo.ItemOut{}, err
|
return repo.ItemOut{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,6 @@ type Attachment struct {
|
||||||
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
||||||
// Type holds the value of the "type" field.
|
// Type holds the value of the "type" field.
|
||||||
Type attachment.Type `json:"type,omitempty"`
|
Type attachment.Type `json:"type,omitempty"`
|
||||||
// Primary holds the value of the "primary" field.
|
|
||||||
Primary bool `json:"primary,omitempty"`
|
|
||||||
// Edges holds the relations/edges for other nodes in the graph.
|
// Edges holds the relations/edges for other nodes in the graph.
|
||||||
// The values are being populated by the AttachmentQuery when eager-loading is set.
|
// The values are being populated by the AttachmentQuery when eager-loading is set.
|
||||||
Edges AttachmentEdges `json:"edges"`
|
Edges AttachmentEdges `json:"edges"`
|
||||||
|
@ -78,8 +76,6 @@ func (*Attachment) scanValues(columns []string) ([]any, error) {
|
||||||
values := make([]any, len(columns))
|
values := make([]any, len(columns))
|
||||||
for i := range columns {
|
for i := range columns {
|
||||||
switch columns[i] {
|
switch columns[i] {
|
||||||
case attachment.FieldPrimary:
|
|
||||||
values[i] = new(sql.NullBool)
|
|
||||||
case attachment.FieldType:
|
case attachment.FieldType:
|
||||||
values[i] = new(sql.NullString)
|
values[i] = new(sql.NullString)
|
||||||
case attachment.FieldCreatedAt, attachment.FieldUpdatedAt:
|
case attachment.FieldCreatedAt, attachment.FieldUpdatedAt:
|
||||||
|
@ -129,12 +125,6 @@ func (a *Attachment) assignValues(columns []string, values []any) error {
|
||||||
} else if value.Valid {
|
} else if value.Valid {
|
||||||
a.Type = attachment.Type(value.String)
|
a.Type = attachment.Type(value.String)
|
||||||
}
|
}
|
||||||
case attachment.FieldPrimary:
|
|
||||||
if value, ok := values[i].(*sql.NullBool); !ok {
|
|
||||||
return fmt.Errorf("unexpected type %T for field primary", values[i])
|
|
||||||
} else if value.Valid {
|
|
||||||
a.Primary = value.Bool
|
|
||||||
}
|
|
||||||
case attachment.ForeignKeys[0]:
|
case attachment.ForeignKeys[0]:
|
||||||
if value, ok := values[i].(*sql.NullScanner); !ok {
|
if value, ok := values[i].(*sql.NullScanner); !ok {
|
||||||
return fmt.Errorf("unexpected type %T for field document_attachments", values[i])
|
return fmt.Errorf("unexpected type %T for field document_attachments", values[i])
|
||||||
|
@ -203,9 +193,6 @@ func (a *Attachment) String() string {
|
||||||
builder.WriteString(", ")
|
builder.WriteString(", ")
|
||||||
builder.WriteString("type=")
|
builder.WriteString("type=")
|
||||||
builder.WriteString(fmt.Sprintf("%v", a.Type))
|
builder.WriteString(fmt.Sprintf("%v", a.Type))
|
||||||
builder.WriteString(", ")
|
|
||||||
builder.WriteString("primary=")
|
|
||||||
builder.WriteString(fmt.Sprintf("%v", a.Primary))
|
|
||||||
builder.WriteByte(')')
|
builder.WriteByte(')')
|
||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,6 @@ const (
|
||||||
FieldUpdatedAt = "updated_at"
|
FieldUpdatedAt = "updated_at"
|
||||||
// FieldType holds the string denoting the type field in the database.
|
// FieldType holds the string denoting the type field in the database.
|
||||||
FieldType = "type"
|
FieldType = "type"
|
||||||
// FieldPrimary holds the string denoting the primary field in the database.
|
|
||||||
FieldPrimary = "primary"
|
|
||||||
// EdgeItem holds the string denoting the item edge name in mutations.
|
// EdgeItem holds the string denoting the item edge name in mutations.
|
||||||
EdgeItem = "item"
|
EdgeItem = "item"
|
||||||
// EdgeDocument holds the string denoting the document edge name in mutations.
|
// EdgeDocument holds the string denoting the document edge name in mutations.
|
||||||
|
@ -52,7 +50,6 @@ var Columns = []string{
|
||||||
FieldCreatedAt,
|
FieldCreatedAt,
|
||||||
FieldUpdatedAt,
|
FieldUpdatedAt,
|
||||||
FieldType,
|
FieldType,
|
||||||
FieldPrimary,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForeignKeys holds the SQL foreign-keys that are owned by the "attachments"
|
// ForeignKeys holds the SQL foreign-keys that are owned by the "attachments"
|
||||||
|
@ -84,8 +81,6 @@ var (
|
||||||
DefaultUpdatedAt func() time.Time
|
DefaultUpdatedAt func() time.Time
|
||||||
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
|
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
|
||||||
UpdateDefaultUpdatedAt func() time.Time
|
UpdateDefaultUpdatedAt func() time.Time
|
||||||
// DefaultPrimary holds the default value on creation for the "primary" field.
|
|
||||||
DefaultPrimary bool
|
|
||||||
// DefaultID holds the default value on creation for the "id" field.
|
// DefaultID holds the default value on creation for the "id" field.
|
||||||
DefaultID func() uuid.UUID
|
DefaultID func() uuid.UUID
|
||||||
)
|
)
|
||||||
|
@ -142,11 +137,6 @@ func ByType(opts ...sql.OrderTermOption) OrderOption {
|
||||||
return sql.OrderByField(FieldType, opts...).ToFunc()
|
return sql.OrderByField(FieldType, opts...).ToFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ByPrimary orders the results by the primary field.
|
|
||||||
func ByPrimary(opts ...sql.OrderTermOption) OrderOption {
|
|
||||||
return sql.OrderByField(FieldPrimary, opts...).ToFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ByItemField orders the results by item field.
|
// ByItemField orders the results by item field.
|
||||||
func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption {
|
func ByItemField(field string, opts ...sql.OrderTermOption) OrderOption {
|
||||||
return func(s *sql.Selector) {
|
return func(s *sql.Selector) {
|
||||||
|
|
|
@ -66,11 +66,6 @@ func UpdatedAt(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(sql.FieldEQ(FieldUpdatedAt, v))
|
return predicate.Attachment(sql.FieldEQ(FieldUpdatedAt, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Primary applies equality check predicate on the "primary" field. It's identical to PrimaryEQ.
|
|
||||||
func Primary(v bool) predicate.Attachment {
|
|
||||||
return predicate.Attachment(sql.FieldEQ(FieldPrimary, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
// CreatedAtEQ applies the EQ predicate on the "created_at" field.
|
||||||
func CreatedAtEQ(v time.Time) predicate.Attachment {
|
func CreatedAtEQ(v time.Time) predicate.Attachment {
|
||||||
return predicate.Attachment(sql.FieldEQ(FieldCreatedAt, v))
|
return predicate.Attachment(sql.FieldEQ(FieldCreatedAt, v))
|
||||||
|
@ -171,16 +166,6 @@ func TypeNotIn(vs ...Type) predicate.Attachment {
|
||||||
return predicate.Attachment(sql.FieldNotIn(FieldType, vs...))
|
return predicate.Attachment(sql.FieldNotIn(FieldType, vs...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrimaryEQ applies the EQ predicate on the "primary" field.
|
|
||||||
func PrimaryEQ(v bool) predicate.Attachment {
|
|
||||||
return predicate.Attachment(sql.FieldEQ(FieldPrimary, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrimaryNEQ applies the NEQ predicate on the "primary" field.
|
|
||||||
func PrimaryNEQ(v bool) predicate.Attachment {
|
|
||||||
return predicate.Attachment(sql.FieldNEQ(FieldPrimary, v))
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasItem applies the HasEdge predicate on the "item" edge.
|
// HasItem applies the HasEdge predicate on the "item" edge.
|
||||||
func HasItem() predicate.Attachment {
|
func HasItem() predicate.Attachment {
|
||||||
return predicate.Attachment(func(s *sql.Selector) {
|
return predicate.Attachment(func(s *sql.Selector) {
|
||||||
|
|
|
@ -65,20 +65,6 @@ func (ac *AttachmentCreate) SetNillableType(a *attachment.Type) *AttachmentCreat
|
||||||
return ac
|
return ac
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPrimary sets the "primary" field.
|
|
||||||
func (ac *AttachmentCreate) SetPrimary(b bool) *AttachmentCreate {
|
|
||||||
ac.mutation.SetPrimary(b)
|
|
||||||
return ac
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNillablePrimary sets the "primary" field if the given value is not nil.
|
|
||||||
func (ac *AttachmentCreate) SetNillablePrimary(b *bool) *AttachmentCreate {
|
|
||||||
if b != nil {
|
|
||||||
ac.SetPrimary(*b)
|
|
||||||
}
|
|
||||||
return ac
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetID sets the "id" field.
|
// SetID sets the "id" field.
|
||||||
func (ac *AttachmentCreate) SetID(u uuid.UUID) *AttachmentCreate {
|
func (ac *AttachmentCreate) SetID(u uuid.UUID) *AttachmentCreate {
|
||||||
ac.mutation.SetID(u)
|
ac.mutation.SetID(u)
|
||||||
|
@ -162,10 +148,6 @@ func (ac *AttachmentCreate) defaults() {
|
||||||
v := attachment.DefaultType
|
v := attachment.DefaultType
|
||||||
ac.mutation.SetType(v)
|
ac.mutation.SetType(v)
|
||||||
}
|
}
|
||||||
if _, ok := ac.mutation.Primary(); !ok {
|
|
||||||
v := attachment.DefaultPrimary
|
|
||||||
ac.mutation.SetPrimary(v)
|
|
||||||
}
|
|
||||||
if _, ok := ac.mutation.ID(); !ok {
|
if _, ok := ac.mutation.ID(); !ok {
|
||||||
v := attachment.DefaultID()
|
v := attachment.DefaultID()
|
||||||
ac.mutation.SetID(v)
|
ac.mutation.SetID(v)
|
||||||
|
@ -188,9 +170,6 @@ func (ac *AttachmentCreate) check() error {
|
||||||
return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Attachment.type": %w`, err)}
|
return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "Attachment.type": %w`, err)}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, ok := ac.mutation.Primary(); !ok {
|
|
||||||
return &ValidationError{Name: "primary", err: errors.New(`ent: missing required field "Attachment.primary"`)}
|
|
||||||
}
|
|
||||||
if _, ok := ac.mutation.ItemID(); !ok {
|
if _, ok := ac.mutation.ItemID(); !ok {
|
||||||
return &ValidationError{Name: "item", err: errors.New(`ent: missing required edge "Attachment.item"`)}
|
return &ValidationError{Name: "item", err: errors.New(`ent: missing required edge "Attachment.item"`)}
|
||||||
}
|
}
|
||||||
|
@ -244,10 +223,6 @@ func (ac *AttachmentCreate) createSpec() (*Attachment, *sqlgraph.CreateSpec) {
|
||||||
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
||||||
_node.Type = value
|
_node.Type = value
|
||||||
}
|
}
|
||||||
if value, ok := ac.mutation.Primary(); ok {
|
|
||||||
_spec.SetField(attachment.FieldPrimary, field.TypeBool, value)
|
|
||||||
_node.Primary = value
|
|
||||||
}
|
|
||||||
if nodes := ac.mutation.ItemIDs(); len(nodes) > 0 {
|
if nodes := ac.mutation.ItemIDs(); len(nodes) > 0 {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2O,
|
||||||
|
|
|
@ -51,20 +51,6 @@ func (au *AttachmentUpdate) SetNillableType(a *attachment.Type) *AttachmentUpdat
|
||||||
return au
|
return au
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPrimary sets the "primary" field.
|
|
||||||
func (au *AttachmentUpdate) SetPrimary(b bool) *AttachmentUpdate {
|
|
||||||
au.mutation.SetPrimary(b)
|
|
||||||
return au
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNillablePrimary sets the "primary" field if the given value is not nil.
|
|
||||||
func (au *AttachmentUpdate) SetNillablePrimary(b *bool) *AttachmentUpdate {
|
|
||||||
if b != nil {
|
|
||||||
au.SetPrimary(*b)
|
|
||||||
}
|
|
||||||
return au
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetItemID sets the "item" edge to the Item entity by ID.
|
// SetItemID sets the "item" edge to the Item entity by ID.
|
||||||
func (au *AttachmentUpdate) SetItemID(id uuid.UUID) *AttachmentUpdate {
|
func (au *AttachmentUpdate) SetItemID(id uuid.UUID) *AttachmentUpdate {
|
||||||
au.mutation.SetItemID(id)
|
au.mutation.SetItemID(id)
|
||||||
|
@ -174,9 +160,6 @@ func (au *AttachmentUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||||
if value, ok := au.mutation.GetType(); ok {
|
if value, ok := au.mutation.GetType(); ok {
|
||||||
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
||||||
}
|
}
|
||||||
if value, ok := au.mutation.Primary(); ok {
|
|
||||||
_spec.SetField(attachment.FieldPrimary, field.TypeBool, value)
|
|
||||||
}
|
|
||||||
if au.mutation.ItemCleared() {
|
if au.mutation.ItemCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2O,
|
||||||
|
@ -275,20 +258,6 @@ func (auo *AttachmentUpdateOne) SetNillableType(a *attachment.Type) *AttachmentU
|
||||||
return auo
|
return auo
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPrimary sets the "primary" field.
|
|
||||||
func (auo *AttachmentUpdateOne) SetPrimary(b bool) *AttachmentUpdateOne {
|
|
||||||
auo.mutation.SetPrimary(b)
|
|
||||||
return auo
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNillablePrimary sets the "primary" field if the given value is not nil.
|
|
||||||
func (auo *AttachmentUpdateOne) SetNillablePrimary(b *bool) *AttachmentUpdateOne {
|
|
||||||
if b != nil {
|
|
||||||
auo.SetPrimary(*b)
|
|
||||||
}
|
|
||||||
return auo
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetItemID sets the "item" edge to the Item entity by ID.
|
// SetItemID sets the "item" edge to the Item entity by ID.
|
||||||
func (auo *AttachmentUpdateOne) SetItemID(id uuid.UUID) *AttachmentUpdateOne {
|
func (auo *AttachmentUpdateOne) SetItemID(id uuid.UUID) *AttachmentUpdateOne {
|
||||||
auo.mutation.SetItemID(id)
|
auo.mutation.SetItemID(id)
|
||||||
|
@ -428,9 +397,6 @@ func (auo *AttachmentUpdateOne) sqlSave(ctx context.Context) (_node *Attachment,
|
||||||
if value, ok := auo.mutation.GetType(); ok {
|
if value, ok := auo.mutation.GetType(); ok {
|
||||||
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
_spec.SetField(attachment.FieldType, field.TypeEnum, value)
|
||||||
}
|
}
|
||||||
if value, ok := auo.mutation.Primary(); ok {
|
|
||||||
_spec.SetField(attachment.FieldPrimary, field.TypeBool, value)
|
|
||||||
}
|
|
||||||
if auo.mutation.ItemCleared() {
|
if auo.mutation.ItemCleared() {
|
||||||
edge := &sqlgraph.EdgeSpec{
|
edge := &sqlgraph.EdgeSpec{
|
||||||
Rel: sqlgraph.M2O,
|
Rel: sqlgraph.M2O,
|
||||||
|
|
|
@ -137,6 +137,7 @@ const (
|
||||||
CurrencyBrl Currency = "brl"
|
CurrencyBrl Currency = "brl"
|
||||||
CurrencyCad Currency = "cad"
|
CurrencyCad Currency = "cad"
|
||||||
CurrencyChf Currency = "chf"
|
CurrencyChf Currency = "chf"
|
||||||
|
CurrencyCny Currency = "cny"
|
||||||
CurrencyCzk Currency = "czk"
|
CurrencyCzk Currency = "czk"
|
||||||
CurrencyDkk Currency = "dkk"
|
CurrencyDkk Currency = "dkk"
|
||||||
CurrencyEur Currency = "eur"
|
CurrencyEur Currency = "eur"
|
||||||
|
@ -159,8 +160,6 @@ const (
|
||||||
CurrencyThb Currency = "thb"
|
CurrencyThb Currency = "thb"
|
||||||
CurrencyTry Currency = "try"
|
CurrencyTry Currency = "try"
|
||||||
CurrencyUsd Currency = "usd"
|
CurrencyUsd Currency = "usd"
|
||||||
CurrencyXag Currency = "xag"
|
|
||||||
CurrencyXau Currency = "xau"
|
|
||||||
CurrencyZar Currency = "zar"
|
CurrencyZar Currency = "zar"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -171,7 +170,7 @@ func (c Currency) String() string {
|
||||||
// CurrencyValidator is a validator for the "currency" field enum values. It is called by the builders before save.
|
// CurrencyValidator is a validator for the "currency" field enum values. It is called by the builders before save.
|
||||||
func CurrencyValidator(c Currency) error {
|
func CurrencyValidator(c Currency) error {
|
||||||
switch c {
|
switch c {
|
||||||
case CurrencyAed, CurrencyAud, CurrencyBgn, CurrencyBrl, CurrencyCad, CurrencyChf, CurrencyCzk, CurrencyDkk, CurrencyEur, CurrencyGbp, CurrencyHkd, CurrencyIdr, CurrencyInr, CurrencyJpy, CurrencyKrw, CurrencyMxn, CurrencyNok, CurrencyNzd, CurrencyPln, CurrencyRmb, CurrencyRon, CurrencyRub, CurrencySar, CurrencySek, CurrencySgd, CurrencyThb, CurrencyTry, CurrencyUsd, CurrencyXag, CurrencyXau, CurrencyZar:
|
case CurrencyAed, CurrencyAud, CurrencyBgn, CurrencyBrl, CurrencyCad, CurrencyChf, CurrencyCny, CurrencyCzk, CurrencyDkk, CurrencyEur, CurrencyGbp, CurrencyHkd, CurrencyIdr, CurrencyInr, CurrencyJpy, CurrencyKrw, CurrencyMxn, CurrencyNok, CurrencyNzd, CurrencyPln, CurrencyRmb, CurrencyRon, CurrencyRub, CurrencySar, CurrencySek, CurrencySgd, CurrencyThb, CurrencyTry, CurrencyUsd, CurrencyZar:
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("group: invalid enum value for currency field: %q", c)
|
return fmt.Errorf("group: invalid enum value for currency field: %q", c)
|
||||||
|
|
|
@ -14,7 +14,6 @@ var (
|
||||||
{Name: "created_at", Type: field.TypeTime},
|
{Name: "created_at", Type: field.TypeTime},
|
||||||
{Name: "updated_at", Type: field.TypeTime},
|
{Name: "updated_at", Type: field.TypeTime},
|
||||||
{Name: "type", Type: field.TypeEnum, Enums: []string{"photo", "manual", "warranty", "attachment", "receipt"}, Default: "attachment"},
|
{Name: "type", Type: field.TypeEnum, Enums: []string{"photo", "manual", "warranty", "attachment", "receipt"}, Default: "attachment"},
|
||||||
{Name: "primary", Type: field.TypeBool, Default: false},
|
|
||||||
{Name: "document_attachments", Type: field.TypeUUID},
|
{Name: "document_attachments", Type: field.TypeUUID},
|
||||||
{Name: "item_attachments", Type: field.TypeUUID},
|
{Name: "item_attachments", Type: field.TypeUUID},
|
||||||
}
|
}
|
||||||
|
@ -26,13 +25,13 @@ var (
|
||||||
ForeignKeys: []*schema.ForeignKey{
|
ForeignKeys: []*schema.ForeignKey{
|
||||||
{
|
{
|
||||||
Symbol: "attachments_documents_attachments",
|
Symbol: "attachments_documents_attachments",
|
||||||
Columns: []*schema.Column{AttachmentsColumns[5]},
|
Columns: []*schema.Column{AttachmentsColumns[4]},
|
||||||
RefColumns: []*schema.Column{DocumentsColumns[0]},
|
RefColumns: []*schema.Column{DocumentsColumns[0]},
|
||||||
OnDelete: schema.Cascade,
|
OnDelete: schema.Cascade,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Symbol: "attachments_items_attachments",
|
Symbol: "attachments_items_attachments",
|
||||||
Columns: []*schema.Column{AttachmentsColumns[6]},
|
Columns: []*schema.Column{AttachmentsColumns[5]},
|
||||||
RefColumns: []*schema.Column{ItemsColumns[0]},
|
RefColumns: []*schema.Column{ItemsColumns[0]},
|
||||||
OnDelete: schema.Cascade,
|
OnDelete: schema.Cascade,
|
||||||
},
|
},
|
||||||
|
@ -117,7 +116,7 @@ var (
|
||||||
{Name: "created_at", Type: field.TypeTime},
|
{Name: "created_at", Type: field.TypeTime},
|
||||||
{Name: "updated_at", Type: field.TypeTime},
|
{Name: "updated_at", Type: field.TypeTime},
|
||||||
{Name: "name", Type: field.TypeString, Size: 255},
|
{Name: "name", Type: field.TypeString, Size: 255},
|
||||||
{Name: "currency", Type: field.TypeEnum, Enums: []string{"aed", "aud", "bgn", "brl", "cad", "chf", "czk", "dkk", "eur", "gbp", "hkd", "idr", "inr", "jpy", "krw", "mxn", "nok", "nzd", "pln", "rmb", "ron", "rub", "sar", "sek", "sgd", "thb", "try", "usd", "xag", "xau", "zar"}, Default: "usd"},
|
{Name: "currency", Type: field.TypeEnum, Enums: []string{"aed", "aud", "bgn", "brl", "cad", "chf", "cny", "czk", "dkk", "eur", "gbp", "hkd", "idr", "inr", "jpy", "krw", "mxn", "nok", "nzd", "pln", "rmb", "ron", "rub", "sar", "sek", "sgd", "thb", "try", "usd", "zar"}, Default: "usd"},
|
||||||
}
|
}
|
||||||
// GroupsTable holds the schema information for the "groups" table.
|
// GroupsTable holds the schema information for the "groups" table.
|
||||||
GroupsTable = &schema.Table{
|
GroupsTable = &schema.Table{
|
||||||
|
|
|
@ -61,7 +61,6 @@ type AttachmentMutation struct {
|
||||||
created_at *time.Time
|
created_at *time.Time
|
||||||
updated_at *time.Time
|
updated_at *time.Time
|
||||||
_type *attachment.Type
|
_type *attachment.Type
|
||||||
primary *bool
|
|
||||||
clearedFields map[string]struct{}
|
clearedFields map[string]struct{}
|
||||||
item *uuid.UUID
|
item *uuid.UUID
|
||||||
cleareditem bool
|
cleareditem bool
|
||||||
|
@ -284,42 +283,6 @@ func (m *AttachmentMutation) ResetType() {
|
||||||
m._type = nil
|
m._type = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPrimary sets the "primary" field.
|
|
||||||
func (m *AttachmentMutation) SetPrimary(b bool) {
|
|
||||||
m.primary = &b
|
|
||||||
}
|
|
||||||
|
|
||||||
// Primary returns the value of the "primary" field in the mutation.
|
|
||||||
func (m *AttachmentMutation) Primary() (r bool, exists bool) {
|
|
||||||
v := m.primary
|
|
||||||
if v == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return *v, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// OldPrimary returns the old "primary" field's value of the Attachment entity.
|
|
||||||
// If the Attachment object wasn't provided to the builder, the object is fetched from the database.
|
|
||||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
|
||||||
func (m *AttachmentMutation) OldPrimary(ctx context.Context) (v bool, err error) {
|
|
||||||
if !m.op.Is(OpUpdateOne) {
|
|
||||||
return v, errors.New("OldPrimary is only allowed on UpdateOne operations")
|
|
||||||
}
|
|
||||||
if m.id == nil || m.oldValue == nil {
|
|
||||||
return v, errors.New("OldPrimary requires an ID field in the mutation")
|
|
||||||
}
|
|
||||||
oldValue, err := m.oldValue(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return v, fmt.Errorf("querying old value for OldPrimary: %w", err)
|
|
||||||
}
|
|
||||||
return oldValue.Primary, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetPrimary resets all changes to the "primary" field.
|
|
||||||
func (m *AttachmentMutation) ResetPrimary() {
|
|
||||||
m.primary = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetItemID sets the "item" edge to the Item entity by id.
|
// SetItemID sets the "item" edge to the Item entity by id.
|
||||||
func (m *AttachmentMutation) SetItemID(id uuid.UUID) {
|
func (m *AttachmentMutation) SetItemID(id uuid.UUID) {
|
||||||
m.item = &id
|
m.item = &id
|
||||||
|
@ -432,7 +395,7 @@ func (m *AttachmentMutation) Type() string {
|
||||||
// order to get all numeric fields that were incremented/decremented, call
|
// order to get all numeric fields that were incremented/decremented, call
|
||||||
// AddedFields().
|
// AddedFields().
|
||||||
func (m *AttachmentMutation) Fields() []string {
|
func (m *AttachmentMutation) Fields() []string {
|
||||||
fields := make([]string, 0, 4)
|
fields := make([]string, 0, 3)
|
||||||
if m.created_at != nil {
|
if m.created_at != nil {
|
||||||
fields = append(fields, attachment.FieldCreatedAt)
|
fields = append(fields, attachment.FieldCreatedAt)
|
||||||
}
|
}
|
||||||
|
@ -442,9 +405,6 @@ func (m *AttachmentMutation) Fields() []string {
|
||||||
if m._type != nil {
|
if m._type != nil {
|
||||||
fields = append(fields, attachment.FieldType)
|
fields = append(fields, attachment.FieldType)
|
||||||
}
|
}
|
||||||
if m.primary != nil {
|
|
||||||
fields = append(fields, attachment.FieldPrimary)
|
|
||||||
}
|
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,8 +419,6 @@ func (m *AttachmentMutation) Field(name string) (ent.Value, bool) {
|
||||||
return m.UpdatedAt()
|
return m.UpdatedAt()
|
||||||
case attachment.FieldType:
|
case attachment.FieldType:
|
||||||
return m.GetType()
|
return m.GetType()
|
||||||
case attachment.FieldPrimary:
|
|
||||||
return m.Primary()
|
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
@ -476,8 +434,6 @@ func (m *AttachmentMutation) OldField(ctx context.Context, name string) (ent.Val
|
||||||
return m.OldUpdatedAt(ctx)
|
return m.OldUpdatedAt(ctx)
|
||||||
case attachment.FieldType:
|
case attachment.FieldType:
|
||||||
return m.OldType(ctx)
|
return m.OldType(ctx)
|
||||||
case attachment.FieldPrimary:
|
|
||||||
return m.OldPrimary(ctx)
|
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unknown Attachment field %s", name)
|
return nil, fmt.Errorf("unknown Attachment field %s", name)
|
||||||
}
|
}
|
||||||
|
@ -508,13 +464,6 @@ func (m *AttachmentMutation) SetField(name string, value ent.Value) error {
|
||||||
}
|
}
|
||||||
m.SetType(v)
|
m.SetType(v)
|
||||||
return nil
|
return nil
|
||||||
case attachment.FieldPrimary:
|
|
||||||
v, ok := value.(bool)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
|
||||||
}
|
|
||||||
m.SetPrimary(v)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unknown Attachment field %s", name)
|
return fmt.Errorf("unknown Attachment field %s", name)
|
||||||
}
|
}
|
||||||
|
@ -573,9 +522,6 @@ func (m *AttachmentMutation) ResetField(name string) error {
|
||||||
case attachment.FieldType:
|
case attachment.FieldType:
|
||||||
m.ResetType()
|
m.ResetType()
|
||||||
return nil
|
return nil
|
||||||
case attachment.FieldPrimary:
|
|
||||||
m.ResetPrimary()
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unknown Attachment field %s", name)
|
return fmt.Errorf("unknown Attachment field %s", name)
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,10 +40,6 @@ func init() {
|
||||||
attachment.DefaultUpdatedAt = attachmentDescUpdatedAt.Default.(func() time.Time)
|
attachment.DefaultUpdatedAt = attachmentDescUpdatedAt.Default.(func() time.Time)
|
||||||
// attachment.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
|
// attachment.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
|
||||||
attachment.UpdateDefaultUpdatedAt = attachmentDescUpdatedAt.UpdateDefault.(func() time.Time)
|
attachment.UpdateDefaultUpdatedAt = attachmentDescUpdatedAt.UpdateDefault.(func() time.Time)
|
||||||
// attachmentDescPrimary is the schema descriptor for primary field.
|
|
||||||
attachmentDescPrimary := attachmentFields[1].Descriptor()
|
|
||||||
// attachment.DefaultPrimary holds the default value on creation for the primary field.
|
|
||||||
attachment.DefaultPrimary = attachmentDescPrimary.Default.(bool)
|
|
||||||
// attachmentDescID is the schema descriptor for id field.
|
// attachmentDescID is the schema descriptor for id field.
|
||||||
attachmentDescID := attachmentMixinFields0[0].Descriptor()
|
attachmentDescID := attachmentMixinFields0[0].Descriptor()
|
||||||
// attachment.DefaultID holds the default value on creation for the id field.
|
// attachment.DefaultID holds the default value on creation for the id field.
|
||||||
|
|
|
@ -24,8 +24,6 @@ func (Attachment) Fields() []ent.Field {
|
||||||
field.Enum("type").
|
field.Enum("type").
|
||||||
Values("photo", "manual", "warranty", "attachment", "receipt").
|
Values("photo", "manual", "warranty", "attachment", "receipt").
|
||||||
Default("attachment"),
|
Default("attachment"),
|
||||||
field.Bool("primary").
|
|
||||||
Default(false),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,8 +58,6 @@ func (Group) Fields() []ent.Field {
|
||||||
"thb",
|
"thb",
|
||||||
"try",
|
"try",
|
||||||
"usd",
|
"usd",
|
||||||
"xag",
|
|
||||||
"xau",
|
|
||||||
"zar",
|
"zar",
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
-- Disable the enforcement of foreign-keys constraints
|
|
||||||
PRAGMA foreign_keys = off;
|
|
||||||
-- Create "new_attachments" table
|
|
||||||
CREATE TABLE `new_attachments` (`id` uuid NOT NULL, `created_at` datetime NOT NULL, `updated_at` datetime NOT NULL, `type` text NOT NULL DEFAULT 'attachment', `primary` bool NOT NULL DEFAULT false, `document_attachments` uuid NOT NULL, `item_attachments` uuid NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `attachments_documents_attachments` FOREIGN KEY (`document_attachments`) REFERENCES `documents` (`id`) ON DELETE CASCADE, CONSTRAINT `attachments_items_attachments` FOREIGN KEY (`item_attachments`) REFERENCES `items` (`id`) ON DELETE CASCADE);
|
|
||||||
-- Copy rows from old table "attachments" to new temporary table "new_attachments"
|
|
||||||
INSERT INTO `new_attachments` (`id`, `created_at`, `updated_at`, `type`, `document_attachments`, `item_attachments`) SELECT `id`, `created_at`, `updated_at`, `type`, `document_attachments`, `item_attachments` FROM `attachments`;
|
|
||||||
-- Drop "attachments" table after copying rows
|
|
||||||
DROP TABLE `attachments`;
|
|
||||||
-- Rename temporary table "new_attachments" to "attachments"
|
|
||||||
ALTER TABLE `new_attachments` RENAME TO `attachments`;
|
|
||||||
-- Enable back the enforcement of foreign-keys constraints
|
|
||||||
PRAGMA foreign_keys = on;
|
|
|
@ -1,4 +1,4 @@
|
||||||
h1:sjJCTAqc9FG8BKBIzh5ZynYD/Ilz6vnLqM4XX83WQ4M=
|
h1:VjVLPBHzJ8N1Hiw+Aeitb0alnVn9UFilnajCzc+pie8=
|
||||||
20220929052825_init.sql h1:ZlCqm1wzjDmofeAcSX3jE4h4VcdTNGpRg2eabztDy9Q=
|
20220929052825_init.sql h1:ZlCqm1wzjDmofeAcSX3jE4h4VcdTNGpRg2eabztDy9Q=
|
||||||
20221001210956_group_invitations.sql h1:YQKJFtE39wFOcRNbZQ/d+ZlHwrcfcsZlcv/pLEYdpjw=
|
20221001210956_group_invitations.sql h1:YQKJFtE39wFOcRNbZQ/d+ZlHwrcfcsZlcv/pLEYdpjw=
|
||||||
20221009173029_add_user_roles.sql h1:vWmzAfgEWQeGk0Vn70zfVPCcfEZth3E0JcvyKTjpYyU=
|
20221009173029_add_user_roles.sql h1:vWmzAfgEWQeGk0Vn70zfVPCcfEZth3E0JcvyKTjpYyU=
|
||||||
|
@ -12,4 +12,3 @@ h1:sjJCTAqc9FG8BKBIzh5ZynYD/Ilz6vnLqM4XX83WQ4M=
|
||||||
20230227024134_add_scheduled_date.sql h1:8qO5OBZ0AzsfYEQOAQQrYIjyhSwM+v1A+/ylLSoiyoc=
|
20230227024134_add_scheduled_date.sql h1:8qO5OBZ0AzsfYEQOAQQrYIjyhSwM+v1A+/ylLSoiyoc=
|
||||||
20230305065819_add_notifier_types.sql h1:r5xrgCKYQ2o9byBqYeAX1zdp94BLdaxf4vq9OmGHNl0=
|
20230305065819_add_notifier_types.sql h1:r5xrgCKYQ2o9byBqYeAX1zdp94BLdaxf4vq9OmGHNl0=
|
||||||
20230305071524_add_group_id_to_notifiers.sql h1:xDShqbyClcFhvJbwclOHdczgXbdffkxXNWjV61hL/t4=
|
20230305071524_add_group_id_to_notifiers.sql h1:xDShqbyClcFhvJbwclOHdczgXbdffkxXNWjV61hL/t4=
|
||||||
20231006213457_add_primary_attachment_flag.sql h1:J4tMSJQFa7vaj0jpnh8YKTssdyIjRyq6RXDXZIzDDu4=
|
|
||||||
|
|
|
@ -233,7 +233,7 @@ func (r *GroupRepository) StatsGroup(ctx context.Context, GID uuid.UUID) (GroupS
|
||||||
(SELECT COUNT(*) FROM items WHERE group_items = ? AND items.archived = false) AS total_items,
|
(SELECT COUNT(*) FROM items WHERE group_items = ? AND items.archived = false) AS total_items,
|
||||||
(SELECT COUNT(*) FROM locations WHERE group_locations = ?) AS total_locations,
|
(SELECT COUNT(*) FROM locations WHERE group_locations = ?) AS total_locations,
|
||||||
(SELECT COUNT(*) FROM labels WHERE group_labels = ?) AS total_labels,
|
(SELECT COUNT(*) FROM labels WHERE group_labels = ?) AS total_labels,
|
||||||
(SELECT SUM(purchase_price*quantity) FROM items WHERE group_items = ? AND items.archived = false) AS total_item_price,
|
(SELECT SUM(purchase_price) FROM items WHERE group_items = ? AND items.archived = false) AS total_item_price,
|
||||||
(SELECT COUNT(*)
|
(SELECT COUNT(*)
|
||||||
FROM items
|
FROM items
|
||||||
WHERE group_items = ?
|
WHERE group_items = ?
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
"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/ent/attachment"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/item"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// AttachmentRepo is a repository for Attachments table that links Items to Documents
|
// AttachmentRepo is a repository for Attachments table that links Items to Documents
|
||||||
|
@ -25,14 +24,12 @@ type (
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Document DocumentOut `json:"document"`
|
Document DocumentOut `json:"document"`
|
||||||
Primary bool `json:"primary"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemAttachmentUpdate struct {
|
ItemAttachmentUpdate struct {
|
||||||
ID uuid.UUID `json:"-"`
|
ID uuid.UUID `json:"-"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Primary bool `json:"primary"`
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,7 +39,6 @@ func ToItemAttachment(attachment *ent.Attachment) ItemAttachment {
|
||||||
CreatedAt: attachment.CreatedAt,
|
CreatedAt: attachment.CreatedAt,
|
||||||
UpdatedAt: attachment.UpdatedAt,
|
UpdatedAt: attachment.UpdatedAt,
|
||||||
Type: attachment.Type.String(),
|
Type: attachment.Type.String(),
|
||||||
Primary: attachment.Primary,
|
|
||||||
Document: DocumentOut{
|
Document: DocumentOut{
|
||||||
ID: attachment.Edges.Document.ID,
|
ID: attachment.Edges.Document.ID,
|
||||||
Title: attachment.Edges.Document.Title,
|
Title: attachment.Edges.Document.Title,
|
||||||
|
@ -68,33 +64,10 @@ func (r *AttachmentRepo) Get(ctx context.Context, id uuid.UUID) (*ent.Attachment
|
||||||
Only(ctx)
|
Only(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *AttachmentRepo) Update(ctx context.Context, itemId uuid.UUID, data *ItemAttachmentUpdate) (*ent.Attachment, error) {
|
func (r *AttachmentRepo) Update(ctx context.Context, itemId uuid.UUID, typ attachment.Type) (*ent.Attachment, error) {
|
||||||
// TODO: execute within Tx
|
itm, err := r.db.Attachment.UpdateOneID(itemId).
|
||||||
typ := attachment.Type(data.Type)
|
SetType(typ).
|
||||||
|
Save(ctx)
|
||||||
bldr := r.db.Attachment.UpdateOneID(itemId).
|
|
||||||
SetType(typ)
|
|
||||||
|
|
||||||
// Primary only applies to photos
|
|
||||||
if typ == attachment.TypePhoto {
|
|
||||||
bldr = bldr.SetPrimary(data.Primary)
|
|
||||||
} else {
|
|
||||||
bldr = bldr.SetPrimary(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
itm, err := bldr.Save(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure all other attachments are not primary
|
|
||||||
err = r.db.Attachment.Update().
|
|
||||||
Where(
|
|
||||||
attachment.HasItemWith(item.ID(itemId)),
|
|
||||||
attachment.IDNEQ(itm.ID),
|
|
||||||
).
|
|
||||||
SetPrimary(false).
|
|
||||||
Exec(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,10 +110,7 @@ func TestAttachmentRepo_Update(t *testing.T) {
|
||||||
|
|
||||||
for _, typ := range []attachment.Type{"photo", "manual", "warranty", "attachment"} {
|
for _, typ := range []attachment.Type{"photo", "manual", "warranty", "attachment"} {
|
||||||
t.Run(string(typ), func(t *testing.T) {
|
t.Run(string(typ), func(t *testing.T) {
|
||||||
_, err := tRepos.Attachments.Update(context.Background(), entity.ID, &ItemAttachmentUpdate{
|
_, err := tRepos.Attachments.Update(context.Background(), entity.ID, typ)
|
||||||
Type: string(typ),
|
|
||||||
})
|
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
updated, err := tRepos.Attachments.Get(context.Background(), entity.ID)
|
updated, err := tRepos.Attachments.Get(context.Background(), entity.ID)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
"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/ent/group"
|
"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/item"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/itemfield"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/itemfield"
|
||||||
|
@ -126,8 +125,6 @@ type (
|
||||||
// Edges
|
// Edges
|
||||||
Location *LocationSummary `json:"location,omitempty" extensions:"x-nullable,x-omitempty"`
|
Location *LocationSummary `json:"location,omitempty" extensions:"x-nullable,x-omitempty"`
|
||||||
Labels []LabelSummary `json:"labels"`
|
Labels []LabelSummary `json:"labels"`
|
||||||
|
|
||||||
ImageID *uuid.UUID `json:"imageId,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemOut struct {
|
ItemOut struct {
|
||||||
|
@ -177,16 +174,6 @@ func mapItemSummary(item *ent.Item) ItemSummary {
|
||||||
labels = mapEach(item.Edges.Label, mapLabelSummary)
|
labels = mapEach(item.Edges.Label, mapLabelSummary)
|
||||||
}
|
}
|
||||||
|
|
||||||
var imageID *uuid.UUID
|
|
||||||
if item.Edges.Attachments != nil {
|
|
||||||
for _, a := range item.Edges.Attachments {
|
|
||||||
if a.Primary && a.Edges.Document != nil {
|
|
||||||
imageID = &a.ID
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ItemSummary{
|
return ItemSummary{
|
||||||
ID: item.ID,
|
ID: item.ID,
|
||||||
Name: item.Name,
|
Name: item.Name,
|
||||||
|
@ -204,7 +191,6 @@ func mapItemSummary(item *ent.Item) ItemSummary {
|
||||||
|
|
||||||
// Warranty
|
// Warranty
|
||||||
Insured: item.Insured,
|
Insured: item.Insured,
|
||||||
ImageID: imageID,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,13 +407,7 @@ func (e *ItemsRepository) QueryByGroup(ctx context.Context, gid uuid.UUID, q Ite
|
||||||
|
|
||||||
qb = qb.
|
qb = qb.
|
||||||
WithLabel().
|
WithLabel().
|
||||||
WithLocation().
|
WithLocation()
|
||||||
WithAttachments(func(aq *ent.AttachmentQuery) {
|
|
||||||
aq.Where(
|
|
||||||
attachment.Primary(true),
|
|
||||||
).
|
|
||||||
WithDocument()
|
|
||||||
})
|
|
||||||
|
|
||||||
if q.Page != -1 || q.PageSize != -1 {
|
if q.Page != -1 || q.PageSize != -1 {
|
||||||
qb = qb.
|
qb = qb.
|
||||||
|
@ -553,13 +533,13 @@ func (e *ItemsRepository) Create(ctx context.Context, gid uuid.UUID, data ItemCr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ItemsRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
func (e *ItemsRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||||
err := e.db.Item.DeleteOneID(id).Exec(ctx)
|
err := e.db.Item.DeleteOneID(id).Exec(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
e.publishMutationEvent(id)
|
e.publishMutationEvent(id)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ItemsRepository) DeleteByGroup(ctx context.Context, gid, id uuid.UUID) error {
|
func (e *ItemsRepository) DeleteByGroup(ctx context.Context, gid, id uuid.UUID) error {
|
||||||
|
@ -569,11 +549,12 @@ func (e *ItemsRepository) DeleteByGroup(ctx context.Context, gid, id uuid.UUID)
|
||||||
item.ID(id),
|
item.ID(id),
|
||||||
item.HasGroupWith(group.ID(gid)),
|
item.HasGroupWith(group.ID(gid)),
|
||||||
).Exec(ctx)
|
).Exec(ctx)
|
||||||
if err != nil {
|
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
e.publishMutationEvent(gid)
|
e.publishMutationEvent(gid)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,7 +670,7 @@ func (e *ItemsRepository) UpdateByGroup(ctx context.Context, GID uuid.UUID, data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
e.publishMutationEvent(GID)
|
e.publishMutationEvent(GID)
|
||||||
return e.GetOne(ctx, data.ID)
|
return e.GetOne(ctx, data.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,7 +709,7 @@ func (e *ItemsRepository) Patch(ctx context.Context, GID, ID uuid.UUID, data Ite
|
||||||
q.SetQuantity(*data.Quantity)
|
q.SetQuantity(*data.Quantity)
|
||||||
}
|
}
|
||||||
|
|
||||||
e.publishMutationEvent(GID)
|
e.publishMutationEvent(GID)
|
||||||
return q.Exec(ctx)
|
return q.Exec(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,51 +822,3 @@ func (e *ItemsRepository) ZeroOutTimeFields(ctx context.Context, GID uuid.UUID)
|
||||||
|
|
||||||
return updated, nil
|
return updated, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ItemsRepository) SetPrimaryPhotos(ctx context.Context, GID uuid.UUID) (int, error) {
|
|
||||||
// All items where there is no primary photo
|
|
||||||
itemIDs, err := e.db.Item.Query().
|
|
||||||
Where(
|
|
||||||
item.HasGroupWith(group.ID(GID)),
|
|
||||||
item.HasAttachmentsWith(
|
|
||||||
attachment.Not(
|
|
||||||
attachment.And(
|
|
||||||
attachment.Primary(true),
|
|
||||||
attachment.TypeEQ(attachment.TypePhoto),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
).
|
|
||||||
IDs(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return -1, err
|
|
||||||
}
|
|
||||||
|
|
||||||
updated := 0
|
|
||||||
for _, id := range itemIDs {
|
|
||||||
// Find the first photo attachment
|
|
||||||
a, err := e.db.Attachment.Query().
|
|
||||||
Where(
|
|
||||||
attachment.HasItemWith(item.ID(id)),
|
|
||||||
attachment.TypeEQ(attachment.TypePhoto),
|
|
||||||
attachment.Primary(false),
|
|
||||||
).
|
|
||||||
First(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return updated, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set it as primary
|
|
||||||
_, err = e.db.Attachment.UpdateOne(a).
|
|
||||||
SetPrimary(true).
|
|
||||||
Save(ctx)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return updated, err
|
|
||||||
}
|
|
||||||
|
|
||||||
updated++
|
|
||||||
}
|
|
||||||
|
|
||||||
return updated, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
"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/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/label"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||||
)
|
)
|
||||||
|
@ -41,6 +42,7 @@ type (
|
||||||
|
|
||||||
LabelOut struct {
|
LabelOut struct {
|
||||||
LabelSummary
|
LabelSummary
|
||||||
|
Items []ItemSummary `json:"items"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -62,6 +64,7 @@ var (
|
||||||
func mapLabelOut(label *ent.Label) LabelOut {
|
func mapLabelOut(label *ent.Label) LabelOut {
|
||||||
return LabelOut{
|
return LabelOut{
|
||||||
LabelSummary: mapLabelSummary(label),
|
LabelSummary: mapLabelSummary(label),
|
||||||
|
Items: mapEach(label.Edges.Items, mapItemSummary),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +78,9 @@ func (r *LabelRepository) getOne(ctx context.Context, where ...predicate.Label)
|
||||||
return mapLabelOutErr(r.db.Label.Query().
|
return mapLabelOutErr(r.db.Label.Query().
|
||||||
Where(where...).
|
Where(where...).
|
||||||
WithGroup().
|
WithGroup().
|
||||||
|
WithItems(func(iq *ent.ItemQuery) {
|
||||||
|
iq.Where(item.Archived(false))
|
||||||
|
}).
|
||||||
Only(ctx),
|
Only(ctx),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -136,7 +142,7 @@ func (r *LabelRepository) UpdateByGroup(ctx context.Context, GID uuid.UUID, data
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete removes the label from the database. This should only be used when
|
// delete removes the label from the database. This should only be used when
|
||||||
// the label's ownership is already confirmed/validated.
|
// the label's ownership is already confirmed/validated.
|
||||||
func (r *LabelRepository) delete(ctx context.Context, id uuid.UUID) error {
|
func (r *LabelRepository) delete(ctx context.Context, id uuid.UUID) error {
|
||||||
return r.db.Label.DeleteOneID(id).Exec(ctx)
|
return r.db.Label.DeleteOneID(id).Exec(ctx)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
"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/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/location"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
"github.com/hay-kot/homebox/backend/internal/data/ent/predicate"
|
||||||
)
|
)
|
||||||
|
@ -48,6 +49,7 @@ type (
|
||||||
LocationOut struct {
|
LocationOut struct {
|
||||||
Parent *LocationSummary `json:"parent,omitempty"`
|
Parent *LocationSummary `json:"parent,omitempty"`
|
||||||
LocationSummary
|
LocationSummary
|
||||||
|
Items []ItemSummary `json:"items"`
|
||||||
Children []LocationSummary `json:"children"`
|
Children []LocationSummary `json:"children"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -86,6 +88,7 @@ func mapLocationOut(location *ent.Location) LocationOut {
|
||||||
CreatedAt: location.CreatedAt,
|
CreatedAt: location.CreatedAt,
|
||||||
UpdatedAt: location.UpdatedAt,
|
UpdatedAt: location.UpdatedAt,
|
||||||
},
|
},
|
||||||
|
Items: mapEach(location.Edges.Items, mapItemSummary),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +164,11 @@ func (r *LocationRepository) getOne(ctx context.Context, where ...predicate.Loca
|
||||||
return mapLocationOutErr(r.db.Location.Query().
|
return mapLocationOutErr(r.db.Location.Query().
|
||||||
Where(where...).
|
Where(where...).
|
||||||
WithGroup().
|
WithGroup().
|
||||||
|
WithItems(func(iq *ent.ItemQuery) {
|
||||||
|
iq.Where(item.Archived(false)).
|
||||||
|
Order(ent.Asc(item.FieldName)).
|
||||||
|
WithLabel()
|
||||||
|
}).
|
||||||
WithParent().
|
WithParent().
|
||||||
WithChildren().
|
WithChildren().
|
||||||
Only(ctx))
|
Only(ctx))
|
||||||
|
|
|
@ -60,31 +60,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/v1/actions/set-primary-photos": {
|
|
||||||
"post": {
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"Bearer": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "Sets the first photo of each item as the primary photo",
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Actions"
|
|
||||||
],
|
|
||||||
"summary": "Set Primary Photos",
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/v1.ActionAmountResult"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/v1/actions/zero-item-time-fields": {
|
"/v1/actions/zero-item-time-fields": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
@ -1896,9 +1871,6 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"primary": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -1910,9 +1882,6 @@
|
||||||
"repo.ItemAttachmentUpdate": {
|
"repo.ItemAttachmentUpdate": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"primary": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -2012,9 +1981,6 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"imageId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"insured": {
|
"insured": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -2122,9 +2088,6 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"imageId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"insured": {
|
"insured": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -2284,6 +2247,12 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.ItemSummary"
|
||||||
|
}
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -2345,6 +2314,12 @@
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"items": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/repo.ItemSummary"
|
||||||
|
}
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,7 +7,7 @@ Great for testing out the application, but not recommended for stable use. Check
|
||||||
For each image there are two tags, respectively the regular tag and $TAG-rootless, which uses a non-root image.
|
For each image there are two tags, respectively the regular tag and $TAG-rootless, which uses a non-root image.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# If using the rootless image, ensure data
|
# If using the rootless image, ensure data
|
||||||
# folder has correct permissions
|
# folder has correct permissions
|
||||||
$ mkdir -p /path/to/data/folder
|
$ mkdir -p /path/to/data/folder
|
||||||
$ chown 65532:65532 -R /path/to/data/folder
|
$ chown 65532:65532 -R /path/to/data/folder
|
||||||
|
@ -21,7 +21,7 @@ $ docker run -d \
|
||||||
--volume /path/to/data/folder/:/data \
|
--volume /path/to/data/folder/:/data \
|
||||||
ghcr.io/hay-kot/homebox:latest
|
ghcr.io/hay-kot/homebox:latest
|
||||||
# ghcr.io/hay-kot/homebox:latest-rootless
|
# ghcr.io/hay-kot/homebox:latest-rootless
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Docker-Compose
|
## Docker-Compose
|
||||||
|
@ -63,7 +63,7 @@ volumes:
|
||||||
| HBOX_OPTIONS_AUTO_INCREMENT_ASSET_ID | true | auto increments the asset_id field for new items |
|
| HBOX_OPTIONS_AUTO_INCREMENT_ASSET_ID | true | auto increments the asset_id field for new items |
|
||||||
| HBOX_WEB_MAX_UPLOAD_SIZE | 10 | maximum file upload size supported in MB |
|
| 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_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, if you're using docker do not change this |
|
| HBOX_STORAGE_SQLITE_URL | /data/homebox.db?_fk=1 | sqlite database url, in you're using docker do not change this |
|
||||||
| HBOX_LOG_LEVEL | info | log level to use, can be one of: trace, debug, info, warn, error, critical |
|
| HBOX_LOG_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_LOG_FORMAT | text | log format to use, can be one of: text, json |
|
||||||
| HBOX_MAILER_HOST | | email host to use, if not set no email provider will be used |
|
| HBOX_MAILER_HOST | | email host to use, if not set no email provider will be used |
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
mkdocs-material==9.4.4
|
mkdocs-material==9.1.21
|
|
@ -10,14 +10,6 @@
|
||||||
class="w-full input input-bordered"
|
class="w-full input input-bordered"
|
||||||
@change="search = $event.target.value"
|
@change="search = $event.target.value"
|
||||||
/>
|
/>
|
||||||
<button
|
|
||||||
v-if="!!value"
|
|
||||||
type="button"
|
|
||||||
class="absolute inset-y-0 right-6 flex items-center rounded-r-md px-2 focus:outline-none"
|
|
||||||
@click="clear"
|
|
||||||
>
|
|
||||||
<Icon name="mdi-close" class="w-5 h-5" />
|
|
||||||
</button>
|
|
||||||
<ComboboxButton class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
|
<ComboboxButton class="absolute inset-y-0 right-0 flex items-center rounded-r-md px-2 focus:outline-none">
|
||||||
<Icon name="mdi-chevron-down" class="w-5 h-5" />
|
<Icon name="mdi-chevron-down" class="w-5 h-5" />
|
||||||
</ComboboxButton>
|
</ComboboxButton>
|
||||||
|
@ -94,10 +86,6 @@
|
||||||
multiple: false,
|
multiple: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
function clear() {
|
|
||||||
emit("update:modelValue", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
const search = ref("");
|
const search = ref("");
|
||||||
const value = useVModel(props, "modelValue", emit);
|
const value = useVModel(props, "modelValue", emit);
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
<template>
|
<template>
|
||||||
<NuxtLink class="group card rounded-md border border-gray-300" :to="`/item/${item.id}`">
|
<NuxtLink class="group card rounded-md" :to="`/item/${item.id}`">
|
||||||
<div class="relative h-[200px]">
|
<div class="rounded-t flex flex-col justify-center bg-neutral text-neutral-content p-5">
|
||||||
<img v-if="imageUrl" class="h-[200px] w-full object-cover rounded-t shadow-sm border-gray-300" :src="imageUrl" />
|
<h2 class="text-lg mb-1 last:mb-0 font-bold two-line">{{ item.name }}</h2>
|
||||||
<div class="absolute bottom-1 left-1">
|
<div>
|
||||||
<NuxtLink
|
<NuxtLink v-if="item.location" class="text-sm hover:link" :to="`/location/${item.location.id}`">
|
||||||
v-if="item.location"
|
|
||||||
class="text-sm hover:link badge shadow-md rounded-md"
|
|
||||||
:to="`/location/${item.location.id}`"
|
|
||||||
>
|
|
||||||
{{ item.location.name }}
|
{{ item.location.name }}
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
|
<span class="flex-1"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="rounded-b p-4 pt-2 flex-grow col-span-4 flex flex-col gap-y-1 bg-base-100">
|
<div class="rounded-b p-4 pt-2 flex-grow col-span-4 flex flex-col gap-y-2 bg-base-100">
|
||||||
<h2 class="text-lg font-bold two-line">{{ item.name }}</h2>
|
|
||||||
<div class="divider my-0"></div>
|
|
||||||
<div class="flex justify-between gap-2">
|
<div class="flex justify-between gap-2">
|
||||||
|
<div class="mr-auto tooltip tooltip-tip" data-tip="Purchase Price">
|
||||||
|
<span v-if="item.purchasePrice != '0'" class="badge badge-sm badge-ghost h-5">
|
||||||
|
<Currency :amount="item.purchasePrice" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div v-if="item.insured" class="tooltip z-10" data-tip="Insured">
|
<div v-if="item.insured" class="tooltip z-10" data-tip="Insured">
|
||||||
<Icon class="h-5 w-5 text-primary" name="mdi-shield-check" />
|
<Icon class="h-5 w-5 text-primary" name="mdi-shield-check" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,6 +26,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Markdown class="mb-2 text-clip three-line" :source="item.description" />
|
<Markdown class="mb-2 text-clip three-line" :source="item.description" />
|
||||||
|
|
||||||
<div class="flex gap-2 flex-wrap -mr-1 mt-auto justify-end">
|
<div class="flex gap-2 flex-wrap -mr-1 mt-auto justify-end">
|
||||||
<LabelChip v-for="label in top3" :key="label.id" :label="label" size="sm" />
|
<LabelChip v-for="label in top3" :key="label.id" :label="label" size="sm" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,16 +37,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ItemOut, ItemSummary } from "~~/lib/api/types/data-contracts";
|
import { ItemOut, ItemSummary } from "~~/lib/api/types/data-contracts";
|
||||||
|
|
||||||
const api = useUserApi();
|
|
||||||
|
|
||||||
const imageUrl = computed(() => {
|
|
||||||
if (!props.item.imageId) {
|
|
||||||
return "/no-image.jpg";
|
|
||||||
}
|
|
||||||
|
|
||||||
return api.authURL(`/items/${props.item.id}/attachments/${props.item.imageId}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
const top3 = computed(() => {
|
const top3 = computed(() => {
|
||||||
return props.item.labels.slice(0, 3) || [];
|
return props.item.labels.slice(0, 3) || [];
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<label tabindex="0" class="btn rounded-l-none rounded-r-xl">
|
<label tabindex="0" class="btn rounded-l-none rounded-r-xl">
|
||||||
<Icon class="h-5 w-5" name="mdi-chevron-down" />
|
<Icon class="h-5 w-5" name="mdi-chevron-down" />
|
||||||
</label>
|
</label>
|
||||||
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-64 right-0">
|
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-64">
|
||||||
<li>
|
<li>
|
||||||
<button type="button" @click="create(false)">Create and Add Another</button>
|
<button type="button" @click="create(false)">Create and Add Another</button>
|
||||||
</li>
|
</li>
|
||||||
|
@ -122,7 +122,6 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const { error, data } = await api.items.create(out);
|
const { error, data } = await api.items.create(out);
|
||||||
loading.value = false;
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error("Couldn't create item");
|
toast.error("Couldn't create item");
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<label tabindex="0" class="btn rounded-l-none rounded-r-xl">
|
<label tabindex="0" class="btn rounded-l-none rounded-r-xl">
|
||||||
<Icon class="h-5 w-5" name="mdi-chevron-down" />
|
<Icon class="h-5 w-5" name="mdi-chevron-down" />
|
||||||
</label>
|
</label>
|
||||||
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-64 right-0">
|
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-64">
|
||||||
<li>
|
<li>
|
||||||
<button type="button" @click="create(false)">Create and Add Another</button>
|
<button type="button" @click="create(false)">Create and Add Another</button>
|
||||||
</li>
|
</li>
|
||||||
|
@ -77,7 +77,6 @@
|
||||||
const { error, data } = await api.labels.create(form);
|
const { error, data } = await api.labels.create(form);
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error("Couldn't create label");
|
toast.error("Couldn't create label");
|
||||||
loading.value = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<label tabindex="0" class="btn rounded-l-none rounded-r-xl">
|
<label tabindex="0" class="btn rounded-l-none rounded-r-xl">
|
||||||
<Icon class="h-5 w-5" name="mdi-chevron-down" />
|
<Icon class="h-5 w-5" name="mdi-chevron-down" />
|
||||||
</label>
|
</label>
|
||||||
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-64 right-0">
|
<ul tabindex="0" class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-64">
|
||||||
<li>
|
<li>
|
||||||
<button type="button" @click="create(false)">Create and Add Another</button>
|
<button type="button" @click="create(false)">Create and Add Another</button>
|
||||||
</li>
|
</li>
|
||||||
|
@ -85,7 +85,6 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
loading.value = false;
|
|
||||||
toast.error("Couldn't create location");
|
toast.error("Couldn't create location");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,12 +33,7 @@
|
||||||
v-if="detail.copyable"
|
v-if="detail.copyable"
|
||||||
class="opacity-0 group-hover:opacity-100 ml-4 my-0 duration-75 transition-opacity"
|
class="opacity-0 group-hover:opacity-100 ml-4 my-0 duration-75 transition-opacity"
|
||||||
>
|
>
|
||||||
<CopyText
|
<CopyText :text="detail.text.toString()" :icon-size="16" class="btn btn-xs btn-ghost btn-circle" />
|
||||||
v-if="detail.text.toString()"
|
|
||||||
:text="detail.text.toString()"
|
|
||||||
:icon-size="16"
|
|
||||||
class="btn btn-xs btn-ghost btn-circle"
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -30,15 +30,12 @@ export function usePublicApi(): PublicApi {
|
||||||
export function useUserApi(): UserClient {
|
export function useUserApi(): UserClient {
|
||||||
const authCtx = useAuthContext();
|
const authCtx = useAuthContext();
|
||||||
|
|
||||||
const requests = new Requests("", "", {});
|
const requests = new Requests("", () => authCtx.token || "", {});
|
||||||
requests.addResponseInterceptor(logger);
|
requests.addResponseInterceptor(logger);
|
||||||
requests.addResponseInterceptor(r => {
|
requests.addResponseInterceptor(r => {
|
||||||
if (r.status === 401) {
|
if (r.status === 401) {
|
||||||
console.error("unauthorized request, invalidating session");
|
console.error("unauthorized request, invalidating session");
|
||||||
authCtx.invalidateSession();
|
authCtx.invalidateSession();
|
||||||
if (window.location.pathname !== "/") {
|
|
||||||
window.location.href = "/";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ import { UserOut } from "~~/lib/api/types/data-contracts";
|
||||||
import { UserClient } from "~~/lib/api/user";
|
import { UserClient } from "~~/lib/api/user";
|
||||||
|
|
||||||
export interface IAuthContext {
|
export interface IAuthContext {
|
||||||
get token(): boolean | null;
|
get token(): string | null;
|
||||||
|
get expiresAt(): string | null;
|
||||||
get attachmentToken(): string | null;
|
get attachmentToken(): string | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,6 +13,11 @@ export interface IAuthContext {
|
||||||
*/
|
*/
|
||||||
user?: UserOut;
|
user?: UserOut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the session is expired.
|
||||||
|
*/
|
||||||
|
isExpired(): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the session is authorized.
|
* Returns true if the session is authorized.
|
||||||
*/
|
*/
|
||||||
|
@ -37,41 +43,59 @@ class AuthContext implements IAuthContext {
|
||||||
// eslint-disable-next-line no-use-before-define
|
// eslint-disable-next-line no-use-before-define
|
||||||
private static _instance?: AuthContext;
|
private static _instance?: AuthContext;
|
||||||
|
|
||||||
private static readonly cookieTokenKey = "hb.auth.session";
|
private static readonly cookieTokenKey = "hb.auth.token";
|
||||||
|
private static readonly cookieExpiresAtKey = "hb.auth.expires_at";
|
||||||
private static readonly cookieAttachmentTokenKey = "hb.auth.attachment_token";
|
private static readonly cookieAttachmentTokenKey = "hb.auth.attachment_token";
|
||||||
|
|
||||||
user?: UserOut;
|
user?: UserOut;
|
||||||
private _token: CookieRef<string | null>;
|
private _token: CookieRef<string | null>;
|
||||||
|
private _expiresAt: CookieRef<string | null>;
|
||||||
private _attachmentToken: CookieRef<string | null>;
|
private _attachmentToken: CookieRef<string | null>;
|
||||||
|
|
||||||
get token() {
|
get token() {
|
||||||
// @ts-ignore sometimes it's a boolean I guess?
|
return this._token.value;
|
||||||
return this._token.value === "true" || this._token.value === true;
|
}
|
||||||
|
|
||||||
|
get expiresAt() {
|
||||||
|
return this._expiresAt.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
get attachmentToken() {
|
get attachmentToken() {
|
||||||
return this._attachmentToken.value;
|
return this._attachmentToken.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private constructor(token: string, attachmentToken: string) {
|
private constructor(token: string, expiresAt: string, attachmentToken: string) {
|
||||||
this._token = useCookie(token);
|
this._token = useCookie(token);
|
||||||
|
this._expiresAt = useCookie(expiresAt);
|
||||||
this._attachmentToken = useCookie(attachmentToken);
|
this._attachmentToken = useCookie(attachmentToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get instance() {
|
static get instance() {
|
||||||
if (!this._instance) {
|
if (!this._instance) {
|
||||||
this._instance = new AuthContext(AuthContext.cookieTokenKey, AuthContext.cookieAttachmentTokenKey);
|
this._instance = new AuthContext(
|
||||||
|
AuthContext.cookieTokenKey,
|
||||||
|
AuthContext.cookieExpiresAtKey,
|
||||||
|
AuthContext.cookieAttachmentTokenKey
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._instance;
|
return this._instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
isExpired() {
|
isExpired() {
|
||||||
return !this.token;
|
const expiresAt = this.expiresAt;
|
||||||
|
if (expiresAt === null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const expiresAtDate = new Date(expiresAt);
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
return now.getTime() > expiresAtDate.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
isAuthorized() {
|
isAuthorized() {
|
||||||
return this.token;
|
return !!this._token.value && !this.isExpired();
|
||||||
}
|
}
|
||||||
|
|
||||||
invalidateSession() {
|
invalidateSession() {
|
||||||
|
@ -79,8 +103,11 @@ class AuthContext implements IAuthContext {
|
||||||
|
|
||||||
// Delete the cookies
|
// Delete the cookies
|
||||||
this._token.value = null;
|
this._token.value = null;
|
||||||
|
this._expiresAt.value = null;
|
||||||
this._attachmentToken.value = null;
|
this._attachmentToken.value = null;
|
||||||
|
|
||||||
console.log("Session invalidated");
|
console.log("Session invalidated");
|
||||||
|
window.location.href = "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(api: PublicApi, email: string, password: string, stayLoggedIn: boolean) {
|
async login(api: PublicApi, email: string, password: string, stayLoggedIn: boolean) {
|
||||||
|
@ -88,10 +115,17 @@ class AuthContext implements IAuthContext {
|
||||||
|
|
||||||
if (!r.error) {
|
if (!r.error) {
|
||||||
const expiresAt = new Date(r.data.expiresAt);
|
const expiresAt = new Date(r.data.expiresAt);
|
||||||
this._token = useCookie(AuthContext.cookieTokenKey);
|
this._token = useCookie(AuthContext.cookieTokenKey, {
|
||||||
|
expires: expiresAt,
|
||||||
|
});
|
||||||
|
this._expiresAt = useCookie(AuthContext.cookieExpiresAtKey, {
|
||||||
|
expires: expiresAt,
|
||||||
|
});
|
||||||
this._attachmentToken = useCookie(AuthContext.cookieAttachmentTokenKey, {
|
this._attachmentToken = useCookie(AuthContext.cookieAttachmentTokenKey, {
|
||||||
expires: expiresAt,
|
expires: expiresAt,
|
||||||
});
|
});
|
||||||
|
this._token.value = r.data.token;
|
||||||
|
this._expiresAt.value = r.data.expiresAt as string;
|
||||||
this._attachmentToken.value = r.data.attachmentToken;
|
this._attachmentToken.value = r.data.attachmentToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,6 +199,5 @@
|
||||||
|
|
||||||
async function logout() {
|
async function logout() {
|
||||||
await authCtx.logout(api);
|
await authCtx.logout(api);
|
||||||
navigateTo("/");
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -19,10 +19,4 @@ export class ActionsAPI extends BaseAPI {
|
||||||
url: route("/actions/ensure-import-refs"),
|
url: route("/actions/ensure-import-refs"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setPrimaryPhotos() {
|
|
||||||
return this.http.post<void, ActionAmountResult>({
|
|
||||||
url: route("/actions/set-primary-photos"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,13 +42,11 @@ export interface ItemAttachment {
|
||||||
createdAt: Date | string;
|
createdAt: Date | string;
|
||||||
document: DocumentOut;
|
document: DocumentOut;
|
||||||
id: string;
|
id: string;
|
||||||
primary: boolean;
|
|
||||||
type: string;
|
type: string;
|
||||||
updatedAt: Date | string;
|
updatedAt: Date | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ItemAttachmentUpdate {
|
export interface ItemAttachmentUpdate {
|
||||||
primary: boolean;
|
|
||||||
title: string;
|
title: string;
|
||||||
type: string;
|
type: string;
|
||||||
}
|
}
|
||||||
|
@ -86,7 +84,6 @@ export interface ItemOut {
|
||||||
description: string;
|
description: string;
|
||||||
fields: ItemField[];
|
fields: ItemField[];
|
||||||
id: string;
|
id: string;
|
||||||
imageId: string;
|
|
||||||
insured: boolean;
|
insured: boolean;
|
||||||
labels: LabelSummary[];
|
labels: LabelSummary[];
|
||||||
/** Warranty */
|
/** Warranty */
|
||||||
|
@ -127,7 +124,6 @@ export interface ItemSummary {
|
||||||
createdAt: Date | string;
|
createdAt: Date | string;
|
||||||
description: string;
|
description: string;
|
||||||
id: string;
|
id: string;
|
||||||
imageId: string;
|
|
||||||
insured: boolean;
|
insured: boolean;
|
||||||
labels: LabelSummary[];
|
labels: LabelSummary[];
|
||||||
/** Edges */
|
/** Edges */
|
||||||
|
@ -191,6 +187,7 @@ export interface LabelOut {
|
||||||
createdAt: Date | string;
|
createdAt: Date | string;
|
||||||
description: string;
|
description: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
items: ItemSummary[];
|
||||||
name: string;
|
name: string;
|
||||||
updatedAt: Date | string;
|
updatedAt: Date | string;
|
||||||
}
|
}
|
||||||
|
@ -214,6 +211,7 @@ export interface LocationOut {
|
||||||
createdAt: Date | string;
|
createdAt: Date | string;
|
||||||
description: string;
|
description: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
items: ItemSummary[];
|
||||||
name: string;
|
name: string;
|
||||||
parent: LocationSummary;
|
parent: LocationSummary;
|
||||||
updatedAt: Date | string;
|
updatedAt: Date | string;
|
||||||
|
|
|
@ -27,8 +27,6 @@ export type Codes =
|
||||||
| "THB"
|
| "THB"
|
||||||
| "TRY"
|
| "TRY"
|
||||||
| "USD"
|
| "USD"
|
||||||
| "XAG"
|
|
||||||
| "XAU"
|
|
||||||
| "ZAR";
|
| "ZAR";
|
||||||
|
|
||||||
export type Currency = {
|
export type Currency = {
|
||||||
|
@ -67,7 +65,5 @@ export const currencies: Currency[] = [
|
||||||
{ code: "THB", local: "Thailand", symbol: "฿", name: "Thai Baht" },
|
{ code: "THB", local: "Thailand", symbol: "฿", name: "Thai Baht" },
|
||||||
{ code: "TRY", local: "Turkey", symbol: "₺", name: "Turkish Lira" },
|
{ code: "TRY", local: "Turkey", symbol: "₺", name: "Turkish Lira" },
|
||||||
{ code: "USD", local: "United States", symbol: "$", name: "United States Dollar" },
|
{ code: "USD", local: "United States", symbol: "$", name: "United States Dollar" },
|
||||||
{ code: "XAG", local: "Global", symbol: "XAG", name: "Silver Troy Ounce" },
|
|
||||||
{ code: "XAU", local: "Global", symbol: "XAU", name: "Gold Troy Ounce" },
|
|
||||||
{ code: "ZAR", local: "South Africa", symbol: "R", name: "South African Rand" },
|
{ code: "ZAR", local: "South Africa", symbol: "R", name: "South African Rand" },
|
||||||
];
|
];
|
||||||
|
|
|
@ -3,18 +3,13 @@ export default defineNuxtRouteMiddleware(async () => {
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
|
|
||||||
if (!ctx.isAuthorized()) {
|
if (!ctx.isAuthorized()) {
|
||||||
if (window.location.pathname !== "/") {
|
return navigateTo("/");
|
||||||
return navigateTo("/");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx.user) {
|
if (!ctx.user) {
|
||||||
console.log("Fetching user data");
|
|
||||||
const { data, error } = await api.user.self();
|
const { data, error } = await api.user.self();
|
||||||
if (error) {
|
if (error) {
|
||||||
if (window.location.pathname !== "/") {
|
return navigateTo("/");
|
||||||
return navigateTo("/");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.user = data.item;
|
ctx.user = data.item;
|
||||||
|
|
|
@ -2,13 +2,8 @@
|
||||||
import { IncomingMessage } from "http";
|
import { IncomingMessage } from "http";
|
||||||
import internal from "stream";
|
import internal from "stream";
|
||||||
import { defineNuxtModule, logger } from "@nuxt/kit";
|
import { defineNuxtModule, logger } from "@nuxt/kit";
|
||||||
// Related To
|
// eslint-disable-next-line
|
||||||
// - https://github.com/nuxt/nuxt/issues/15417
|
import { createProxyServer } from "http-proxy";
|
||||||
// - https://github.com/nuxt/cli/issues/107
|
|
||||||
//
|
|
||||||
// fix from
|
|
||||||
// - https://gist.github.com/ucw/67f7291c64777fb24341e8eae72bcd24
|
|
||||||
import { createProxyServer } from "http-proxy"; // eslint-disable-line import/named
|
|
||||||
|
|
||||||
export default defineNuxtModule({
|
export default defineNuxtModule({
|
||||||
defaults: {
|
defaults: {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
"@typescript-eslint/parser": "^6.0.0",
|
"@typescript-eslint/parser": "^6.0.0",
|
||||||
"@vite-pwa/nuxt": "^0.1.0",
|
"@vite-pwa/nuxt": "^0.1.0",
|
||||||
"eslint": "^8.23.0",
|
"eslint": "^8.23.0",
|
||||||
"eslint-config-prettier": "^9.0.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-prettier": "^4.2.1",
|
"eslint-plugin-prettier": "^4.2.1",
|
||||||
"eslint-plugin-vue": "^9.4.0",
|
"eslint-plugin-vue": "^9.4.0",
|
||||||
"h3": "^1.7.1",
|
"h3": "^1.7.1",
|
||||||
|
|
|
@ -5,17 +5,12 @@
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: "empty",
|
layout: "empty",
|
||||||
middleware: [
|
|
||||||
() => {
|
|
||||||
const ctx = useAuthContext();
|
|
||||||
if (ctx.isAuthorized()) {
|
|
||||||
return "/home";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const ctx = useAuthContext();
|
const ctx = useAuthContext();
|
||||||
|
if (ctx.isAuthorized()) {
|
||||||
|
navigateTo("/home");
|
||||||
|
}
|
||||||
|
|
||||||
const api = usePublicApi();
|
const api = usePublicApi();
|
||||||
const toast = useNotifier();
|
const toast = useNotifier();
|
||||||
|
|
|
@ -307,7 +307,6 @@
|
||||||
id: "",
|
id: "",
|
||||||
title: "",
|
title: "",
|
||||||
type: "",
|
type: "",
|
||||||
primary: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const attachmentOpts = Object.entries(AttachmentTypes).map(([key, value]) => ({
|
const attachmentOpts = Object.entries(AttachmentTypes).map(([key, value]) => ({
|
||||||
|
@ -319,7 +318,6 @@
|
||||||
editState.id = attachment.id;
|
editState.id = attachment.id;
|
||||||
editState.title = attachment.document.title;
|
editState.title = attachment.document.title;
|
||||||
editState.type = attachment.type;
|
editState.type = attachment.type;
|
||||||
editState.primary = attachment.primary;
|
|
||||||
editState.modal = true;
|
editState.modal = true;
|
||||||
|
|
||||||
editState.obj = attachmentOpts.find(o => o.value === attachment.type) || attachmentOpts[0];
|
editState.obj = attachmentOpts.find(o => o.value === attachment.type) || attachmentOpts[0];
|
||||||
|
@ -330,7 +328,6 @@
|
||||||
const { error, data } = await api.items.attachments.update(itemId.value, editState.id, {
|
const { error, data } = await api.items.attachments.update(itemId.value, editState.id, {
|
||||||
title: editState.title,
|
title: editState.title,
|
||||||
type: editState.type,
|
type: editState.type,
|
||||||
primary: editState.primary,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -410,6 +407,7 @@
|
||||||
<template #title> Attachment Edit </template>
|
<template #title> Attachment Edit </template>
|
||||||
|
|
||||||
<FormTextField v-model="editState.title" label="Attachment Title" />
|
<FormTextField v-model="editState.title" label="Attachment Title" />
|
||||||
|
{{ editState.type }}
|
||||||
<FormSelect
|
<FormSelect
|
||||||
v-model:value="editState.type"
|
v-model:value="editState.type"
|
||||||
label="Attachment Type"
|
label="Attachment Type"
|
||||||
|
@ -417,14 +415,6 @@
|
||||||
name="text"
|
name="text"
|
||||||
:items="attachmentOpts"
|
:items="attachmentOpts"
|
||||||
/>
|
/>
|
||||||
<div v-if="editState.type == 'photo'" class="flex gap-2 mt-3">
|
|
||||||
<input v-model="editState.primary" type="checkbox" class="checkbox" />
|
|
||||||
<p class="text-sm">
|
|
||||||
<span class="font-semibold">Primary Photo</span>
|
|
||||||
This options is only available for photos. Only one photo can be primary. If you select this option, the
|
|
||||||
current primary photo, if any will be unselected.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-action">
|
<div class="modal-action">
|
||||||
<BaseButton :loading="editState.loading" @click="updateAttachment"> Update </BaseButton>
|
<BaseButton :loading="editState.loading" @click="updateAttachment"> Update </BaseButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -59,7 +59,6 @@
|
||||||
const { error, data } = await api.labels.update(labelId.value, updateData);
|
const { error, data } = await api.labels.update(labelId.value, updateData);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
updating.value = false;
|
|
||||||
toast.error("Failed to update label");
|
toast.error("Failed to update label");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -69,23 +68,6 @@
|
||||||
updateModal.value = false;
|
updateModal.value = false;
|
||||||
updating.value = false;
|
updating.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const items = computedAsync(async () => {
|
|
||||||
if (!label.value) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const resp = await api.items.getAll({
|
|
||||||
labels: [label.value.id],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (resp.error) {
|
|
||||||
toast.error("Failed to load items");
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp.data.items;
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -101,47 +83,51 @@
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
|
|
||||||
<BaseContainer v-if="label">
|
<BaseContainer v-if="label" class="space-y-6 mb-16">
|
||||||
<div class="bg-white rounded p-3">
|
<section>
|
||||||
<header class="mb-2">
|
<BaseSectionHeader v-if="label">
|
||||||
<div class="flex flex-wrap items-end gap-2">
|
<Icon name="mdi-package-variant" class="mr-2 -mt-1 text-base-content" />
|
||||||
<div class="avatar placeholder mb-auto">
|
<span class="text-base-content">
|
||||||
<div class="bg-neutral-focus text-neutral-content rounded-full w-12">
|
{{ label ? label.name : "" }}
|
||||||
<Icon name="mdi-package-variant" class="h-7 w-7" />
|
</span>
|
||||||
</div>
|
|
||||||
</div>
|
<template #description>
|
||||||
<div>
|
<Markdown class="text-lg" :source="label.description"> </Markdown>
|
||||||
<h1 class="text-2xl pb-1">
|
</template>
|
||||||
{{ label ? label.name : "" }}
|
</BaseSectionHeader>
|
||||||
</h1>
|
|
||||||
<div class="flex gap-1 flex-wrap text-xs">
|
<div class="flex gap-3 flex-wrap mb-6 text-sm italic">
|
||||||
<div>
|
<div>
|
||||||
Created
|
Created
|
||||||
<DateTime :date="label?.createdAt" />
|
<DateTime :date="label?.createdAt" />
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ml-auto mt-2 flex flex-wrap items-center justify-between gap-3">
|
|
||||||
<div class="btn-group">
|
|
||||||
<PageQRCode class="dropdown-left" />
|
|
||||||
<BaseButton size="sm" @click="openUpdate">
|
|
||||||
<Icon class="mr-1" name="mdi-pencil" />
|
|
||||||
Edit
|
|
||||||
</BaseButton>
|
|
||||||
</div>
|
|
||||||
<BaseButton class="btn btn-sm" @click="confirmDelete()">
|
|
||||||
<Icon name="mdi-delete" class="mr-2" />
|
|
||||||
Delete
|
|
||||||
</BaseButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
<div>
|
||||||
<div class="divider my-0 mb-1"></div>
|
<Icon name="mdi-circle-small" />
|
||||||
<Markdown v-if="label && label.description" class="text-base" :source="label.description"> </Markdown>
|
</div>
|
||||||
</div>
|
<div>
|
||||||
<section v-if="label && items">
|
Last Updated
|
||||||
<ItemViewSelectable :items="items" />
|
<DateTime :date="label?.updatedAt" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap items-center justify-between mb-6 mt-3">
|
||||||
|
<div class="btn-group">
|
||||||
|
<PageQRCode class="dropdown-right" />
|
||||||
|
<BaseButton class="ml-auto" size="sm" @click="openUpdate">
|
||||||
|
<Icon class="mr-1" name="mdi-pencil" />
|
||||||
|
Edit
|
||||||
|
</BaseButton>
|
||||||
|
</div>
|
||||||
|
<BaseButton class="btn btn-sm" @click="confirmDelete()">
|
||||||
|
<Icon name="mdi-delete" class="mr-2" />
|
||||||
|
Delete
|
||||||
|
</BaseButton>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</BaseContainer>
|
</BaseContainer>
|
||||||
|
|
||||||
|
<section v-if="label && label.items">
|
||||||
|
<ItemViewSelectable :items="label.items" />
|
||||||
|
</section>
|
||||||
</BaseContainer>
|
</BaseContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -68,7 +68,6 @@
|
||||||
const { error, data } = await api.locations.update(locationId.value, updateData);
|
const { error, data } = await api.locations.update(locationId.value, updateData);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
updating.value = false;
|
|
||||||
toast.error("Failed to update location");
|
toast.error("Failed to update location");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -83,23 +82,6 @@
|
||||||
const locations = computed(() => locationStore.allLocations);
|
const locations = computed(() => locationStore.allLocations);
|
||||||
|
|
||||||
const parent = ref<LocationSummary | any>({});
|
const parent = ref<LocationSummary | any>({});
|
||||||
|
|
||||||
const items = computedAsync(async () => {
|
|
||||||
if (!location.value) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const resp = await api.items.getAll({
|
|
||||||
locations: [location.value.id],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (resp.error) {
|
|
||||||
toast.error("Failed to load items");
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp.data.items;
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -117,57 +99,61 @@
|
||||||
</form>
|
</form>
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
|
|
||||||
<BaseContainer v-if="location">
|
<BaseContainer v-if="location" class="space-y-6 mb-16">
|
||||||
<div class="bg-white rounded p-3">
|
<section>
|
||||||
<header class="mb-2">
|
<BaseSectionHeader v-if="location">
|
||||||
<div class="flex flex-wrap items-end gap-2">
|
<Icon name="mdi-package-variant" class="mr-2 -mt-1 text-base-content" />
|
||||||
<div class="avatar placeholder mb-auto">
|
<span class="text-base-content">
|
||||||
<div class="bg-neutral-focus text-neutral-content rounded-full w-12">
|
{{ location ? location.name : "" }}
|
||||||
<Icon name="mdi-package-variant" class="h-7 w-7" />
|
</span>
|
||||||
</div>
|
|
||||||
</div>
|
<div v-if="location?.parent" class="text-sm breadcrumbs pb-0">
|
||||||
<div>
|
<ul class="text-base-content/70">
|
||||||
<div v-if="location?.parent" class="text-sm breadcrumbs pt-0 pb-0">
|
<li>
|
||||||
<ul class="text-base-content/70">
|
<NuxtLink :to="`/location/${location.parent.id}`"> {{ location.parent.name }}</NuxtLink>
|
||||||
<li>
|
</li>
|
||||||
<NuxtLink :to="`/location/${location.parent.id}`"> {{ location.parent.name }}</NuxtLink>
|
<li>{{ location.name }}</li>
|
||||||
</li>
|
</ul>
|
||||||
<li>{{ location.name }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<h1 class="text-2xl pb-1">
|
|
||||||
{{ location ? location.name : "" }}
|
|
||||||
</h1>
|
|
||||||
<div class="flex gap-1 flex-wrap text-xs">
|
|
||||||
<div>
|
|
||||||
Created
|
|
||||||
<DateTime :date="location?.createdAt" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ml-auto mt-2 flex flex-wrap items-center justify-between gap-3">
|
|
||||||
<div class="btn-group">
|
|
||||||
<PageQRCode class="dropdown-left" />
|
|
||||||
<BaseButton size="sm" @click="openUpdate">
|
|
||||||
<Icon class="mr-1" name="mdi-pencil" />
|
|
||||||
Edit
|
|
||||||
</BaseButton>
|
|
||||||
</div>
|
|
||||||
<BaseButton class="btn btn-sm" @click="confirmDelete()">
|
|
||||||
<Icon name="mdi-delete" class="mr-2" />
|
|
||||||
Delete
|
|
||||||
</BaseButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
<template #description>
|
||||||
<div class="divider my-0 mb-1"></div>
|
<Markdown class="text-lg" :source="location.description"> </Markdown>
|
||||||
<Markdown v-if="location && location.description" class="text-base" :source="location.description"> </Markdown>
|
</template>
|
||||||
</div>
|
</BaseSectionHeader>
|
||||||
<section v-if="location && items">
|
|
||||||
<ItemViewSelectable :items="items" />
|
<div class="flex gap-3 flex-wrap mb-6 text-sm italic">
|
||||||
|
<div>
|
||||||
|
Created
|
||||||
|
<DateTime :date="location?.createdAt" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Icon name="mdi-circle-small" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Last Updated
|
||||||
|
<DateTime :date="location?.updatedAt" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap items-center justify-between mb-6 mt-3">
|
||||||
|
<div class="btn-group">
|
||||||
|
<PageQRCode class="dropdown-right" />
|
||||||
|
<BaseButton class="ml-auto" size="sm" @click="openUpdate">
|
||||||
|
<Icon class="mr-1" name="mdi-pencil" />
|
||||||
|
Edit
|
||||||
|
</BaseButton>
|
||||||
|
</div>
|
||||||
|
<BaseButton class="btn btn-sm" @click="confirmDelete()">
|
||||||
|
<Icon name="mdi-delete" class="mr-2" />
|
||||||
|
Delete
|
||||||
|
</BaseButton>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section v-if="location && location.children.length > 0" class="mt-6">
|
<template v-if="location && location.items.length > 0">
|
||||||
|
<ItemViewSelectable :items="location.items" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<section v-if="location && location.children.length > 0">
|
||||||
<BaseSectionHeader class="mb-5"> Child Locations </BaseSectionHeader>
|
<BaseSectionHeader class="mb-5"> Child Locations </BaseSectionHeader>
|
||||||
<div class="grid gap-2 grid-cols-1 sm:grid-cols-3">
|
<div class="grid gap-2 grid-cols-1 sm:grid-cols-3">
|
||||||
<LocationCard v-for="item in location.children" :key="item.id" :location="item" />
|
<LocationCard v-for="item in location.children" :key="item.id" :location="item" />
|
||||||
|
|
|
@ -82,12 +82,6 @@
|
||||||
See Github Issue #236 for more details.
|
See Github Issue #236 for more details.
|
||||||
</a>
|
</a>
|
||||||
</DetailAction>
|
</DetailAction>
|
||||||
<DetailAction @action="setPrimaryPhotos">
|
|
||||||
<template #title> Set Primary Photos </template>
|
|
||||||
In version v0.10.0 of Homebox, the primary image field was added to attachments of type photo. This action
|
|
||||||
will set the primary image field to the first image in the attachments array in the database, if it is not
|
|
||||||
already set. <a class="link" href="https://github.com/hay-kot/homebox/pull/576">See GitHub PR #576</a>
|
|
||||||
</DetailAction>
|
|
||||||
</div>
|
</div>
|
||||||
</BaseCard>
|
</BaseCard>
|
||||||
</BaseContainer>
|
</BaseContainer>
|
||||||
|
@ -179,25 +173,6 @@
|
||||||
|
|
||||||
notify.success(`${result.data.completed} assets have been updated.`);
|
notify.success(`${result.data.completed} assets have been updated.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setPrimaryPhotos() {
|
|
||||||
const { isCanceled } = await confirm.open(
|
|
||||||
"Are you sure you want to set primary photos? This can take a while and cannot be undone."
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isCanceled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await api.actions.setPrimaryPhotos();
|
|
||||||
|
|
||||||
if (result.error) {
|
|
||||||
notify.error("Failed to set primary photos.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
notify.success(`${result.data.completed} assets have been updated.`);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
|
@ -98,11 +98,11 @@ devDependencies:
|
||||||
specifier: ^8.23.0
|
specifier: ^8.23.0
|
||||||
version: 8.29.0
|
version: 8.29.0
|
||||||
eslint-config-prettier:
|
eslint-config-prettier:
|
||||||
specifier: ^9.0.0
|
specifier: ^8.5.0
|
||||||
version: 9.0.0(eslint@8.29.0)
|
version: 8.5.0(eslint@8.29.0)
|
||||||
eslint-plugin-prettier:
|
eslint-plugin-prettier:
|
||||||
specifier: ^4.2.1
|
specifier: ^4.2.1
|
||||||
version: 4.2.1(eslint-config-prettier@9.0.0)(eslint@8.29.0)(prettier@2.8.1)
|
version: 4.2.1(eslint-config-prettier@8.5.0)(eslint@8.29.0)(prettier@2.8.1)
|
||||||
eslint-plugin-vue:
|
eslint-plugin-vue:
|
||||||
specifier: ^9.4.0
|
specifier: ^9.4.0
|
||||||
version: 9.8.0(eslint@8.29.0)
|
version: 9.8.0(eslint@8.29.0)
|
||||||
|
@ -4557,8 +4557,8 @@ packages:
|
||||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
/eslint-config-prettier@9.0.0(eslint@8.29.0):
|
/eslint-config-prettier@8.5.0(eslint@8.29.0):
|
||||||
resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==}
|
resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=7.0.0'
|
eslint: '>=7.0.0'
|
||||||
|
@ -4784,7 +4784,7 @@ packages:
|
||||||
semver: 6.3.0
|
semver: 6.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/eslint-plugin-prettier@4.2.1(eslint-config-prettier@9.0.0)(eslint@8.29.0)(prettier@2.8.1):
|
/eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.5.0)(eslint@8.29.0)(prettier@2.8.1):
|
||||||
resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
|
resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -4796,7 +4796,7 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.29.0
|
eslint: 8.29.0
|
||||||
eslint-config-prettier: 9.0.0(eslint@8.29.0)
|
eslint-config-prettier: 8.5.0(eslint@8.29.0)
|
||||||
prettier: 2.8.1
|
prettier: 2.8.1
|
||||||
prettier-linter-helpers: 1.0.0
|
prettier-linter-helpers: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 89 KiB |
Loading…
Reference in a new issue