Feat: finish putImageAliases
This commit is contained in:
9
Makefile
9
Makefile
@@ -1,6 +1,7 @@
|
||||
.PHONY: all swagger docker install test bench
|
||||
.PHONY: all swagger docker install test
|
||||
|
||||
SWAG ?= go run github.com/swaggo/swag/cmd/swag@v1.16.4
|
||||
DOCKER ?= docker
|
||||
|
||||
GO_ENV += CGO_ENABLED=0
|
||||
SOURCE := $(shell find . -type f -name '*.go')
|
||||
@@ -9,7 +10,7 @@ TARGET := backend
|
||||
all: swagger docker
|
||||
|
||||
docker: $(TARGET)
|
||||
docker compose up -d --force-recreate --build backend
|
||||
$(DOCKER) compose up -d --force-recreate --build backend
|
||||
|
||||
install:
|
||||
$(GO_ENV) go install
|
||||
@@ -17,6 +18,10 @@ install:
|
||||
test:
|
||||
go test -v ./tests -count=1
|
||||
|
||||
postgres:
|
||||
$(DOCKER) compose exec postgres psql \
|
||||
postgres://go2025:go2025@postgres:5432/go2025?sslmode=disable
|
||||
|
||||
swagger:
|
||||
$(SWAG) fmt
|
||||
$(SWAG) init -o docs -g cmds/serve.go -pdl 1
|
||||
|
||||
@@ -268,10 +268,10 @@ const docTemplate = `{
|
||||
"api.getImagesOutputImage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aliases": {
|
||||
"aliasesIds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
|
||||
@@ -260,10 +260,10 @@
|
||||
"api.getImagesOutputImage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aliases": {
|
||||
"aliasesIds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
|
||||
@@ -9,9 +9,9 @@ definitions:
|
||||
type: object
|
||||
api.getImagesOutputImage:
|
||||
properties:
|
||||
aliases:
|
||||
aliasesIds:
|
||||
items:
|
||||
type: string
|
||||
type: integer
|
||||
type: array
|
||||
id:
|
||||
type: integer
|
||||
|
||||
@@ -19,5 +19,6 @@ import (
|
||||
func (self *Handlers) DeleteAlias(
|
||||
w http.ResponseWriter, req bunrouter.Request,
|
||||
) error {
|
||||
// TODO
|
||||
return utils.Success(w)
|
||||
}
|
||||
|
||||
@@ -19,5 +19,6 @@ import (
|
||||
func (self *Handlers) DeleteImage(
|
||||
w http.ResponseWriter, req bunrouter.Request,
|
||||
) error {
|
||||
// TODO
|
||||
return utils.Success(w)
|
||||
}
|
||||
|
||||
@@ -15,5 +15,6 @@ import (
|
||||
func (self *Handlers) GetAliasUpdate(
|
||||
w http.ResponseWriter, req bunrouter.Request,
|
||||
) error {
|
||||
// TODO
|
||||
return utils.Success(w)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ type getAliasesOutputAlias struct {
|
||||
func (self *Handlers) GetAliases(
|
||||
w http.ResponseWriter, req bunrouter.Request,
|
||||
) error {
|
||||
// mock output
|
||||
ctx := req.Context()
|
||||
|
||||
aliases, err := self.db.GetAliases(ctx)
|
||||
|
||||
@@ -2,10 +2,10 @@ package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"gitea.konchin.com/go2025/backend/middlewares"
|
||||
"gitea.konchin.com/go2025/backend/utils"
|
||||
"github.com/uptrace/bunrouter"
|
||||
)
|
||||
|
||||
@@ -13,7 +13,7 @@ type getImagesOutputImage struct {
|
||||
Id int64 `json:"id"`
|
||||
Uploader string `json:"uploadedUserId"`
|
||||
UploadTS int64 `json:"uploadedAt"`
|
||||
Aliases []string `json:"aliases"`
|
||||
AliasesIds []int64 `json:"aliasesIds"`
|
||||
}
|
||||
|
||||
// GetImages
|
||||
@@ -27,18 +27,63 @@ type getImagesOutputImage struct {
|
||||
func (self *Handlers) GetImages(
|
||||
w http.ResponseWriter, req bunrouter.Request,
|
||||
) error {
|
||||
// ctx := req.Context()
|
||||
ctx := req.Context()
|
||||
|
||||
images := strings.Split(req.Param("images"), ",")
|
||||
aliases := strings.Split(req.Param("aliases"), ",")
|
||||
rawReqImages := strings.Split(req.Param("images"), ",")
|
||||
rawReqAliases := strings.Split(req.Param("aliases"), ",")
|
||||
|
||||
if (len(images) == 0 && len(aliases) == 0) ||
|
||||
(len(images) > 0 && len(aliases) > 0) {
|
||||
if (len(rawReqImages) == 0 && len(rawReqAliases) == 0) ||
|
||||
(len(rawReqImages) > 0 && len(rawReqAliases) > 0) {
|
||||
return middlewares.HTTPError{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Message: "images and aliases should exist exactly one",
|
||||
}
|
||||
}
|
||||
|
||||
return utils.Success(w)
|
||||
var reqImages, reqAliases []int64
|
||||
for _, img := range rawReqImages {
|
||||
imgId, err := strconv.ParseInt(img, 10, 64)
|
||||
if err != nil {
|
||||
return middlewares.HTTPError{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Message: "failed to parse image ids",
|
||||
}
|
||||
}
|
||||
reqImages = append(reqImages, imgId)
|
||||
}
|
||||
for _, ali := range rawReqAliases {
|
||||
aliId, err := strconv.ParseInt(ali, 10, 64)
|
||||
if err != nil {
|
||||
return middlewares.HTTPError{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Message: "failed to parse alias ids",
|
||||
}
|
||||
}
|
||||
reqAliases = append(reqAliases, aliId)
|
||||
}
|
||||
|
||||
images, err := self.db.GetImages(ctx, reqImages, reqAliases)
|
||||
if err != nil {
|
||||
return middlewares.HTTPError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "failed to get images",
|
||||
OriginError: err,
|
||||
}
|
||||
}
|
||||
|
||||
var output []getImagesOutputImage
|
||||
for _, img := range images {
|
||||
var aliases []int64
|
||||
for _, alias := range img.Aliases {
|
||||
aliases = append(aliases, alias.Id)
|
||||
}
|
||||
output = append(output, getImagesOutputImage{
|
||||
Id: img.Id,
|
||||
Uploader: img.Uploader,
|
||||
UploadTS: img.UploadTS.Unix(),
|
||||
AliasesIds: aliases,
|
||||
})
|
||||
}
|
||||
|
||||
return bunrouter.JSON(w, output)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"gitea.konchin.com/go2025/backend/middlewares"
|
||||
"gitea.konchin.com/go2025/backend/utils"
|
||||
"github.com/uptrace/bunrouter"
|
||||
)
|
||||
@@ -19,5 +21,14 @@ import (
|
||||
func (self *Handlers) PostImage(
|
||||
w http.ResponseWriter, req bunrouter.Request,
|
||||
) error {
|
||||
typeHeader := strings.Split(req.Header.Get("Content-Type"), "/")
|
||||
if len(typeHeader) != 2 || typeHeader[0] != "image" {
|
||||
return middlewares.HTTPError{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Message: "incorrect 'Content-Type' header",
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
return utils.Success(w)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,23 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"gitea.konchin.com/go2025/backend/middlewares"
|
||||
"gitea.konchin.com/go2025/backend/utils"
|
||||
"github.com/uptrace/bunrouter"
|
||||
)
|
||||
|
||||
type putImageAliasesInputAlias = string
|
||||
type putImageAliasesInput struct {
|
||||
Aliases []string `json:"aliases"`
|
||||
}
|
||||
|
||||
// PutImageAliases
|
||||
//
|
||||
// @param id path int64 true "Image Id"
|
||||
// @param payload body []putImageAliasesInputAlias true "Payload"
|
||||
// @param payload body putImageAliasesInput true "Payload"
|
||||
// @success 200
|
||||
// @failure 401
|
||||
// @failure 404
|
||||
@@ -20,5 +25,43 @@ type putImageAliasesInputAlias = string
|
||||
func (self *Handlers) PutImageAliases(
|
||||
w http.ResponseWriter, req bunrouter.Request,
|
||||
) error {
|
||||
ctx := req.Context()
|
||||
|
||||
imgId, err := req.Params().Int64("id")
|
||||
if err != nil {
|
||||
return middlewares.HTTPError{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Message: "falied to parse image id in path",
|
||||
OriginError: err,
|
||||
}
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return middlewares.HTTPError{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Message: "failed to read payload",
|
||||
OriginError: err,
|
||||
}
|
||||
}
|
||||
|
||||
var input putImageAliasesInput
|
||||
if err := json.Unmarshal(b, &input); err != nil {
|
||||
return middlewares.HTTPError{
|
||||
StatusCode: http.StatusBadRequest,
|
||||
Message: "failed to unmarshal json",
|
||||
OriginError: err,
|
||||
}
|
||||
}
|
||||
|
||||
err = self.db.UpdateAliases(ctx, imgId, input.Aliases)
|
||||
if err != nil {
|
||||
return middlewares.HTTPError{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Message: "failed to update aliases",
|
||||
OriginError: err,
|
||||
}
|
||||
}
|
||||
|
||||
return utils.Success(w)
|
||||
}
|
||||
|
||||
@@ -42,19 +42,21 @@ func (self *BunDatabase) UpdateRefreshToken(
|
||||
ret := models.Session{
|
||||
UserId: userId,
|
||||
}
|
||||
|
||||
err := self.db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
|
||||
err := self.db.NewSelect().
|
||||
Model(&ret).
|
||||
WherePK().
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return models.Session{}, err
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ret.RotateRefreshToken(); err != nil {
|
||||
tracing.Logger.Ctx(ctx).
|
||||
Error("failed to rotate refresh token",
|
||||
zap.Error(err))
|
||||
return models.Session{}, err
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = self.db.NewUpdate().
|
||||
@@ -62,6 +64,12 @@ func (self *BunDatabase) UpdateRefreshToken(
|
||||
Set("refresh_token = ?", ret.RefreshToken).
|
||||
Where("user_id = ?", userId).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return models.Session{}, err
|
||||
}
|
||||
@@ -104,3 +112,75 @@ func (self *BunDatabase) GetAliases(
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *BunDatabase) GetImages(
|
||||
ctx context.Context,
|
||||
imageIds []int64,
|
||||
aliasIds []int64,
|
||||
) ([]models.Image, error) {
|
||||
if len(aliasIds) > 0 {
|
||||
var rels []models.AliasImage
|
||||
err := self.db.NewSelect().
|
||||
Model(&rels).
|
||||
Where("alias_id IN (?)", bun.In(aliasIds)).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return []models.Image{}, err
|
||||
}
|
||||
for _, rel := range rels {
|
||||
imageIds = append(imageIds, rel.ImageId)
|
||||
}
|
||||
}
|
||||
|
||||
var ret []models.Image
|
||||
if len(imageIds) > 0 {
|
||||
err := self.db.NewSelect().
|
||||
Model(&ret).
|
||||
Where("image_id IN (?)", bun.In(imageIds)).
|
||||
Relation("Aliases").
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return []models.Image{}, err
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *BunDatabase) UpdateAliases(
|
||||
ctx context.Context,
|
||||
imageId int64,
|
||||
aliasNames []string,
|
||||
) error {
|
||||
return self.db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
|
||||
var aliases []models.Alias
|
||||
for _, ali := range aliasNames {
|
||||
aliases = append(aliases, models.Alias{
|
||||
Name: ali,
|
||||
})
|
||||
}
|
||||
_, err := self.db.NewInsert().
|
||||
Model(&aliases).
|
||||
On("CONFLICT (id) DO NOTHING").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var rels []models.AliasImage
|
||||
for _, alias := range aliases {
|
||||
rels = append(rels, models.AliasImage{
|
||||
AliasId: alias.Id,
|
||||
ImageId: imageId,
|
||||
})
|
||||
}
|
||||
_, err = self.db.NewInsert().
|
||||
Model(&rels).
|
||||
On("CONFLICT (alias_id, image_id) DO NOTHING").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -25,4 +25,16 @@ type Database interface {
|
||||
GetAliases(
|
||||
ctx context.Context,
|
||||
) ([]models.Alias, error)
|
||||
|
||||
GetImages(
|
||||
ctx context.Context,
|
||||
imageIds []int64,
|
||||
aliasIds []int64,
|
||||
) ([]models.Image, error)
|
||||
|
||||
UpdateAliases(
|
||||
ctx context.Context,
|
||||
imageId int64,
|
||||
aliasNames []string,
|
||||
) error
|
||||
}
|
||||
|
||||
@@ -12,4 +12,6 @@ type Image struct {
|
||||
Id int64 `bun:"id,pk,autoincrement"`
|
||||
Uploader string `bun:"uploader"`
|
||||
UploadTS time.Time `bun:"upload_timestamp"`
|
||||
|
||||
Aliases []Alias `bun:"m2m:alias_image,join:Image=Alias"`
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
)
|
||||
|
||||
func InitDB(ctx context.Context, db *bun.DB) error {
|
||||
db.RegisterModel((*models.AliasImage)(nil))
|
||||
return db.ResetModel(ctx,
|
||||
(*models.AliasImage)(nil),
|
||||
(*models.Alias)(nil),
|
||||
(*models.Image)(nil),
|
||||
(*models.Session)(nil),
|
||||
|
||||
Reference in New Issue
Block a user