From 5c363589d80535fec81734533c08d0cd175fb192 Mon Sep 17 00:00:00 2001 From: AzenKain Date: Thu, 16 Apr 2026 12:39:05 +0700 Subject: [PATCH] UPDATE: Change type response --- db/migrations/000005_verifications.up.sql | 13 +- db/query/verification.sql | 112 +++++++++++-- internal/dtos/response/user.go | 8 + internal/dtos/response/verification.go | 4 +- internal/gen/sqlc/users.sql.go | 9 +- internal/gen/sqlc/verification.sql.go | 154 ++++++++++++++---- internal/models/user.go | 21 ++- internal/models/verification.go | 26 ++- .../repositories/verificationRepository.go | 48 +++++- internal/services/verificationService.go | 4 +- sqlc.yaml | 6 +- 11 files changed, 336 insertions(+), 69 deletions(-) diff --git a/db/migrations/000005_verifications.up.sql b/db/migrations/000005_verifications.up.sql index 08aa94b..bcaa359 100644 --- a/db/migrations/000005_verifications.up.sql +++ b/db/migrations/000005_verifications.up.sql @@ -21,9 +21,20 @@ CREATE INDEX idx_user_verifications_user_type ON user_verifications(user_id, verify_type) WHERE is_deleted = false; +CREATE INDEX idx_user_verifications_user_created +ON user_verifications(user_id, created_at DESC) +WHERE is_deleted = false; + +CREATE INDEX idx_user_verifications_reviewed_by +ON user_verifications(reviewed_by) +WHERE is_deleted = false;; + CREATE INDEX idx_user_verifications_status_created ON user_verifications(status, created_at DESC) WHERE is_deleted = false; CREATE INDEX idx_verification_medias_media_id -ON verification_medias(media_id); \ No newline at end of file +ON verification_medias(media_id); + +CREATE INDEX idx_verification_medias_verification_id +ON verification_medias(verification_id); diff --git a/db/query/verification.sql b/db/query/verification.sql index 726450e..6694618 100644 --- a/db/query/verification.sql +++ b/db/query/verification.sql @@ -1,23 +1,61 @@ -- name: CreateUserVerification :one -INSERT INTO user_verifications ( - user_id, verify_type, content -) VALUES ( - $1, $2, $3 +WITH inserted_uv AS ( + INSERT INTO user_verifications ( + user_id, verify_type, content + ) VALUES ( + $1, $2, $3 + ) + RETURNING * ) -RETURNING *; +SELECT + i.id, + i.verify_type, + i.content, + i.is_deleted, + i.status, + i.review_note, + i.reviewed_at, + i.created_at, + json_build_object( + 'id', u.id, + 'email', u.email, + 'display_name', up.display_name, + 'full_name', up.full_name, + 'avatar_url', up.avatar_url + )::json AS user, + NULL::json AS reviewer, -- Khi mới tạo thì reviewer luôn null + '[]'::json AS medias +FROM inserted_uv i +JOIN users u ON i.user_id = u.id +LEFT JOIN user_profiles up ON u.id = up.user_id; + -- name: GetUserVerificationByID :one SELECT uv.id, - uv.user_id, uv.verify_type, uv.content, uv.is_deleted, uv.status, - uv.reviewed_by, uv.review_note, uv.reviewed_at, uv.created_at, + json_build_object( + 'id', u.id, + 'email', u.email, + 'display_name', up.display_name, + 'full_name', up.full_name, + 'avatar_url', up.avatar_url + )::json AS user, + CASE WHEN uv.reviewed_by IS NOT NULL THEN + json_build_object( + 'id', ru.id, + 'email', ru.email, + 'display_name', rup.display_name, + 'full_name', rup.full_name, + 'avatar_url', rup.avatar_url + )::json + ELSE NULL::json END AS reviewer, ( SELECT COALESCE( json_agg( @@ -38,20 +76,39 @@ SELECT WHERE vm.verification_id = uv.id ) AS medias FROM user_verifications uv +JOIN users u ON uv.user_id = u.id +LEFT JOIN user_profiles up ON u.id = up.user_id +LEFT JOIN users ru ON uv.reviewed_by = ru.id +LEFT JOIN user_profiles rup ON ru.id = rup.user_id WHERE uv.id = $1 AND uv.is_deleted = false; + -- name: GetUserVerifications :many SELECT uv.id, - uv.user_id, uv.verify_type, uv.content, uv.is_deleted, uv.status, - uv.reviewed_by, - uv.reviewed_at, - uv.review_note, + uv.review_note, + uv.reviewed_at, uv.created_at, + json_build_object( + 'id', u.id, + 'email', u.email, + 'display_name', up.display_name, + 'full_name', up.full_name, + 'avatar_url', up.avatar_url + )::json AS user, + CASE WHEN uv.reviewed_by IS NOT NULL THEN + json_build_object( + 'id', ru.id, + 'email', ru.email, + 'display_name', rup.display_name, + 'full_name', rup.full_name, + 'avatar_url', rup.avatar_url + )::json + ELSE NULL::json END AS reviewer, ( SELECT COALESCE( json_agg( @@ -72,9 +129,14 @@ SELECT WHERE vm.verification_id = uv.id ) AS medias FROM user_verifications uv +JOIN users u ON uv.user_id = u.id +LEFT JOIN user_profiles up ON u.id = up.user_id +LEFT JOIN users ru ON uv.reviewed_by = ru.id +LEFT JOIN user_profiles rup ON ru.id = rup.user_id WHERE uv.user_id = $1 AND uv.is_deleted = false ORDER BY uv.created_at DESC; + -- name: UpdateUserVerificationStatus :exec UPDATE user_verifications SET @@ -84,15 +146,18 @@ SET reviewed_at = now() WHERE id = $1 AND is_deleted = false; + -- name: DeleteUserVerification :exec UPDATE user_verifications SET is_deleted = true WHERE id = $1; + -- name: DeleteVerificationMedia :exec DELETE FROM verification_medias WHERE verification_id = $1 AND media_id = $2; + -- name: CreateVerificationMedia :exec INSERT INTO verification_medias ( verification_id, media_id @@ -100,23 +165,39 @@ INSERT INTO verification_medias ( SELECT $1, unnest($2::uuid[]) ON CONFLICT DO NOTHING; + -- name: BulkDeleteVerificationMediaByMediaId :many DELETE FROM verification_medias WHERE media_id = $1 RETURNING verification_id; + -- name: SearchUserVerifications :many SELECT uv.id, - uv.user_id, uv.verify_type, uv.content, uv.is_deleted, uv.status, - uv.reviewed_by, uv.review_note, uv.reviewed_at, uv.created_at, + json_build_object( + 'id', u.id, + 'email', u.email, + 'display_name', up.display_name, + 'full_name', up.full_name, + 'avatar_url', up.avatar_url + )::json AS user, + CASE WHEN uv.reviewed_by IS NOT NULL THEN + json_build_object( + 'id', ru.id, + 'email', ru.email, + 'display_name', rup.display_name, + 'full_name', rup.full_name, + 'avatar_url', rup.avatar_url + )::json + ELSE NULL::json END AS reviewer, ( SELECT COALESCE( json_agg( @@ -137,6 +218,10 @@ SELECT WHERE vm.verification_id = uv.id ) AS medias FROM user_verifications uv +JOIN users u ON uv.user_id = u.id +LEFT JOIN user_profiles up ON u.id = up.user_id +LEFT JOIN users ru ON uv.reviewed_by = ru.id +LEFT JOIN user_profiles rup ON ru.id = rup.user_id WHERE uv.is_deleted = false AND (sqlc.narg('user_ids')::uuid[] IS NULL OR uv.user_id = ANY(sqlc.narg('user_ids')::uuid[])) @@ -167,6 +252,7 @@ ORDER BY LIMIT sqlc.arg('limit') OFFSET sqlc.arg('offset'); + -- name: CountUserVerifications :one SELECT count(*) FROM user_verifications uv diff --git a/internal/dtos/response/user.go b/internal/dtos/response/user.go index ff0f6f5..62a8e52 100644 --- a/internal/dtos/response/user.go +++ b/internal/dtos/response/user.go @@ -13,6 +13,14 @@ type UserResponse struct { Roles []*RoleSimpleResponse `json:"roles"` } +type UserSimpleResponse struct { + ID string `json:"id"` + Email string `json:"email"` + DisplayName string `json:"display_name"` + FullName string `json:"full_name"` + AvatarUrl string `json:"avatar_url"` +} + type UserProfileSimpleResponse struct { DisplayName string `json:"display_name"` FullName string `json:"full_name"` diff --git a/internal/dtos/response/verification.go b/internal/dtos/response/verification.go index e901585..222bf28 100644 --- a/internal/dtos/response/verification.go +++ b/internal/dtos/response/verification.go @@ -4,11 +4,11 @@ import "time" type UserVerificationResponse struct { ID string `json:"id"` - UserID string `json:"user_id"` + User *UserSimpleResponse `json:"user"` VerifyType string `json:"verify_type"` Content string `json:"content"` Status string `json:"status"` - ReviewedBy string `json:"reviewed_by"` + Reviewer *UserSimpleResponse `json:"reviewer"` ReviewNote string `json:"review_note"` ReviewedAt *time.Time `json:"reviewed_at"` CreatedAt *time.Time `json:"created_at"` diff --git a/internal/gen/sqlc/users.sql.go b/internal/gen/sqlc/users.sql.go index 2d94a82..658e074 100644 --- a/internal/gen/sqlc/users.sql.go +++ b/internal/gen/sqlc/users.sql.go @@ -7,6 +7,7 @@ package sqlc import ( "context" + "encoding/json" "github.com/jackc/pgx/v5/pgtype" ) @@ -173,7 +174,7 @@ type GetUserByEmailRow struct { IsDeleted bool `json:"is_deleted"` CreatedAt pgtype.Timestamptz `json:"created_at"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` - Profile []byte `json:"profile"` + Profile json.RawMessage `json:"profile"` Roles []byte `json:"roles"` } @@ -245,7 +246,7 @@ type GetUserByIDRow struct { IsDeleted bool `json:"is_deleted"` CreatedAt pgtype.Timestamptz `json:"created_at"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` - Profile []byte `json:"profile"` + Profile json.RawMessage `json:"profile"` Roles []byte `json:"roles"` } @@ -318,7 +319,7 @@ type GetUserByIDWithoutDeletedRow struct { IsDeleted bool `json:"is_deleted"` CreatedAt pgtype.Timestamptz `json:"created_at"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` - Profile []byte `json:"profile"` + Profile json.RawMessage `json:"profile"` Roles []byte `json:"roles"` } @@ -457,7 +458,7 @@ type SearchUsersRow struct { IsDeleted bool `json:"is_deleted"` CreatedAt pgtype.Timestamptz `json:"created_at"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` - Profile []byte `json:"profile"` + Profile json.RawMessage `json:"profile"` Roles []byte `json:"roles"` } diff --git a/internal/gen/sqlc/verification.sql.go b/internal/gen/sqlc/verification.sql.go index 698aeef..069b5a2 100644 --- a/internal/gen/sqlc/verification.sql.go +++ b/internal/gen/sqlc/verification.sql.go @@ -87,12 +87,35 @@ func (q *Queries) CountUserVerifications(ctx context.Context, arg CountUserVerif } const createUserVerification = `-- name: CreateUserVerification :one -INSERT INTO user_verifications ( - user_id, verify_type, content -) VALUES ( - $1, $2, $3 +WITH inserted_uv AS ( + INSERT INTO user_verifications ( + user_id, verify_type, content + ) VALUES ( + $1, $2, $3 + ) + RETURNING id, user_id, verify_type, content, is_deleted, status, reviewed_by, review_note, reviewed_at, created_at ) -RETURNING id, user_id, verify_type, content, is_deleted, status, reviewed_by, review_note, reviewed_at, created_at +SELECT + i.id, + i.verify_type, + i.content, + i.is_deleted, + i.status, + i.review_note, + i.reviewed_at, + i.created_at, + json_build_object( + 'id', u.id, + 'email', u.email, + 'display_name', up.display_name, + 'full_name', up.full_name, + 'avatar_url', up.avatar_url + )::json AS user, + NULL::json AS reviewer, -- Khi mới tạo thì reviewer luôn null + '[]'::json AS medias +FROM inserted_uv i +JOIN users u ON i.user_id = u.id +LEFT JOIN user_profiles up ON u.id = up.user_id ` type CreateUserVerificationParams struct { @@ -101,20 +124,35 @@ type CreateUserVerificationParams struct { Content pgtype.Text `json:"content"` } -func (q *Queries) CreateUserVerification(ctx context.Context, arg CreateUserVerificationParams) (UserVerification, error) { +type CreateUserVerificationRow struct { + ID pgtype.UUID `json:"id"` + VerifyType int16 `json:"verify_type"` + Content pgtype.Text `json:"content"` + IsDeleted bool `json:"is_deleted"` + Status int16 `json:"status"` + ReviewNote pgtype.Text `json:"review_note"` + ReviewedAt pgtype.Timestamptz `json:"reviewed_at"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + User []byte `json:"user"` + Reviewer []byte `json:"reviewer"` + Medias []byte `json:"medias"` +} + +func (q *Queries) CreateUserVerification(ctx context.Context, arg CreateUserVerificationParams) (CreateUserVerificationRow, error) { row := q.db.QueryRow(ctx, createUserVerification, arg.UserID, arg.VerifyType, arg.Content) - var i UserVerification + var i CreateUserVerificationRow err := row.Scan( &i.ID, - &i.UserID, &i.VerifyType, &i.Content, &i.IsDeleted, &i.Status, - &i.ReviewedBy, &i.ReviewNote, &i.ReviewedAt, &i.CreatedAt, + &i.User, + &i.Reviewer, + &i.Medias, ) return i, err } @@ -166,15 +204,29 @@ func (q *Queries) DeleteVerificationMedia(ctx context.Context, arg DeleteVerific const getUserVerificationByID = `-- name: GetUserVerificationByID :one SELECT uv.id, - uv.user_id, uv.verify_type, uv.content, uv.is_deleted, uv.status, - uv.reviewed_by, uv.review_note, uv.reviewed_at, uv.created_at, + json_build_object( + 'id', u.id, + 'email', u.email, + 'display_name', up.display_name, + 'full_name', up.full_name, + 'avatar_url', up.avatar_url + )::json AS user, + CASE WHEN uv.reviewed_by IS NOT NULL THEN + json_build_object( + 'id', ru.id, + 'email', ru.email, + 'display_name', rup.display_name, + 'full_name', rup.full_name, + 'avatar_url', rup.avatar_url + )::json + ELSE NULL::json END AS reviewer, ( SELECT COALESCE( json_agg( @@ -195,20 +247,24 @@ SELECT WHERE vm.verification_id = uv.id ) AS medias FROM user_verifications uv +JOIN users u ON uv.user_id = u.id +LEFT JOIN user_profiles up ON u.id = up.user_id +LEFT JOIN users ru ON uv.reviewed_by = ru.id +LEFT JOIN user_profiles rup ON ru.id = rup.user_id WHERE uv.id = $1 AND uv.is_deleted = false ` type GetUserVerificationByIDRow struct { ID pgtype.UUID `json:"id"` - UserID pgtype.UUID `json:"user_id"` VerifyType int16 `json:"verify_type"` Content pgtype.Text `json:"content"` IsDeleted bool `json:"is_deleted"` Status int16 `json:"status"` - ReviewedBy pgtype.UUID `json:"reviewed_by"` ReviewNote pgtype.Text `json:"review_note"` ReviewedAt pgtype.Timestamptz `json:"reviewed_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` + User []byte `json:"user"` + Reviewer []byte `json:"reviewer"` Medias []byte `json:"medias"` } @@ -217,15 +273,15 @@ func (q *Queries) GetUserVerificationByID(ctx context.Context, id pgtype.UUID) ( var i GetUserVerificationByIDRow err := row.Scan( &i.ID, - &i.UserID, &i.VerifyType, &i.Content, &i.IsDeleted, &i.Status, - &i.ReviewedBy, &i.ReviewNote, &i.ReviewedAt, &i.CreatedAt, + &i.User, + &i.Reviewer, &i.Medias, ) return i, err @@ -234,15 +290,29 @@ func (q *Queries) GetUserVerificationByID(ctx context.Context, id pgtype.UUID) ( const getUserVerifications = `-- name: GetUserVerifications :many SELECT uv.id, - uv.user_id, uv.verify_type, uv.content, uv.is_deleted, uv.status, - uv.reviewed_by, - uv.reviewed_at, - uv.review_note, + uv.review_note, + uv.reviewed_at, uv.created_at, + json_build_object( + 'id', u.id, + 'email', u.email, + 'display_name', up.display_name, + 'full_name', up.full_name, + 'avatar_url', up.avatar_url + )::json AS user, + CASE WHEN uv.reviewed_by IS NOT NULL THEN + json_build_object( + 'id', ru.id, + 'email', ru.email, + 'display_name', rup.display_name, + 'full_name', rup.full_name, + 'avatar_url', rup.avatar_url + )::json + ELSE NULL::json END AS reviewer, ( SELECT COALESCE( json_agg( @@ -263,21 +333,25 @@ SELECT WHERE vm.verification_id = uv.id ) AS medias FROM user_verifications uv +JOIN users u ON uv.user_id = u.id +LEFT JOIN user_profiles up ON u.id = up.user_id +LEFT JOIN users ru ON uv.reviewed_by = ru.id +LEFT JOIN user_profiles rup ON ru.id = rup.user_id WHERE uv.user_id = $1 AND uv.is_deleted = false ORDER BY uv.created_at DESC ` type GetUserVerificationsRow struct { ID pgtype.UUID `json:"id"` - UserID pgtype.UUID `json:"user_id"` VerifyType int16 `json:"verify_type"` Content pgtype.Text `json:"content"` IsDeleted bool `json:"is_deleted"` Status int16 `json:"status"` - ReviewedBy pgtype.UUID `json:"reviewed_by"` - ReviewedAt pgtype.Timestamptz `json:"reviewed_at"` ReviewNote pgtype.Text `json:"review_note"` + ReviewedAt pgtype.Timestamptz `json:"reviewed_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` + User []byte `json:"user"` + Reviewer []byte `json:"reviewer"` Medias []byte `json:"medias"` } @@ -292,15 +366,15 @@ func (q *Queries) GetUserVerifications(ctx context.Context, userID pgtype.UUID) var i GetUserVerificationsRow if err := rows.Scan( &i.ID, - &i.UserID, &i.VerifyType, &i.Content, &i.IsDeleted, &i.Status, - &i.ReviewedBy, - &i.ReviewedAt, &i.ReviewNote, + &i.ReviewedAt, &i.CreatedAt, + &i.User, + &i.Reviewer, &i.Medias, ); err != nil { return nil, err @@ -316,15 +390,29 @@ func (q *Queries) GetUserVerifications(ctx context.Context, userID pgtype.UUID) const searchUserVerifications = `-- name: SearchUserVerifications :many SELECT uv.id, - uv.user_id, uv.verify_type, uv.content, uv.is_deleted, uv.status, - uv.reviewed_by, uv.review_note, uv.reviewed_at, uv.created_at, + json_build_object( + 'id', u.id, + 'email', u.email, + 'display_name', up.display_name, + 'full_name', up.full_name, + 'avatar_url', up.avatar_url + )::json AS user, + CASE WHEN uv.reviewed_by IS NOT NULL THEN + json_build_object( + 'id', ru.id, + 'email', ru.email, + 'display_name', rup.display_name, + 'full_name', rup.full_name, + 'avatar_url', rup.avatar_url + )::json + ELSE NULL::json END AS reviewer, ( SELECT COALESCE( json_agg( @@ -345,6 +433,10 @@ SELECT WHERE vm.verification_id = uv.id ) AS medias FROM user_verifications uv +JOIN users u ON uv.user_id = u.id +LEFT JOIN user_profiles up ON u.id = up.user_id +LEFT JOIN users ru ON uv.reviewed_by = ru.id +LEFT JOIN user_profiles rup ON ru.id = rup.user_id WHERE uv.is_deleted = false AND ($1::uuid[] IS NULL OR uv.user_id = ANY($1::uuid[])) @@ -392,15 +484,15 @@ type SearchUserVerificationsParams struct { type SearchUserVerificationsRow struct { ID pgtype.UUID `json:"id"` - UserID pgtype.UUID `json:"user_id"` VerifyType int16 `json:"verify_type"` Content pgtype.Text `json:"content"` IsDeleted bool `json:"is_deleted"` Status int16 `json:"status"` - ReviewedBy pgtype.UUID `json:"reviewed_by"` ReviewNote pgtype.Text `json:"review_note"` ReviewedAt pgtype.Timestamptz `json:"reviewed_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` + User []byte `json:"user"` + Reviewer []byte `json:"reviewer"` Medias []byte `json:"medias"` } @@ -427,15 +519,15 @@ func (q *Queries) SearchUserVerifications(ctx context.Context, arg SearchUserVer var i SearchUserVerificationsRow if err := rows.Scan( &i.ID, - &i.UserID, &i.VerifyType, &i.Content, &i.IsDeleted, &i.Status, - &i.ReviewedBy, &i.ReviewNote, &i.ReviewedAt, &i.CreatedAt, + &i.User, + &i.Reviewer, &i.Medias, ); err != nil { return nil, err diff --git a/internal/models/user.go b/internal/models/user.go index 0ec84cf..1a154bc 100644 --- a/internal/models/user.go +++ b/internal/models/user.go @@ -20,9 +20,26 @@ type UserEntity struct { UpdatedAt *time.Time `json:"updated_at"` Roles []*RoleSimple `json:"roles"` } +type UserSimpleEntity struct { + ID string `json:"id"` + Email string `json:"email"` + DisplayName string `json:"display_name"` + FullName string `json:"full_name"` + AvatarUrl string `json:"avatar_url"` +} + +func (u *UserSimpleEntity) ToResponse() *response.UserSimpleResponse { + return &response.UserSimpleResponse{ + ID: u.ID, + Email: u.Email, + DisplayName: u.DisplayName, + FullName: u.FullName, + AvatarUrl: u.AvatarUrl, + } +} func (u *UserEntity) ParseRoles(data []byte) error { - if len(data) == 0 { + if len(data) == 0 || string(data) == "null" { u.Roles = []*RoleSimple{} return nil } @@ -30,7 +47,7 @@ func (u *UserEntity) ParseRoles(data []byte) error { } func (u *UserEntity) ParseProfile(data []byte) error { - if len(data) == 0 { + if len(data) == 0 || string(data) == "null" { u.Profile = &UserProfileSimple{} return nil } diff --git a/internal/models/verification.go b/internal/models/verification.go index ea94aad..b987c81 100644 --- a/internal/models/verification.go +++ b/internal/models/verification.go @@ -9,12 +9,12 @@ import ( type UserVerificationEntity struct { ID string `json:"id"` - UserID string `json:"user_id"` + User *UserSimpleEntity `json:"user"` VerifyType constants.VerifyType `json:"verify_type"` Content string `json:"content"` IsDeleted bool `json:"is_deleted"` Status constants.StatusType `json:"status"` - ReviewedBy string `json:"reviewed_by"` + Reviewer *UserSimpleEntity `json:"reviewer"` ReviewNote string `json:"review_note"` ReviewedAt *time.Time `json:"reviewed_at"` CreatedAt *time.Time `json:"created_at"` @@ -29,13 +29,29 @@ type UserVerificationStorageEntity struct { } func (u *UserVerificationEntity) ParseMedia(data []byte) error { - if len(data) == 0 { + if len(data) == 0 || string(data) == "null" { u.Media = []*MediaSimpleEntity{} return nil } return json.Unmarshal(data, &u.Media) } +func (u *UserVerificationEntity) ParseUser(data []byte) error { + if len(data) == 0 || string(data) == "null" { + u.User = nil + return nil + } + return json.Unmarshal(data, &u.User) +} + +func (u *UserVerificationEntity) ParseReviewer(data []byte) error { + if len(data) == 0 || string(data) == "null" { + u.Reviewer = nil + return nil + } + return json.Unmarshal(data, &u.Reviewer) +} + func (u *UserVerificationEntity) ToResponse() *response.UserVerificationResponse { mediaResponses := make([]*response.MediaSimpleResponse, 0) for _, m := range u.Media { @@ -54,12 +70,12 @@ func (u *UserVerificationEntity) ToResponse() *response.UserVerificationResponse res := &response.UserVerificationResponse{ ID: u.ID, - UserID: u.UserID, + User: u.User.ToResponse(), VerifyType: u.VerifyType.String(), Content: u.Content, Status: u.Status.String(), ReviewNote: u.ReviewNote, - ReviewedBy: u.ReviewedBy, + Reviewer: u.Reviewer.ToResponse(), ReviewedAt: u.ReviewedAt, CreatedAt: u.CreatedAt, Medias: mediaResponses, diff --git a/internal/repositories/verificationRepository.go b/internal/repositories/verificationRepository.go index a6cc9ce..f6cec7b 100644 --- a/internal/repositories/verificationRepository.go +++ b/internal/repositories/verificationRepository.go @@ -60,20 +60,27 @@ func (v *verificationRepository) GetByID(ctx context.Context, id pgtype.UUID) (* verification = models.UserVerificationEntity{ ID: convert.UUIDToString(row.ID), - UserID: convert.UUIDToString(row.UserID), VerifyType: constants.ParseVerifyType(row.VerifyType), Content: convert.TextToString(row.Content), IsDeleted: row.IsDeleted, Status: constants.ParseStatusType(row.Status), ReviewNote: convert.TextToString(row.ReviewNote), - ReviewedBy: convert.UUIDToString(row.ReviewedBy), ReviewedAt: convert.TimeToPtr(row.ReviewedAt), CreatedAt: convert.TimeToPtr(row.CreatedAt), } + if err := verification.ParseMedia(row.Medias); err != nil { return nil, err } + if err := verification.ParseUser(row.User); err != nil { + return nil, err + } + + if err := verification.ParseReviewer(row.Reviewer); err != nil { + return nil, err + } + _ = v.c.Set(ctx, cacheId, verification, constants.NormalCacheDuration) return &verification, nil @@ -148,16 +155,27 @@ func (v *verificationRepository) Create(ctx context.Context, params sqlc.CreateU verification := models.UserVerificationEntity{ ID: convert.UUIDToString(row.ID), - UserID: convert.UUIDToString(row.UserID), VerifyType: constants.ParseVerifyType(row.VerifyType), Content: convert.TextToString(row.Content), IsDeleted: row.IsDeleted, Status: constants.ParseStatusType(row.Status), ReviewNote: convert.TextToString(row.ReviewNote), - ReviewedBy: convert.UUIDToString(row.ReviewedBy), ReviewedAt: convert.TimeToPtr(row.ReviewedAt), CreatedAt: convert.TimeToPtr(row.CreatedAt), } + + if err := verification.ParseMedia(row.Medias); err != nil { + return nil, err + } + + if err := verification.ParseUser(row.User); err != nil { + return nil, err + } + + if err := verification.ParseReviewer(row.Reviewer); err != nil { + return nil, err + } + _ = v.c.Del(ctx, fmt.Sprintf("verification:userId:%s", convert.UUIDToString(params.UserID))) return &verification, nil } @@ -246,19 +264,26 @@ func (v *verificationRepository) GetByUserID(ctx context.Context, userId pgtype. for _, row := range rows { verification := &models.UserVerificationEntity{ ID: convert.UUIDToString(row.ID), - UserID: convert.UUIDToString(row.UserID), VerifyType: constants.ParseVerifyType(row.VerifyType), Content: convert.TextToString(row.Content), IsDeleted: row.IsDeleted, Status: constants.ParseStatusType(row.Status), ReviewNote: convert.TextToString(row.ReviewNote), - ReviewedBy: convert.UUIDToString(row.ReviewedBy), ReviewedAt: convert.TimeToPtr(row.ReviewedAt), CreatedAt: convert.TimeToPtr(row.CreatedAt), } if err := verification.ParseMedia(row.Medias); err != nil { return nil, err } + + if err := verification.ParseUser(row.User); err != nil { + return nil, err + } + + if err := verification.ParseReviewer(row.Reviewer); err != nil { + return nil, err + } + ids = append(ids, verification.ID) items = append(items, verification) @@ -303,20 +328,27 @@ func (v *verificationRepository) Search(ctx context.Context, params sqlc.SearchU for _, row := range rows { verification := &models.UserVerificationEntity{ ID: convert.UUIDToString(row.ID), - UserID: convert.UUIDToString(row.UserID), VerifyType: constants.ParseVerifyType(row.VerifyType), Content: convert.TextToString(row.Content), IsDeleted: row.IsDeleted, Status: constants.ParseStatusType(row.Status), ReviewNote: convert.TextToString(row.ReviewNote), - ReviewedBy: convert.UUIDToString(row.ReviewedBy), ReviewedAt: convert.TimeToPtr(row.ReviewedAt), CreatedAt: convert.TimeToPtr(row.CreatedAt), } + if err := verification.ParseMedia(row.Medias); err != nil { return nil, err } + if err := verification.ParseUser(row.User); err != nil { + return nil, err + } + + if err := verification.ParseReviewer(row.Reviewer); err != nil { + return nil, err + } + ids = append(ids, verification.ID) items = append(items, verification) diff --git a/internal/services/verificationService.go b/internal/services/verificationService.go index c42ca32..e1e0a06 100644 --- a/internal/services/verificationService.go +++ b/internal/services/verificationService.go @@ -124,7 +124,7 @@ func (v *verificationService) DeleteVerification(ctx context.Context, claims *re } shoudDelete := false - if slices.Contains(claims.Roles, constants.ADMIN) || slices.Contains(claims.Roles, constants.MOD) || verification.UserID == claims.UId { + if slices.Contains(claims.Roles, constants.ADMIN) || slices.Contains(claims.Roles, constants.MOD) || verification.User.ID == claims.UId { shoudDelete = true } @@ -304,7 +304,7 @@ func (v *verificationService) UpdateStatusVerification(ctx context.Context, user return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid status!") } - userVerificationUUID, err := convert.StringToUUID(verification.UserID) + userVerificationUUID, err := convert.StringToUUID(verification.User.ID) if err != nil { return nil, fiber.NewError(fiber.StatusInternalServerError, err.Error()) } diff --git a/sqlc.yaml b/sqlc.yaml index dae4638..a0794e3 100644 --- a/sqlc.yaml +++ b/sqlc.yaml @@ -17,4 +17,8 @@ sql: - column: "users_with_roles.roles" go_type: import: "history-api/models" - type: "[]Role" \ No newline at end of file + type: "[]Role" + - db_type: json + go_type: encoding/json.RawMessage + - db_type: jsonb + go_type: encoding/json.RawMessage \ No newline at end of file