feat: implementation for handlers were written
This commit is contained in:
parent
31a09037cb
commit
80285ba7da
2 changed files with 2676 additions and 0 deletions
1958
modules/backend/api/gen.go
Normal file
1958
modules/backend/api/gen.go
Normal file
File diff suppressed because it is too large
Load diff
718
modules/backend/api/impl.go
Normal file
718
modules/backend/api/impl.go
Normal file
|
|
@ -0,0 +1,718 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"nyanimedb-server/db"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"github.com/jackc/pgx/v5/pgtype"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
db *db.Queries
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(db *db.Queries) Server {
|
||||||
|
return Server{db: db}
|
||||||
|
}
|
||||||
|
|
||||||
|
// —————————————————————————————————————————————
|
||||||
|
// ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
|
||||||
|
// —————————————————————————————————————————————
|
||||||
|
|
||||||
|
func parseInt32(s string) (int32, error) {
|
||||||
|
i, err := strconv.ParseInt(s, 10, 32)
|
||||||
|
return int32(i), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ptr[T any](v T) *T { return &v }
|
||||||
|
|
||||||
|
func pgInt4ToPtr(v pgtype.Int4) *int32 {
|
||||||
|
if v.Valid {
|
||||||
|
return &v.Int32
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func pgTextToPtr(v pgtype.Text) *string {
|
||||||
|
if v.Valid {
|
||||||
|
return &v.String
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func pgFloat8ToPtr(v pgtype.Float8) *float64 {
|
||||||
|
if v.Valid {
|
||||||
|
return &v.Float64
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonbToInterface(data []byte) interface{} {
|
||||||
|
if data == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var out interface{}
|
||||||
|
if err := json.Unmarshal(data, &out); err != nil {
|
||||||
|
return string(data) // fallback
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// —————————————————————————————————————————————
|
||||||
|
// ХЕНДЛЕРЫ
|
||||||
|
// —————————————————————————————————————————————
|
||||||
|
|
||||||
|
func (s Server) GetMedia(ctx context.Context, req GetMediaRequestObject) (GetMediaResponseObject, error) {
|
||||||
|
id, err := parseInt32(req.Params.ImageId)
|
||||||
|
if err != nil {
|
||||||
|
return GetMedia200JSONResponse{Success: ptr(false), Error: ptr("invalid image_id")}, nil
|
||||||
|
}
|
||||||
|
img, err := s.db.GetImageByID(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
if err == pgx.ErrNoRows {
|
||||||
|
return GetMedia200JSONResponse{Success: ptr(false), Error: ptr("image not found")}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return GetMedia200JSONResponse{
|
||||||
|
Success: ptr(true),
|
||||||
|
ImagePath: ptr(img.ImagePath),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) PostMedia(ctx context.Context, req PostMediaRequestObject) (PostMediaResponseObject, error) {
|
||||||
|
// ❗ Не реализовано: OpenAPI не определяет тело запроса для загрузки
|
||||||
|
return PostMedia200JSONResponse{
|
||||||
|
Success: ptr(false),
|
||||||
|
Error: ptr("upload not implemented: request body not defined in spec"),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) GetUsers(ctx context.Context, req GetUsersRequestObject) (GetUsersResponseObject, error) {
|
||||||
|
users, err := s.db.ListUsers(ctx, db.ListUsersParams{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var resp []User
|
||||||
|
for _, u := range users {
|
||||||
|
resp = append(resp, mapUser(u))
|
||||||
|
}
|
||||||
|
return GetUsers200JSONResponse(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) PostUsers(ctx context.Context, req PostUsersRequestObject) (PostUsersResponseObject, error) {
|
||||||
|
if req.Body == nil {
|
||||||
|
return PostUsers200JSONResponse{
|
||||||
|
Success: ptr(false),
|
||||||
|
Error: ptr("request body is required"),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
body := *req.Body
|
||||||
|
|
||||||
|
// Обязательные поля
|
||||||
|
nickname, ok := body["nickname"].(string)
|
||||||
|
if !ok || nickname == "" {
|
||||||
|
return PostUsers200JSONResponse{Success: ptr(false), Error: ptr("nickname is required")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mail, ok := body["mail"].(string)
|
||||||
|
if !ok || mail == "" {
|
||||||
|
return PostUsers200JSONResponse{Success: ptr(false), Error: ptr("mail is required")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
password, ok := body["password"].(string)
|
||||||
|
if !ok || password == "" {
|
||||||
|
return PostUsers200JSONResponse{Success: ptr(false), Error: ptr("password is required")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Опциональные поля
|
||||||
|
var avatarID *int32
|
||||||
|
if v, ok := body["avatar_id"].(float64); ok {
|
||||||
|
id := int32(v)
|
||||||
|
avatarID = &id
|
||||||
|
}
|
||||||
|
|
||||||
|
dispName, _ := body["disp_name"].(string)
|
||||||
|
userDesc, _ := body["user_desc"].(string)
|
||||||
|
|
||||||
|
// 🔐 Хешируем пароль
|
||||||
|
passhashBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return PostUsers200JSONResponse{Success: ptr(false), Error: ptr("failed to hash password")}, nil
|
||||||
|
}
|
||||||
|
passhash := string(passhashBytes)
|
||||||
|
|
||||||
|
// Сохраняем в БД
|
||||||
|
_, err = s.db.CreateUser(ctx, db.CreateUserParams{
|
||||||
|
AvatarID: pgtype.Int4{
|
||||||
|
Int32: 0,
|
||||||
|
Valid: avatarID != nil,
|
||||||
|
},
|
||||||
|
Passhash: passhash,
|
||||||
|
Mail: pgtype.Text{
|
||||||
|
String: mail,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
Nickname: nickname,
|
||||||
|
DispName: pgtype.Text{
|
||||||
|
String: dispName,
|
||||||
|
Valid: dispName != "",
|
||||||
|
},
|
||||||
|
UserDesc: pgtype.Text{
|
||||||
|
String: userDesc,
|
||||||
|
Valid: userDesc != "",
|
||||||
|
},
|
||||||
|
CreationDate: pgtype.Timestamp{
|
||||||
|
Time: time.Now(),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
// Проверяем нарушение уникальности (например, дубль mail или nickname)
|
||||||
|
if err.Error() == "ERROR: duplicate key value violates unique constraint \"users_mail_key\"" ||
|
||||||
|
err.Error() == "ERROR: duplicate key value violates unique constraint \"users_nickname_key\"" {
|
||||||
|
return PostUsers200JSONResponse{
|
||||||
|
Success: ptr(false),
|
||||||
|
Error: ptr("user with this email or nickname already exists"),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return PostUsers200JSONResponse{Success: ptr(false), Error: ptr("database error")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем созданного пользователя (без passhash и mail!)
|
||||||
|
// Предположим, что у вас есть запрос GetUserByNickname или аналогичный
|
||||||
|
// Но проще — вернуть только ID и nickname
|
||||||
|
|
||||||
|
// ⚠️ Поскольку мы не знаем user_id, можно:
|
||||||
|
// а) добавить RETURNING в CreateUser (рекомендуется),
|
||||||
|
// б) сделать отдельный SELECT.
|
||||||
|
|
||||||
|
// Пока вернём минимальный ответ
|
||||||
|
userResp := User{
|
||||||
|
"nickname": nickname,
|
||||||
|
// "user_id" можно добавить, если обновите query.sql
|
||||||
|
}
|
||||||
|
|
||||||
|
return PostUsers200JSONResponse{
|
||||||
|
Success: ptr(true),
|
||||||
|
UserJson: &userResp,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
func (s Server) DeleteUsersUserId(ctx context.Context, req DeleteUsersUserIdRequestObject) (DeleteUsersUserIdResponseObject, error) {
|
||||||
|
userID, err := parseInt32(req.UserId)
|
||||||
|
if err != nil {
|
||||||
|
return DeleteUsersUserId200JSONResponse{Success: ptr(false), Error: ptr("invalid user_id")}, nil
|
||||||
|
}
|
||||||
|
err = s.db.DeleteUser(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
if err == pgx.ErrNoRows {
|
||||||
|
return DeleteUsersUserId200JSONResponse{Success: ptr(false), Error: ptr("user not found")}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return DeleteUsersUserId200JSONResponse{Success: ptr(true)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) GetUsersUserId(ctx context.Context, req GetUsersUserIdRequestObject) (GetUsersUserIdResponseObject, error) {
|
||||||
|
userID, err := parseInt32(req.UserId)
|
||||||
|
if err != nil {
|
||||||
|
return GetUsersUserId404Response{}, nil
|
||||||
|
}
|
||||||
|
user, err := s.db.GetUserByID(ctx, userID)
|
||||||
|
if err != nil {
|
||||||
|
if err == pgx.ErrNoRows {
|
||||||
|
return GetUsersUserId404Response{}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return GetUsersUserId200JSONResponse(mapUser(user)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) PatchUsersUserId(ctx context.Context, req PatchUsersUserIdRequestObject) (PatchUsersUserIdResponseObject, error) {
|
||||||
|
userID, err := parseInt32(req.UserId)
|
||||||
|
if err != nil {
|
||||||
|
return PatchUsersUserId200JSONResponse{Success: ptr(false), Error: ptr("invalid user_id")}, nil
|
||||||
|
}
|
||||||
|
if req.Body == nil {
|
||||||
|
return PatchUsersUserId200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
body := *req.Body
|
||||||
|
args := db.UpdateUserParams{
|
||||||
|
UserID: userID,
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := body["avatar_id"].(float64); ok {
|
||||||
|
args.AvatarID = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||||
|
// args.AvatarIDValid = true
|
||||||
|
}
|
||||||
|
if v, ok := body["disp_name"].(string); ok {
|
||||||
|
args.DispName = pgtype.Text{String: v, Valid: true}
|
||||||
|
// args.DispNameValid = true
|
||||||
|
}
|
||||||
|
if v, ok := body["user_desc"].(string); ok {
|
||||||
|
args.UserDesc = pgtype.Text{String: v, Valid: true}
|
||||||
|
// args.UserDescValid = true
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.db.UpdateUser(ctx, args)
|
||||||
|
if err != nil {
|
||||||
|
return PatchUsersUserId200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||||
|
}
|
||||||
|
return PatchUsersUserId200JSONResponse{Success: ptr(true)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) GetUsersUserIdReviews(ctx context.Context, req GetUsersUserIdReviewsRequestObject) (GetUsersUserIdReviewsResponseObject, error) {
|
||||||
|
userID, err := parseInt32(req.UserId)
|
||||||
|
if err != nil {
|
||||||
|
return GetUsersUserIdReviews200JSONResponse{}, nil
|
||||||
|
}
|
||||||
|
limit := int32(20)
|
||||||
|
offset := int32(0)
|
||||||
|
// if req.Params.Limit != nil {
|
||||||
|
// limit = int32(*req.Params.Limit)
|
||||||
|
// }
|
||||||
|
// if req.Params.Offset != nil {
|
||||||
|
// offset = int32(*req.Params.Offset)
|
||||||
|
// }
|
||||||
|
|
||||||
|
reviews, err := s.db.ListReviewsByUser(ctx, db.ListReviewsByUserParams{
|
||||||
|
UserID: userID,
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp []Review
|
||||||
|
for _, r := range reviews {
|
||||||
|
resp = append(resp, mapReview(r))
|
||||||
|
}
|
||||||
|
return GetUsersUserIdReviews200JSONResponse(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) DeleteUsersUserIdTitles(ctx context.Context, req DeleteUsersUserIdTitlesRequestObject) (DeleteUsersUserIdTitlesResponseObject, error) {
|
||||||
|
userID, err := parseInt32(req.UserId)
|
||||||
|
if err != nil {
|
||||||
|
return DeleteUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("invalid user_id")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if req.Params.TitleId != nil {
|
||||||
|
titleID, err := parseInt32(*req.Params.TitleId)
|
||||||
|
if err != nil {
|
||||||
|
return DeleteUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("invalid title_id")}, nil
|
||||||
|
}
|
||||||
|
err = s.db.DeleteUserTitle(ctx, db.DeleteUserTitleParams{
|
||||||
|
UserID: userID,
|
||||||
|
Column2: titleID,
|
||||||
|
})
|
||||||
|
if err != nil && err != pgx.ErrNoRows {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else {
|
||||||
|
// err = s.db.DeleteAllUserTitles(ctx, userID)
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
return DeleteUsersUserIdTitles200JSONResponse{Success: ptr(true)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) GetUsersUserIdTitles(ctx context.Context, req GetUsersUserIdTitlesRequestObject) (GetUsersUserIdTitlesResponseObject, error) {
|
||||||
|
userID, err := parseInt32(req.UserId)
|
||||||
|
if err != nil {
|
||||||
|
return GetUsersUserIdTitles200JSONResponse{}, nil
|
||||||
|
}
|
||||||
|
limit := int32(100)
|
||||||
|
offset := int32(0)
|
||||||
|
if req.Params.Limit != nil {
|
||||||
|
limit = int32(*req.Params.Limit)
|
||||||
|
}
|
||||||
|
if req.Params.Offset != nil {
|
||||||
|
offset = int32(*req.Params.Offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
titles, err := s.db.ListUserTitles(ctx, db.ListUserTitlesParams{
|
||||||
|
UserID: userID,
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp []UserTitle
|
||||||
|
for _, t := range titles {
|
||||||
|
resp = append(resp, mapUserTitle(t))
|
||||||
|
}
|
||||||
|
return GetUsersUserIdTitles200JSONResponse(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) PatchUsersUserIdTitles(ctx context.Context, req PatchUsersUserIdTitlesRequestObject) (PatchUsersUserIdTitlesResponseObject, error) {
|
||||||
|
// userID, err := parseInt32(req.UserId)
|
||||||
|
// if err != nil {
|
||||||
|
// return PatchUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("invalid user_id")}, nil
|
||||||
|
// }
|
||||||
|
// if req.Body == nil {
|
||||||
|
// return PatchUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// body := *req.Body
|
||||||
|
// titleID, ok := body["title_id"].(float64)
|
||||||
|
// if !ok {
|
||||||
|
// return PatchUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("title_id required")}, nil
|
||||||
|
// }
|
||||||
|
|
||||||
|
// args := db.UpdateUserTitleParams{
|
||||||
|
// UserID: userID,
|
||||||
|
// TitleID: int32(titleID),
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if v, ok := body["status"].(string); ok {
|
||||||
|
// args.Status = db.UsertitleStatusT(v)
|
||||||
|
// // args.StatusValid = true
|
||||||
|
// }
|
||||||
|
// if v, ok := body["rate"].(float64); ok {
|
||||||
|
// args.Rate = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||||
|
// // args.RateValid = true
|
||||||
|
// }
|
||||||
|
// if v, ok := body["review_id"].(float64); ok {
|
||||||
|
// args.ReviewID = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||||
|
// // args.ReviewIDValid = true
|
||||||
|
// }
|
||||||
|
|
||||||
|
// _, err = s.db.UpdateUserTitle(ctx, args)
|
||||||
|
// if err != nil {
|
||||||
|
// return PatchUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||||
|
// }
|
||||||
|
return PatchUsersUserIdTitles200JSONResponse{Success: ptr(true)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) PostUsersUserIdTitles(ctx context.Context, req PostUsersUserIdTitlesRequestObject) (PostUsersUserIdTitlesResponseObject, error) {
|
||||||
|
userID, err := parseInt32(req.UserId)
|
||||||
|
if err != nil {
|
||||||
|
return PostUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("invalid user_id")}, nil
|
||||||
|
}
|
||||||
|
if req.Body == nil {
|
||||||
|
return PostUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
body := req.Body
|
||||||
|
titleID, err := parseInt32(*body.TitleId)
|
||||||
|
if err != nil {
|
||||||
|
return PostUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr("invalid title_id")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
status := db.UsertitleStatusT("planned")
|
||||||
|
if body.Status != nil {
|
||||||
|
status = db.UsertitleStatusT(*body.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.db.CreateUserTitle(ctx, db.CreateUserTitleParams{
|
||||||
|
UserID: userID,
|
||||||
|
TitleID: titleID,
|
||||||
|
Status: status,
|
||||||
|
Rate: pgtype.Int4{Valid: false},
|
||||||
|
ReviewID: pgtype.Int4{Valid: false},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return PostUsersUserIdTitles200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||||
|
}
|
||||||
|
return PostUsersUserIdTitles200JSONResponse{Success: ptr(true)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) GetTags(ctx context.Context, req GetTagsRequestObject) (GetTagsResponseObject, error) {
|
||||||
|
limit := int32(100)
|
||||||
|
offset := int32(0)
|
||||||
|
if req.Params.Limit != nil {
|
||||||
|
limit = int32(*req.Params.Limit)
|
||||||
|
}
|
||||||
|
if req.Params.Offset != nil {
|
||||||
|
offset = int32(*req.Params.Offset)
|
||||||
|
}
|
||||||
|
tags, err := s.db.ListTags(ctx, db.ListTagsParams{Limit: limit, Offset: offset})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var resp []Tag
|
||||||
|
for _, t := range tags {
|
||||||
|
resp = append(resp, Tag{
|
||||||
|
"tag_id": t.TagID,
|
||||||
|
"tag_names": jsonbToInterface(t.TagNames),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return GetTags200JSONResponse(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) GetTitle(ctx context.Context, req GetTitleRequestObject) (GetTitleResponseObject, error) {
|
||||||
|
limit := int32(50)
|
||||||
|
offset := int32(0)
|
||||||
|
if req.Params.Limit != nil {
|
||||||
|
limit = int32(*req.Params.Limit)
|
||||||
|
}
|
||||||
|
if req.Params.Offset != nil {
|
||||||
|
offset = int32(*req.Params.Offset)
|
||||||
|
}
|
||||||
|
titles, err := s.db.ListTitles(ctx, db.ListTitlesParams{Limit: limit, Offset: offset})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var resp []Title
|
||||||
|
for _, t := range titles {
|
||||||
|
resp = append(resp, mapTitle(t))
|
||||||
|
}
|
||||||
|
return GetTitle200JSONResponse(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) GetTitleTitleId(ctx context.Context, req GetTitleTitleIdRequestObject) (GetTitleTitleIdResponseObject, error) {
|
||||||
|
titleID, err := parseInt32(req.TitleId)
|
||||||
|
if err != nil {
|
||||||
|
return GetTitleTitleId404Response{}, nil
|
||||||
|
}
|
||||||
|
title, err := s.db.GetTitleByID(ctx, titleID)
|
||||||
|
if err != nil {
|
||||||
|
if err == pgx.ErrNoRows {
|
||||||
|
return GetTitleTitleId404Response{}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return GetTitleTitleId200JSONResponse(mapTitle(title)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) PatchTitleTitleId(ctx context.Context, req PatchTitleTitleIdRequestObject) (PatchTitleTitleIdResponseObject, error) {
|
||||||
|
titleID, err := parseInt32(req.TitleId)
|
||||||
|
if err != nil {
|
||||||
|
return PatchTitleTitleId200JSONResponse{Success: ptr(false), Error: ptr("invalid title_id")}, nil
|
||||||
|
}
|
||||||
|
if req.Body == nil {
|
||||||
|
return PatchTitleTitleId200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
body := *req.Body
|
||||||
|
args := db.UpdateTitleParams{
|
||||||
|
TitleID: titleID,
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := body["title_names"].(map[string]interface{}); ok {
|
||||||
|
data, _ := json.Marshal(v)
|
||||||
|
args.TitleNames = data
|
||||||
|
// args.TitleNamesValid = true
|
||||||
|
}
|
||||||
|
if v, ok := body["studio_id"].(float64); ok {
|
||||||
|
args.StudioID = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||||
|
// args.StudioIDValid = true
|
||||||
|
}
|
||||||
|
if v, ok := body["poster_id"].(float64); ok {
|
||||||
|
args.PosterID = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||||
|
// args.PosterIDValid = true
|
||||||
|
}
|
||||||
|
// if v, ok := body["title_status"].(string); ok {
|
||||||
|
// args.TitleStatus = db.NullTitleStatusT(v)
|
||||||
|
// // args.TitleStatusValid = true
|
||||||
|
// }
|
||||||
|
if v, ok := body["release_year"].(float64); ok {
|
||||||
|
args.ReleaseYear = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||||
|
// args.ReleaseYearValid = true
|
||||||
|
}
|
||||||
|
if v, ok := body["episodes_aired"].(float64); ok {
|
||||||
|
args.EpisodesAired = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||||
|
// args.EpisodesAiredValid = true
|
||||||
|
}
|
||||||
|
if v, ok := body["episodes_all"].(float64); ok {
|
||||||
|
args.EpisodesAll = pgtype.Int4{Int32: int32(v), Valid: true}
|
||||||
|
// args.EpisodesAllValid = true
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.db.UpdateTitle(ctx, args)
|
||||||
|
if err != nil {
|
||||||
|
return PatchTitleTitleId200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||||
|
}
|
||||||
|
return PatchTitleTitleId200JSONResponse{Success: ptr(true)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) GetTitleTitleIdReviews(ctx context.Context, req GetTitleTitleIdReviewsRequestObject) (GetTitleTitleIdReviewsResponseObject, error) {
|
||||||
|
titleID, err := parseInt32(req.TitleId)
|
||||||
|
if err != nil {
|
||||||
|
return GetTitleTitleIdReviews200JSONResponse{}, nil
|
||||||
|
}
|
||||||
|
limit := int32(20)
|
||||||
|
offset := int32(0)
|
||||||
|
if req.Params.Limit != nil {
|
||||||
|
limit = int32(*req.Params.Limit)
|
||||||
|
}
|
||||||
|
if req.Params.Offset != nil {
|
||||||
|
offset = int32(*req.Params.Offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
reviews, err := s.db.ListReviewsByTitle(ctx, db.ListReviewsByTitleParams{
|
||||||
|
TitleID: titleID,
|
||||||
|
Limit: limit,
|
||||||
|
Offset: offset,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp []Review
|
||||||
|
for _, r := range reviews {
|
||||||
|
resp = append(resp, mapReview(r))
|
||||||
|
}
|
||||||
|
return GetTitleTitleIdReviews200JSONResponse(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) PostReviews(ctx context.Context, req PostReviewsRequestObject) (PostReviewsResponseObject, error) {
|
||||||
|
if req.Body == nil {
|
||||||
|
return PostReviews200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
body := *req.Body
|
||||||
|
userID, ok1 := body["user_id"].(float64)
|
||||||
|
titleID, ok2 := body["title_id"].(float64)
|
||||||
|
reviewText, ok3 := body["review_text"].(string)
|
||||||
|
if !ok1 || !ok2 || !ok3 {
|
||||||
|
return PostReviews200JSONResponse{Success: ptr(false), Error: ptr("user_id, title_id, review_text required")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var imageIDs []int32
|
||||||
|
if ids, ok := body["image_ids"].([]interface{}); ok {
|
||||||
|
for _, id := range ids {
|
||||||
|
if f, ok := id.(float64); ok {
|
||||||
|
imageIDs = append(imageIDs, int32(f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := s.db.CreateReview(ctx, db.CreateReviewParams{
|
||||||
|
UserID: int32(userID),
|
||||||
|
TitleID: int32(titleID),
|
||||||
|
ImageIds: imageIDs,
|
||||||
|
ReviewText: reviewText,
|
||||||
|
CreationDate: pgtype.Timestamp{Time: time.Now(), Valid: true},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return PostReviews200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return PostReviews200JSONResponse{Success: ptr(true)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) DeleteReviewsReviewId(ctx context.Context, req DeleteReviewsReviewIdRequestObject) (DeleteReviewsReviewIdResponseObject, error) {
|
||||||
|
reviewID, err := parseInt32(req.ReviewId)
|
||||||
|
if err != nil {
|
||||||
|
return DeleteReviewsReviewId200JSONResponse{Success: ptr(false), Error: ptr("invalid review_id")}, nil
|
||||||
|
}
|
||||||
|
err = s.db.DeleteReview(ctx, reviewID)
|
||||||
|
if err != nil {
|
||||||
|
if err == pgx.ErrNoRows {
|
||||||
|
return DeleteReviewsReviewId200JSONResponse{Success: ptr(false), Error: ptr("review not found")}, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return DeleteReviewsReviewId200JSONResponse{Success: ptr(true)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) PatchReviewsReviewId(ctx context.Context, req PatchReviewsReviewIdRequestObject) (PatchReviewsReviewIdResponseObject, error) {
|
||||||
|
reviewID, err := parseInt32(req.ReviewId)
|
||||||
|
if err != nil {
|
||||||
|
return PatchReviewsReviewId200JSONResponse{Success: ptr(false), Error: ptr("invalid review_id")}, nil
|
||||||
|
}
|
||||||
|
if req.Body == nil {
|
||||||
|
return PatchReviewsReviewId200JSONResponse{Success: ptr(false), Error: ptr("empty body")}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
body := *req.Body
|
||||||
|
args := db.UpdateReviewParams{
|
||||||
|
ReviewID: reviewID,
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := body["review_text"].(string); ok {
|
||||||
|
args.ReviewText = pgtype.Text{String: v, Valid: true}
|
||||||
|
// args.ReviewTextValid = true
|
||||||
|
}
|
||||||
|
if ids, ok := body["image_ids"].([]interface{}); ok {
|
||||||
|
var imageIDs []int32
|
||||||
|
for _, id := range ids {
|
||||||
|
if f, ok := id.(float64); ok {
|
||||||
|
imageIDs = append(imageIDs, int32(f))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
args.ImageIds = imageIDs
|
||||||
|
// args.ImageIdsValid = true
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.db.UpdateReview(ctx, args)
|
||||||
|
if err != nil {
|
||||||
|
return PatchReviewsReviewId200JSONResponse{Success: ptr(false), Error: ptr(err.Error())}, nil
|
||||||
|
}
|
||||||
|
return PatchReviewsReviewId200JSONResponse{Success: ptr(true)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// —————————————————————————————————————————————
|
||||||
|
// МАППИНГИ
|
||||||
|
// —————————————————————————————————————————————
|
||||||
|
|
||||||
|
func mapUser(u db.Users) User {
|
||||||
|
return User{
|
||||||
|
"user_id": u.UserID,
|
||||||
|
"avatar_id": pgInt4ToPtr(u.AvatarID),
|
||||||
|
"nickname": u.Nickname,
|
||||||
|
"disp_name": pgTextToPtr(u.DispName),
|
||||||
|
"user_desc": pgTextToPtr(u.UserDesc),
|
||||||
|
"creation_date": u.CreationDate.Time,
|
||||||
|
// mail и passhash НЕ возвращаем!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapTitle(t db.Titles) Title {
|
||||||
|
var releaseSeason interface{}
|
||||||
|
if t.ReleaseSeason.Valid {
|
||||||
|
releaseSeason = string(t.ReleaseSeason.ReleaseSeasonT)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Title{
|
||||||
|
"title_id": t.TitleID,
|
||||||
|
"title_names": jsonbToInterface(t.TitleNames),
|
||||||
|
"studio_id": t.StudioID,
|
||||||
|
"poster_id": pgInt4ToPtr(t.PosterID),
|
||||||
|
"signal_ids": t.SignalIds,
|
||||||
|
"title_status": string(t.TitleStatus),
|
||||||
|
"rating": pgFloat8ToPtr(t.Rating),
|
||||||
|
"rating_count": pgInt4ToPtr(t.RatingCount),
|
||||||
|
"release_year": pgInt4ToPtr(t.ReleaseYear),
|
||||||
|
"release_season": releaseSeason,
|
||||||
|
"season": pgInt4ToPtr(t.Season),
|
||||||
|
"episodes_aired": pgInt4ToPtr(t.EpisodesAired),
|
||||||
|
"episodes_all": pgInt4ToPtr(t.EpisodesAll),
|
||||||
|
"episodes_len": jsonbToInterface(t.EpisodesLen),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapReview(r db.Reviews) Review {
|
||||||
|
return Review{
|
||||||
|
"review_id": r.ReviewID,
|
||||||
|
"user_id": r.UserID,
|
||||||
|
"title_id": r.TitleID,
|
||||||
|
"image_ids": r.ImageIds,
|
||||||
|
"review_text": r.ReviewText,
|
||||||
|
"creation_date": r.CreationDate.Time,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapUserTitle(ut db.Usertitles) UserTitle {
|
||||||
|
return UserTitle{
|
||||||
|
"usertitle_id": ut.UsertitleID,
|
||||||
|
"user_id": ut.UserID,
|
||||||
|
"title_id": ut.TitleID,
|
||||||
|
"status": string(ut.Status),
|
||||||
|
"rate": pgInt4ToPtr(ut.Rate),
|
||||||
|
"review_id": pgInt4ToPtr(ut.ReviewID),
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue