Merge branch 'dev-ars' into dev
All checks were successful
Build and Deploy Go App / build (push) Successful in 6m26s
Build and Deploy Go App / deploy (push) Successful in 26s

This commit is contained in:
Iron_Felix 2025-11-27 07:11:30 +03:00
commit 246fdc86b5
11 changed files with 405 additions and 72 deletions

View file

@ -407,6 +407,30 @@ paths:
description: User or Title not found description: User or Title not found
'500': '500':
description: Internal server error description: Internal server error
delete:
operationId: deleteUserTitle
summary: Delete a usertitle
description: User deleting title from list of watched
parameters:
- name: user_id
in: path
description: ID of the user to assign the title to
required: true
schema:
type: integer
format: int64
example: 123
responses:
'200':
description: Title successfully deleted
'401':
description: Unauthorized — missing or invalid auth token
'403':
description: Forbidden — user not allowed to delete title
'404':
description: User or Title not found
'500':
description: Internal server error
components: components:
parameters: parameters:
cursor: cursor:
@ -557,6 +581,7 @@ components:
additionalProperties: additionalProperties:
type: number type: number
format: double format: double
additionalProperties: true
required: required:
- id - id
- title_names - title_names

View file

@ -16,12 +16,6 @@ import (
openapi_types "github.com/oapi-codegen/runtime/types" openapi_types "github.com/oapi-codegen/runtime/types"
) )
// Defines values for ImageStorageType.
const (
Local ImageStorageType = "local"
S3 ImageStorageType = "s3"
)
// Defines values for ReleaseSeason. // Defines values for ReleaseSeason.
const ( const (
Fall ReleaseSeason = "fall" Fall ReleaseSeason = "fall"
@ -30,6 +24,12 @@ const (
Winter ReleaseSeason = "winter" Winter ReleaseSeason = "winter"
) )
// Defines values for StorageType.
const (
Local StorageType = "local"
S3 StorageType = "s3"
)
// Defines values for TitleSort. // Defines values for TitleSort.
const ( const (
Id TitleSort = "id" Id TitleSort = "id"
@ -65,15 +65,15 @@ type Image struct {
ImagePath *string `json:"image_path,omitempty"` ImagePath *string `json:"image_path,omitempty"`
// StorageType Image storage type // StorageType Image storage type
StorageType *ImageStorageType `json:"storage_type,omitempty"` StorageType *StorageType `json:"storage_type,omitempty"`
} }
// ImageStorageType Image storage type
type ImageStorageType string
// ReleaseSeason Title release season // ReleaseSeason Title release season
type ReleaseSeason string type ReleaseSeason string
// StorageType Image storage type
type StorageType string
// Studio defines model for Studio. // Studio defines model for Studio.
type Studio struct { type Studio struct {
Description *string `json:"description,omitempty"` Description *string `json:"description,omitempty"`
@ -156,6 +156,18 @@ type UserTitle struct {
UserId int64 `json:"user_id"` UserId int64 `json:"user_id"`
} }
// UserTitleMini defines model for UserTitleMini.
type UserTitleMini struct {
Ctime *time.Time `json:"ctime,omitempty"`
Rate *int32 `json:"rate,omitempty"`
ReviewId *int64 `json:"review_id,omitempty"`
// Status User's title status
Status UserTitleStatus `json:"status"`
TitleId int64 `json:"title_id"`
UserId int64 `json:"user_id"`
}
// UserTitleStatus User's title status // UserTitleStatus User's title status
type UserTitleStatus string type UserTitleStatus string
@ -225,21 +237,30 @@ type GetUsersUserIdTitlesParams struct {
Fields *string `form:"fields,omitempty" json:"fields,omitempty"` Fields *string `form:"fields,omitempty" json:"fields,omitempty"`
} }
// UpdateUserTitleJSONBody defines parameters for UpdateUserTitle.
type UpdateUserTitleJSONBody struct {
Rate *int32 `json:"rate,omitempty"`
// Status User's title status
Status *UserTitleStatus `json:"status,omitempty"`
TitleId int64 `json:"title_id"`
}
// AddUserTitleJSONBody defines parameters for AddUserTitle. // AddUserTitleJSONBody defines parameters for AddUserTitle.
type AddUserTitleJSONBody struct { type AddUserTitleJSONBody struct {
Ctime *time.Time `json:"ctime,omitempty"` Rate *int32 `json:"rate,omitempty"`
Rate *int32 `json:"rate,omitempty"`
ReviewId *int64 `json:"review_id,omitempty"`
// Status User's title status // Status User's title status
Status UserTitleStatus `json:"status"` Status UserTitleStatus `json:"status"`
TitleId int64 `json:"title_id"` TitleId int64 `json:"title_id"`
UserId int64 `json:"user_id"`
} }
// UpdateUserJSONRequestBody defines body for UpdateUser for application/json ContentType. // UpdateUserJSONRequestBody defines body for UpdateUser for application/json ContentType.
type UpdateUserJSONRequestBody UpdateUserJSONBody type UpdateUserJSONRequestBody UpdateUserJSONBody
// UpdateUserTitleJSONRequestBody defines body for UpdateUserTitle for application/json ContentType.
type UpdateUserTitleJSONRequestBody UpdateUserTitleJSONBody
// AddUserTitleJSONRequestBody defines body for AddUserTitle for application/json ContentType. // AddUserTitleJSONRequestBody defines body for AddUserTitle for application/json ContentType.
type AddUserTitleJSONRequestBody AddUserTitleJSONBody type AddUserTitleJSONRequestBody AddUserTitleJSONBody
@ -499,9 +520,15 @@ type ServerInterface interface {
// Partially update a user account // Partially update a user account
// (PATCH /users/{user_id}) // (PATCH /users/{user_id})
UpdateUser(c *gin.Context, userId int64) UpdateUser(c *gin.Context, userId int64)
// Delete a usertitle
// (DELETE /users/{user_id}/titles)
DeleteUserTitle(c *gin.Context, userId int64)
// Get user titles // Get user titles
// (GET /users/{user_id}/titles) // (GET /users/{user_id}/titles)
GetUsersUserIdTitles(c *gin.Context, userId string, params GetUsersUserIdTitlesParams) GetUsersUserIdTitles(c *gin.Context, userId string, params GetUsersUserIdTitlesParams)
// Update a usertitle
// (PATCH /users/{user_id}/titles)
UpdateUserTitle(c *gin.Context, userId int64)
// Add a title to a user // Add a title to a user
// (POST /users/{user_id}/titles) // (POST /users/{user_id}/titles)
AddUserTitle(c *gin.Context, userId int64) AddUserTitle(c *gin.Context, userId int64)
@ -716,6 +743,30 @@ func (siw *ServerInterfaceWrapper) UpdateUser(c *gin.Context) {
siw.Handler.UpdateUser(c, userId) siw.Handler.UpdateUser(c, userId)
} }
// DeleteUserTitle operation middleware
func (siw *ServerInterfaceWrapper) DeleteUserTitle(c *gin.Context) {
var err error
// ------------- Path parameter "user_id" -------------
var userId int64
err = runtime.BindStyledParameterWithOptions("simple", "user_id", c.Param("user_id"), &userId, runtime.BindStyledParameterOptions{Explode: false, Required: true})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter user_id: %w", err), http.StatusBadRequest)
return
}
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
if c.IsAborted() {
return
}
}
siw.Handler.DeleteUserTitle(c, userId)
}
// GetUsersUserIdTitles operation middleware // GetUsersUserIdTitles operation middleware
func (siw *ServerInterfaceWrapper) GetUsersUserIdTitles(c *gin.Context) { func (siw *ServerInterfaceWrapper) GetUsersUserIdTitles(c *gin.Context) {
@ -839,6 +890,30 @@ func (siw *ServerInterfaceWrapper) GetUsersUserIdTitles(c *gin.Context) {
siw.Handler.GetUsersUserIdTitles(c, userId, params) siw.Handler.GetUsersUserIdTitles(c, userId, params)
} }
// UpdateUserTitle operation middleware
func (siw *ServerInterfaceWrapper) UpdateUserTitle(c *gin.Context) {
var err error
// ------------- Path parameter "user_id" -------------
var userId int64
err = runtime.BindStyledParameterWithOptions("simple", "user_id", c.Param("user_id"), &userId, runtime.BindStyledParameterOptions{Explode: false, Required: true})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter user_id: %w", err), http.StatusBadRequest)
return
}
for _, middleware := range siw.HandlerMiddlewares {
middleware(c)
if c.IsAborted() {
return
}
}
siw.Handler.UpdateUserTitle(c, userId)
}
// AddUserTitle operation middleware // AddUserTitle operation middleware
func (siw *ServerInterfaceWrapper) AddUserTitle(c *gin.Context) { func (siw *ServerInterfaceWrapper) AddUserTitle(c *gin.Context) {
@ -894,7 +969,9 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options
router.GET(options.BaseURL+"/titles/:title_id", wrapper.GetTitlesTitleId) router.GET(options.BaseURL+"/titles/:title_id", wrapper.GetTitlesTitleId)
router.GET(options.BaseURL+"/users/:user_id", wrapper.GetUsersUserId) router.GET(options.BaseURL+"/users/:user_id", wrapper.GetUsersUserId)
router.PATCH(options.BaseURL+"/users/:user_id", wrapper.UpdateUser) router.PATCH(options.BaseURL+"/users/:user_id", wrapper.UpdateUser)
router.DELETE(options.BaseURL+"/users/:user_id/titles", wrapper.DeleteUserTitle)
router.GET(options.BaseURL+"/users/:user_id/titles", wrapper.GetUsersUserIdTitles) router.GET(options.BaseURL+"/users/:user_id/titles", wrapper.GetUsersUserIdTitles)
router.PATCH(options.BaseURL+"/users/:user_id/titles", wrapper.UpdateUserTitle)
router.POST(options.BaseURL+"/users/:user_id/titles", wrapper.AddUserTitle) router.POST(options.BaseURL+"/users/:user_id/titles", wrapper.AddUserTitle)
} }
@ -1110,6 +1187,54 @@ func (response UpdateUser500Response) VisitUpdateUserResponse(w http.ResponseWri
return nil return nil
} }
type DeleteUserTitleRequestObject struct {
UserId int64 `json:"user_id"`
}
type DeleteUserTitleResponseObject interface {
VisitDeleteUserTitleResponse(w http.ResponseWriter) error
}
type DeleteUserTitle200Response struct {
}
func (response DeleteUserTitle200Response) VisitDeleteUserTitleResponse(w http.ResponseWriter) error {
w.WriteHeader(200)
return nil
}
type DeleteUserTitle401Response struct {
}
func (response DeleteUserTitle401Response) VisitDeleteUserTitleResponse(w http.ResponseWriter) error {
w.WriteHeader(401)
return nil
}
type DeleteUserTitle403Response struct {
}
func (response DeleteUserTitle403Response) VisitDeleteUserTitleResponse(w http.ResponseWriter) error {
w.WriteHeader(403)
return nil
}
type DeleteUserTitle404Response struct {
}
func (response DeleteUserTitle404Response) VisitDeleteUserTitleResponse(w http.ResponseWriter) error {
w.WriteHeader(404)
return nil
}
type DeleteUserTitle500Response struct {
}
func (response DeleteUserTitle500Response) VisitDeleteUserTitleResponse(w http.ResponseWriter) error {
w.WriteHeader(500)
return nil
}
type GetUsersUserIdTitlesRequestObject struct { type GetUsersUserIdTitlesRequestObject struct {
UserId string `json:"user_id"` UserId string `json:"user_id"`
Params GetUsersUserIdTitlesParams Params GetUsersUserIdTitlesParams
@ -1163,6 +1288,64 @@ func (response GetUsersUserIdTitles500Response) VisitGetUsersUserIdTitlesRespons
return nil return nil
} }
type UpdateUserTitleRequestObject struct {
UserId int64 `json:"user_id"`
Body *UpdateUserTitleJSONRequestBody
}
type UpdateUserTitleResponseObject interface {
VisitUpdateUserTitleResponse(w http.ResponseWriter) error
}
type UpdateUserTitle200JSONResponse UserTitleMini
func (response UpdateUserTitle200JSONResponse) VisitUpdateUserTitleResponse(w http.ResponseWriter) error {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
return json.NewEncoder(w).Encode(response)
}
type UpdateUserTitle400Response struct {
}
func (response UpdateUserTitle400Response) VisitUpdateUserTitleResponse(w http.ResponseWriter) error {
w.WriteHeader(400)
return nil
}
type UpdateUserTitle401Response struct {
}
func (response UpdateUserTitle401Response) VisitUpdateUserTitleResponse(w http.ResponseWriter) error {
w.WriteHeader(401)
return nil
}
type UpdateUserTitle403Response struct {
}
func (response UpdateUserTitle403Response) VisitUpdateUserTitleResponse(w http.ResponseWriter) error {
w.WriteHeader(403)
return nil
}
type UpdateUserTitle404Response struct {
}
func (response UpdateUserTitle404Response) VisitUpdateUserTitleResponse(w http.ResponseWriter) error {
w.WriteHeader(404)
return nil
}
type UpdateUserTitle500Response struct {
}
func (response UpdateUserTitle500Response) VisitUpdateUserTitleResponse(w http.ResponseWriter) error {
w.WriteHeader(500)
return nil
}
type AddUserTitleRequestObject struct { type AddUserTitleRequestObject struct {
UserId int64 `json:"user_id"` UserId int64 `json:"user_id"`
Body *AddUserTitleJSONRequestBody Body *AddUserTitleJSONRequestBody
@ -1172,16 +1355,7 @@ type AddUserTitleResponseObject interface {
VisitAddUserTitleResponse(w http.ResponseWriter) error VisitAddUserTitleResponse(w http.ResponseWriter) error
} }
type AddUserTitle200JSONResponse struct { type AddUserTitle200JSONResponse UserTitleMini
Ctime *time.Time `json:"ctime,omitempty"`
Rate *int32 `json:"rate,omitempty"`
ReviewId *int64 `json:"review_id,omitempty"`
// Status User's title status
Status UserTitleStatus `json:"status"`
TitleId int64 `json:"title_id"`
UserId int64 `json:"user_id"`
}
func (response AddUserTitle200JSONResponse) VisitAddUserTitleResponse(w http.ResponseWriter) error { func (response AddUserTitle200JSONResponse) VisitAddUserTitleResponse(w http.ResponseWriter) error {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@ -1252,9 +1426,15 @@ type StrictServerInterface interface {
// Partially update a user account // Partially update a user account
// (PATCH /users/{user_id}) // (PATCH /users/{user_id})
UpdateUser(ctx context.Context, request UpdateUserRequestObject) (UpdateUserResponseObject, error) UpdateUser(ctx context.Context, request UpdateUserRequestObject) (UpdateUserResponseObject, error)
// Delete a usertitle
// (DELETE /users/{user_id}/titles)
DeleteUserTitle(ctx context.Context, request DeleteUserTitleRequestObject) (DeleteUserTitleResponseObject, error)
// Get user titles // Get user titles
// (GET /users/{user_id}/titles) // (GET /users/{user_id}/titles)
GetUsersUserIdTitles(ctx context.Context, request GetUsersUserIdTitlesRequestObject) (GetUsersUserIdTitlesResponseObject, error) GetUsersUserIdTitles(ctx context.Context, request GetUsersUserIdTitlesRequestObject) (GetUsersUserIdTitlesResponseObject, error)
// Update a usertitle
// (PATCH /users/{user_id}/titles)
UpdateUserTitle(ctx context.Context, request UpdateUserTitleRequestObject) (UpdateUserTitleResponseObject, error)
// Add a title to a user // Add a title to a user
// (POST /users/{user_id}/titles) // (POST /users/{user_id}/titles)
AddUserTitle(ctx context.Context, request AddUserTitleRequestObject) (AddUserTitleResponseObject, error) AddUserTitle(ctx context.Context, request AddUserTitleRequestObject) (AddUserTitleResponseObject, error)
@ -1390,6 +1570,33 @@ func (sh *strictHandler) UpdateUser(ctx *gin.Context, userId int64) {
} }
} }
// DeleteUserTitle operation middleware
func (sh *strictHandler) DeleteUserTitle(ctx *gin.Context, userId int64) {
var request DeleteUserTitleRequestObject
request.UserId = userId
handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
return sh.ssi.DeleteUserTitle(ctx, request.(DeleteUserTitleRequestObject))
}
for _, middleware := range sh.middlewares {
handler = middleware(handler, "DeleteUserTitle")
}
response, err := handler(ctx, request)
if err != nil {
ctx.Error(err)
ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(DeleteUserTitleResponseObject); ok {
if err := validResponse.VisitDeleteUserTitleResponse(ctx.Writer); err != nil {
ctx.Error(err)
}
} else if response != nil {
ctx.Error(fmt.Errorf("unexpected response type: %T", response))
}
}
// GetUsersUserIdTitles operation middleware // GetUsersUserIdTitles operation middleware
func (sh *strictHandler) GetUsersUserIdTitles(ctx *gin.Context, userId string, params GetUsersUserIdTitlesParams) { func (sh *strictHandler) GetUsersUserIdTitles(ctx *gin.Context, userId string, params GetUsersUserIdTitlesParams) {
var request GetUsersUserIdTitlesRequestObject var request GetUsersUserIdTitlesRequestObject
@ -1418,6 +1625,41 @@ func (sh *strictHandler) GetUsersUserIdTitles(ctx *gin.Context, userId string, p
} }
} }
// UpdateUserTitle operation middleware
func (sh *strictHandler) UpdateUserTitle(ctx *gin.Context, userId int64) {
var request UpdateUserTitleRequestObject
request.UserId = userId
var body UpdateUserTitleJSONRequestBody
if err := ctx.ShouldBindJSON(&body); err != nil {
ctx.Status(http.StatusBadRequest)
ctx.Error(err)
return
}
request.Body = &body
handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
return sh.ssi.UpdateUserTitle(ctx, request.(UpdateUserTitleRequestObject))
}
for _, middleware := range sh.middlewares {
handler = middleware(handler, "UpdateUserTitle")
}
response, err := handler(ctx, request)
if err != nil {
ctx.Error(err)
ctx.Status(http.StatusInternalServerError)
} else if validResponse, ok := response.(UpdateUserTitleResponseObject); ok {
if err := validResponse.VisitUpdateUserTitleResponse(ctx.Writer); err != nil {
ctx.Error(err)
}
} else if response != nil {
ctx.Error(fmt.Errorf("unexpected response type: %T", response))
}
}
// AddUserTitle operation middleware // AddUserTitle operation middleware
func (sh *strictHandler) AddUserTitle(ctx *gin.Context, userId int64) { func (sh *strictHandler) AddUserTitle(ctx *gin.Context, userId int64) {
var request AddUserTitleRequestObject var request AddUserTitleRequestObject

View file

@ -21,4 +21,3 @@ components:
$ref: "./parameters/_index.yaml" $ref: "./parameters/_index.yaml"
schemas: schemas:
$ref: "./schemas/_index.yaml" $ref: "./schemas/_index.yaml"

View file

@ -189,3 +189,31 @@ patch:
description: User or Title not found description: User or Title not found
'500': '500':
description: Internal server error description: Internal server error
delete:
summary: Delete a usertitle
description: User deleting title from list of watched
operationId: deleteUserTitle
parameters:
- name: user_id
in: path
required: true
schema:
type: integer
format: int64
description: ID of the user to assign the title to
example: 123
responses:
'200':
description: Title successfully deleted
# '400':
# description: Invalid request body (missing fields, invalid types, etc.)
'401':
description: Unauthorized — missing or invalid auth token
'403':
description: Forbidden — user not allowed to delete title
'404':
description: User or Title not found
'500':
description: Internal server error

4
deploy/api_gen.ps1 Normal file
View file

@ -0,0 +1,4 @@
cd ./api
openapi-format .\openapi.yaml --output .\_build\openapi.yaml --yaml
cd ..
oapi-codegen --config=api\oapi-codegen.yaml api\_build\openapi.yaml

View file

@ -1,7 +1,6 @@
package handlers package handlers
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
oapi "nyanimedb/api" oapi "nyanimedb/api"
@ -17,11 +16,11 @@ func NewServer(db *sqlc.Queries) Server {
return Server{db: db} return Server{db: db}
} }
func sql2StorageType(s *sqlc.StorageTypeT) (*oapi.ImageStorageType, error) { func sql2StorageType(s *sqlc.StorageTypeT) (*oapi.StorageType, error) {
if s == nil { if s == nil {
return nil, nil return nil, nil
} }
var t oapi.ImageStorageType var t oapi.StorageType
switch *s { switch *s {
case sqlc.StorageTypeTLocal: case sqlc.StorageTypeTLocal:
t = oapi.Local t = oapi.Local
@ -33,7 +32,7 @@ func sql2StorageType(s *sqlc.StorageTypeT) (*oapi.ImageStorageType, error) {
return &t, nil return &t, nil
} }
func (s Server) mapTitle(ctx context.Context, title sqlc.GetTitleByIDRow) (oapi.Title, error) { func (s Server) mapTitle(title sqlc.GetTitleByIDRow) (oapi.Title, error) {
oapi_title := oapi.Title{ oapi_title := oapi.Title{
EpisodesAired: title.EpisodesAired, EpisodesAired: title.EpisodesAired,

View file

@ -144,7 +144,7 @@ func (s Server) GetTitlesTitleId(ctx context.Context, request oapi.GetTitlesTitl
return oapi.GetTitlesTitleId500Response{}, nil return oapi.GetTitlesTitleId500Response{}, nil
} }
oapi_title, err = s.mapTitle(ctx, sqlc_title) oapi_title, err = s.mapTitle(sqlc_title)
if err != nil { if err != nil {
log.Errorf("%v", err) log.Errorf("%v", err)
return oapi.GetTitlesTitleId500Response{}, nil return oapi.GetTitlesTitleId500Response{}, nil
@ -238,7 +238,7 @@ func (s Server) GetTitles(ctx context.Context, request oapi.GetTitlesRequestObje
// _title.TitleStorageType = string(s) // _title.TitleStorageType = string(s)
// } // }
t, err := s.mapTitle(ctx, _title) t, err := s.mapTitle(_title)
if err != nil { if err != nil {
log.Errorf("%v", err) log.Errorf("%v", err)
return oapi.GetTitles500Response{}, nil return oapi.GetTitles500Response{}, nil

View file

@ -2,6 +2,7 @@ package handlers
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
oapi "nyanimedb/api" oapi "nyanimedb/api"
sqlc "nyanimedb/sql" sqlc "nyanimedb/sql"
@ -9,24 +10,12 @@ import (
"time" "time"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
"github.com/oapi-codegen/runtime/types" "github.com/oapi-codegen/runtime/types"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// type Server struct {
// db *sqlc.Queries
// }
// func NewServer(db *sqlc.Queries) Server {
// return Server{db: db}
// }
// func parseInt64(s string) (int32, error) {
// i, err := strconv.ParseInt(s, 10, 64)
// return int32(i), err
// }
func mapUser(u sqlc.GetUserByIDRow) (oapi.User, error) { func mapUser(u sqlc.GetUserByIDRow) (oapi.User, error) {
i := oapi.Image{ i := oapi.Image{
Id: u.AvatarID, Id: u.AvatarID,
@ -202,7 +191,7 @@ func (s Server) mapUsertitle(ctx context.Context, t sqlc.SearchUserTitlesRow) (o
// StudioImagePath: title.StudioImagePath, // StudioImagePath: title.StudioImagePath,
} }
oapi_title, err := s.mapTitle(ctx, _title) oapi_title, err := s.mapTitle(_title)
if err != nil { if err != nil {
return oapi_usertitle, fmt.Errorf("mapUsertitle: %v", err) return oapi_usertitle, fmt.Errorf("mapUsertitle: %v", err)
} }
@ -368,19 +357,26 @@ func (s Server) AddUserTitle(ctx context.Context, request oapi.AddUserTitleReque
} }
params := sqlc.InsertUserTitleParams{ params := sqlc.InsertUserTitleParams{
UserID: request.UserId, UserID: request.UserId,
TitleID: request.Body.TitleId, TitleID: request.Body.TitleId,
Status: *status, Status: *status,
Rate: request.Body.Rate, Rate: request.Body.Rate,
ReviewID: request.Body.ReviewId,
} }
user_title, err := s.db.InsertUserTitle(ctx, params) user_title, err := s.db.InsertUserTitle(ctx, params)
if err != nil { if err != nil {
log.Errorf("%v", err) var pgErr *pgconn.PgError
return oapi.AddUserTitle500Response{}, nil if errors.As(err, &pgErr) {
// fmt.Println(pgErr.Message) // => syntax error at end of input
// fmt.Println(pgErr.Code) // => 42601
if pgErr.Code == "23505" { //duplicate key value
return oapi.AddUserTitle409Response{}, nil
}
} else {
log.Errorf("%v", err)
return oapi.AddUserTitle500Response{}, nil
}
} }
oapi_status, err := sql2usertitlestatus(user_title.Status) oapi_status, err := sql2usertitlestatus(user_title.Status)
if err != nil { if err != nil {
log.Errorf("%v", err) log.Errorf("%v", err)
@ -406,3 +402,13 @@ func (s Server) AddUserTitle(ctx context.Context, request oapi.AddUserTitleReque
return oapi.AddUserTitle200JSONResponse(oapi_usertitle), nil return oapi.AddUserTitle200JSONResponse(oapi_usertitle), nil
} }
// DeleteUserTitle implements oapi.StrictServerInterface.
func (s Server) DeleteUserTitle(ctx context.Context, request oapi.DeleteUserTitleRequestObject) (oapi.DeleteUserTitleResponseObject, error) {
panic("unimplemented")
}
// UpdateUserTitle implements oapi.StrictServerInterface.
func (s Server) UpdateUserTitle(ctx context.Context, request oapi.UpdateUserTitleRequestObject) (oapi.UpdateUserTitleResponseObject, error) {
panic("unimplemented")
}

View file

@ -461,21 +461,13 @@ VALUES (
) )
RETURNING user_id, title_id, status, rate, review_id, ctime; RETURNING user_id, title_id, status, rate, review_id, ctime;
-- -- name: UpdateUserTitle :one -- name: UpdateUserTitle :one
-- UPDATE usertitles -- Fails with sql.ErrNoRows if (user_id, title_id) not found
-- SET UPDATE usertitles
-- status = COALESCE(sqlc.narg('status'), status), SET
-- rate = COALESCE(sqlc.narg('rate'), rate), status = COALESCE(sqlc.narg('status')::usertitle_status_t, status),
-- review_id = COALESCE(sqlc.narg('review_id'), review_id) rate = COALESCE(sqlc.narg('rate')::int, rate)
-- WHERE user_id = $1 AND title_id = $2 WHERE
-- RETURNING *; user_id = sqlc.arg('user_id')
AND title_id = sqlc.arg('title_id')
-- -- name: DeleteUserTitle :exec RETURNING *;
-- DELETE FROM usertitles
-- WHERE user_id = $1 AND ($2::int IS NULL OR title_id = $2);
-- -- name: ListTags :many
-- SELECT tag_id, tag_names
-- FROM tags
-- ORDER BY tag_id
-- LIMIT $1 OFFSET $2;

View file

@ -179,6 +179,6 @@ END;
$$ LANGUAGE plpgsql; $$ LANGUAGE plpgsql;
CREATE TRIGGER set_ctime_on_update CREATE TRIGGER set_ctime_on_update
AFTER UPDATE ON usertitles BEFORE UPDATE ON usertitles
FOR EACH ROW FOR EACH ROW
EXECUTE FUNCTION set_ctime(); EXECUTE FUNCTION set_ctime();

View file

@ -925,3 +925,41 @@ func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (UpdateU
) )
return i, err return i, err
} }
const updateUserTitle = `-- name: UpdateUserTitle :one
UPDATE usertitles
SET
status = COALESCE($1::usertitle_status_t, status),
rate = COALESCE($2::int, rate)
WHERE
user_id = $3
AND title_id = $4
RETURNING user_id, title_id, status, rate, review_id, ctime
`
type UpdateUserTitleParams struct {
Status NullUsertitleStatusT `json:"status"`
Rate *int32 `json:"rate"`
UserID int64 `json:"user_id"`
TitleID int64 `json:"title_id"`
}
// Fails with sql.ErrNoRows if (user_id, title_id) not found
func (q *Queries) UpdateUserTitle(ctx context.Context, arg UpdateUserTitleParams) (Usertitle, error) {
row := q.db.QueryRow(ctx, updateUserTitle,
arg.Status,
arg.Rate,
arg.UserID,
arg.TitleID,
)
var i Usertitle
err := row.Scan(
&i.UserID,
&i.TitleID,
&i.Status,
&i.Rate,
&i.ReviewID,
&i.Ctime,
)
return i, err
}