consolidate API code

This commit is contained in:
Hayden 2022-09-23 14:47:34 -08:00
parent 0899217c43
commit d67d96c6fe
8 changed files with 305 additions and 108 deletions

View file

@ -354,6 +354,50 @@ const docTemplate = `{
}
}
},
"put": {
"security": [
{
"Bearer": []
}
],
"tags": [
"Items"
],
"summary": "retrieves an attachment for an item",
"parameters": [
{
"type": "string",
"description": "Item ID",
"name": "id",
"in": "path",
"required": true
},
{
"type": "string",
"description": "Attachment ID",
"name": "attachment_id",
"in": "path",
"required": true
},
{
"description": "Attachment Update",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/types.ItemAttachmentUpdate"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/types.ItemOut"
}
}
}
},
"delete": {
"security": [
{
@ -1060,6 +1104,17 @@ const docTemplate = `{
}
}
},
"types.ItemAttachmentUpdate": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"types.ItemCreate": {
"type": "object",
"properties": {

View file

@ -346,6 +346,50 @@
}
}
},
"put": {
"security": [
{
"Bearer": []
}
],
"tags": [
"Items"
],
"summary": "retrieves an attachment for an item",
"parameters": [
{
"type": "string",
"description": "Item ID",
"name": "id",
"in": "path",
"required": true
},
{
"type": "string",
"description": "Attachment ID",
"name": "attachment_id",
"in": "path",
"required": true
},
{
"description": "Attachment Update",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/types.ItemAttachmentUpdate"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/types.ItemOut"
}
}
}
},
"delete": {
"security": [
{
@ -1052,6 +1096,17 @@
}
}
},
"types.ItemAttachmentUpdate": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"types.ItemCreate": {
"type": "object",
"properties": {

View file

@ -65,6 +65,13 @@ definitions:
token:
type: string
type: object
types.ItemAttachmentUpdate:
properties:
title:
type: string
type:
type: string
type: object
types.ItemCreate:
properties:
description:
@ -586,6 +593,34 @@ paths:
summary: retrieves an attachment for an item
tags:
- Items
put:
parameters:
- description: Item ID
in: path
name: id
required: true
type: string
- description: Attachment ID
in: path
name: attachment_id
required: true
type: string
- description: Attachment Update
in: body
name: payload
required: true
schema:
$ref: '#/definitions/types.ItemAttachmentUpdate'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/types.ItemOut'
security:
- Bearer: []
summary: retrieves an attachment for an item
tags:
- Items
/v1/items/{id}/attachments/download:
get:
parameters:

View file

@ -88,6 +88,7 @@ func (a *app) newRouter(repos *repo.AllRepos) *chi.Mux {
r.Post(v1Base("/items/{id}/attachments"), v1Ctrl.HandleItemAttachmentCreate())
r.Get(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentToken())
r.Put(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentUpdate())
r.Delete(v1Base("/items/{id}/attachments/{attachment_id}"), v1Ctrl.HandleItemAttachmentDelete())
})
}

View file

@ -3,12 +3,8 @@ package v1
import (
"encoding/csv"
"errors"
"fmt"
"net/http"
"path/filepath"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/ent/attachment"
"github.com/hay-kot/homebox/backend/internal/services"
"github.com/hay-kot/homebox/backend/internal/types"
@ -70,7 +66,7 @@ func (ctrl *V1Controller) HandleItemsCreate() http.HandlerFunc {
// @Summary deletes a item
// @Tags Items
// @Produce json
// @Param id path string true "Item ID"
// @Param id path string true "Item ID"
// @Success 204
// @Router /v1/items/{id} [DELETE]
// @Security Bearer
@ -120,7 +116,7 @@ func (ctrl *V1Controller) HandleItemGet() http.HandlerFunc {
// @Summary updates a item
// @Tags Items
// @Produce json
// @Param id path string true "Item ID"
// @Param id path string true "Item ID"
// @Param payload body types.ItemUpdate true "Item Data"
// @Success 200 {object} types.ItemOut
// @Router /v1/items/{id} [PUT]
@ -233,14 +229,15 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc {
attachmentName = "attachment"
}
uid, user, err := ctrl.partialParseIdAndUser(w, r)
uid, _, err := ctrl.partialParseIdAndUser(w, r)
if err != nil {
return
}
ctx := services.NewServiceContext(r.Context())
item, err := ctrl.svc.Items.AttachmentAdd(
r.Context(),
user.GroupID,
ctx,
uid,
attachmentName,
attachment.Type(attachmentType),
@ -256,101 +253,3 @@ func (ctrl *V1Controller) HandleItemAttachmentCreate() http.HandlerFunc {
server.Respond(w, http.StatusCreated, item)
}
}
// HandleItemAttachmentGet godocs
// @Summary retrieves an attachment for an item
// @Tags Items
// @Produce application/octet-stream
// @Param id path string true "Item ID"
// @Param token query string true "Attachment token"
// @Success 200
// @Router /v1/items/{id}/attachments/download [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
token := server.GetParam(r, "token", "")
path, err := ctrl.svc.Items.AttachmentPath(r.Context(), token)
if err != nil {
log.Err(err).Msg("failed to get attachment")
server.RespondServerError(w)
return
}
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filepath.Base(path)))
w.Header().Set("Content-Type", "application/octet-stream")
http.ServeFile(w, r, path)
}
}
// HandleItemAttachmentToken godocs
// @Summary retrieves an attachment for an item
// @Tags Items
// @Produce application/octet-stream
// @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID"
// @Success 200 {object} types.ItemAttachmentToken
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentToken() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
uid, user, err := ctrl.partialParseIdAndUser(w, r)
if err != nil {
return
}
attachmentId, err := uuid.Parse(chi.URLParam(r, "attachment_id"))
if err != nil {
log.Err(err).Msg("failed to parse attachment_id param")
server.RespondError(w, http.StatusBadRequest, err)
return
}
token, err := ctrl.svc.Items.AttachmentToken(r.Context(), user.GroupID, uid, attachmentId)
if err != nil {
log.Err(err).Msg("failed to get attachment")
server.RespondServerError(w)
return
}
server.Respond(w, http.StatusOK, types.ItemAttachmentToken{
Token: token,
})
}
}
// HandleItemAttachmentDelete godocs
// @Summary retrieves an attachment for an item
// @Tags Items
// @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID"
// @Success 204
// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentDelete() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
uid, user, err := ctrl.partialParseIdAndUser(w, r)
if err != nil {
return
}
attachmentId, err := uuid.Parse(chi.URLParam(r, "attachment_id"))
if err != nil {
log.Err(err).Msg("failed to parse attachment_id param")
server.RespondError(w, http.StatusBadRequest, err)
return
}
err = ctrl.svc.Items.AttachmentDelete(r.Context(), user.GroupID, uid, attachmentId)
if err != nil {
log.Err(err).Msg("failed to delete attachment")
server.RespondServerError(w)
return
}
server.Respond(w, http.StatusNoContent, nil)
}
}

View file

@ -0,0 +1,140 @@
package v1
import (
"fmt"
"net/http"
"path/filepath"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
"github.com/hay-kot/homebox/backend/internal/services"
"github.com/hay-kot/homebox/backend/internal/types"
"github.com/hay-kot/homebox/backend/pkgs/server"
"github.com/rs/zerolog/log"
)
// HandleItemAttachmentGet godocs
// @Summary retrieves an attachment for an item
// @Tags Items
// @Produce application/octet-stream
// @Param id path string true "Item ID"
// @Param token query string true "Attachment token"
// @Success 200
// @Router /v1/items/{id}/attachments/download [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentDownload() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
token := server.GetParam(r, "token", "")
path, err := ctrl.svc.Items.AttachmentPath(r.Context(), token)
if err != nil {
log.Err(err).Msg("failed to get attachment")
server.RespondServerError(w)
return
}
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filepath.Base(path)))
w.Header().Set("Content-Type", "application/octet-stream")
http.ServeFile(w, r, path)
}
}
// HandleItemAttachmentToken godocs
// @Summary retrieves an attachment for an item
// @Tags Items
// @Produce application/octet-stream
// @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID"
// @Success 200 {object} types.ItemAttachmentToken
// @Router /v1/items/{id}/attachments/{attachment_id} [GET]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentToken() http.HandlerFunc {
return ctrl.handleItemAttachmentsHandler
}
// HandleItemAttachmentDelete godocs
// @Summary retrieves an attachment for an item
// @Tags Items
// @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID"
// @Success 204
// @Router /v1/items/{id}/attachments/{attachment_id} [DELETE]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentDelete() http.HandlerFunc {
return ctrl.handleItemAttachmentsHandler
}
// HandleItemAttachmentUpdate godocs
// @Summary retrieves an attachment for an item
// @Tags Items
// @Param id path string true "Item ID"
// @Param attachment_id path string true "Attachment ID"
// @Param payload body types.ItemAttachmentUpdate true "Attachment Update"
// @Success 200 {object} types.ItemOut
// @Router /v1/items/{id}/attachments/{attachment_id} [PUT]
// @Security Bearer
func (ctrl *V1Controller) HandleItemAttachmentUpdate() http.HandlerFunc {
return ctrl.handleItemAttachmentsHandler
}
func (ctrl *V1Controller) handleItemAttachmentsHandler(w http.ResponseWriter, r *http.Request) {
uid, user, err := ctrl.partialParseIdAndUser(w, r)
if err != nil {
return
}
attachmentId, err := uuid.Parse(chi.URLParam(r, "attachment_id"))
if err != nil {
log.Err(err).Msg("failed to parse attachment_id param")
server.RespondError(w, http.StatusBadRequest, err)
return
}
ctx := services.NewServiceContext(r.Context())
switch r.Method {
// Token Handler
case http.MethodGet:
token, err := ctrl.svc.Items.AttachmentToken(ctx, uid, attachmentId)
if err != nil {
log.Err(err).Msg("failed to get attachment")
server.RespondServerError(w)
return
}
server.Respond(w, http.StatusOK, types.ItemAttachmentToken{Token: token})
// Delete Attachment Handler
case http.MethodDelete:
err = ctrl.svc.Items.AttachmentDelete(r.Context(), user.GroupID, uid, attachmentId)
if err != nil {
log.Err(err).Msg("failed to delete attachment")
server.RespondServerError(w)
return
}
server.Respond(w, http.StatusNoContent, nil)
// Update Attachment Handler
case http.MethodPut:
var attachment types.ItemAttachmentUpdate
err = server.Decode(r, &attachment)
if err != nil {
log.Err(err).Msg("failed to decode attachment")
server.RespondError(w, http.StatusBadRequest, err)
return
}
attachment.ID = attachmentId
val, err := ctrl.svc.Items.AttachmentUpdate(ctx, uid, &attachment)
if err != nil {
log.Err(err).Msg("failed to delete attachment")
server.RespondServerError(w)
return
}
server.Respond(w, http.StatusOK, val)
}
}

View file

@ -34,9 +34,15 @@ func (r *AttachmentRepo) Get(ctx context.Context, id uuid.UUID) (*ent.Attachment
}
func (r *AttachmentRepo) Update(ctx context.Context, itemId uuid.UUID, typ attachment.Type) (*ent.Attachment, error) {
return r.db.Attachment.UpdateOneID(itemId).
itm, err := r.db.Attachment.UpdateOneID(itemId).
SetType(typ).
Save(ctx)
if err != nil {
return nil, err
}
return r.Get(ctx, itm.ID)
}
func (r *AttachmentRepo) Delete(ctx context.Context, id uuid.UUID) error {

View file

@ -110,3 +110,9 @@ type ItemAttachment struct {
type ItemAttachmentToken struct {
Token string `json:"token"`
}
type ItemAttachmentUpdate struct {
ID uuid.UUID `json:"-"`
Type string `json:"type"`
Title string `json:"title"`
}