add update users and refactor
This commit is contained in:
parent
eb9774cce5
commit
f8ecd20220
@ -67,8 +67,11 @@ func (server *Server) getRoutes() {
|
||||
// REQUIRE AUTH TOKEN
|
||||
authRoutes := router.Use(authMiddleware(server.TokenMaker))
|
||||
authRoutes.POST("/review/location", server.createReview)
|
||||
authRoutes.PATCH("/user", server.updateUser)
|
||||
authRoutes.GET("/user/review/location/:location_id", server.getUserReviewByLocation)
|
||||
authRoutes.GET("/user/profile", server.getUserStats)
|
||||
authRoutes.PATCH("/user/avatar", server.updateUserAvatar)
|
||||
authRoutes.DELETE("/user/avatar", server.removeAvatar)
|
||||
|
||||
server.Router = router
|
||||
}
|
||||
|
97
api/user.go
97
api/user.go
@ -3,7 +3,10 @@ package api
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
db "git.nochill.in/nochill/hiling_go/db/sqlc"
|
||||
@ -11,6 +14,7 @@ import (
|
||||
"git.nochill.in/nochill/hiling_go/util/token"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/lib/pq"
|
||||
"github.com/sqlc-dev/pqtype"
|
||||
)
|
||||
|
||||
type createUserRequest struct {
|
||||
@ -161,6 +165,99 @@ func (server *Server) getUserStats(ctx *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
type UpdateUserRequest struct {
|
||||
About string `json:"about"`
|
||||
Website string `json:"website"`
|
||||
SocialMedia []map[string]string `json:"social_media"`
|
||||
}
|
||||
|
||||
func (server *Server) updateUser(ctx *gin.Context) {
|
||||
var req UpdateUserRequest
|
||||
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, ValidationErrorResponse(err))
|
||||
return
|
||||
}
|
||||
|
||||
authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload)
|
||||
|
||||
fmt.Println(req.About)
|
||||
|
||||
social, _ := json.Marshal(req.SocialMedia)
|
||||
socialArr := pqtype.NullRawMessage{
|
||||
RawMessage: social,
|
||||
Valid: len(req.SocialMedia) > 0,
|
||||
}
|
||||
|
||||
user, err := server.Store.UpdateUser(ctx, db.UpdateUserParams{
|
||||
About: sql.NullString{String: req.About, Valid: true},
|
||||
SocialMedia: socialArr,
|
||||
Website: sql.NullString{String: req.Website, Valid: len(req.Website) > 0},
|
||||
ID: int32(authPayload.UserID),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to update user"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, user)
|
||||
}
|
||||
|
||||
func (server *Server) updateUserAvatar(ctx *gin.Context) {
|
||||
file, err := ctx.FormFile("file")
|
||||
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to parse file"))
|
||||
return
|
||||
}
|
||||
|
||||
authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload)
|
||||
|
||||
fileExt := filepath.Ext(file.Filename)
|
||||
now := time.Now()
|
||||
dir := fmt.Sprintf("public/upload/images/user/%d/avatar", authPayload.UserID)
|
||||
osFilename := fmt.Sprintf("%s%s%s", util.RandomString(5), fmt.Sprintf("%v", now.Unix()), fileExt)
|
||||
imgPath := fmt.Sprintf("%s/%s", dir, osFilename)
|
||||
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
os.Mkdir(dir, 0775)
|
||||
}
|
||||
|
||||
if err := ctx.SaveUploadedFile(file, imgPath); err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Error while try to save thumbnail image"))
|
||||
return
|
||||
}
|
||||
|
||||
url, err := server.Store.UpdateAvatar(ctx, db.UpdateAvatarParams{
|
||||
ID: int32(authPayload.UserID),
|
||||
AvatarPicture: sql.NullString{Valid: true, String: imgPath},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to save image to database"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, gin.H{"image_url": url.String})
|
||||
}
|
||||
|
||||
func (server *Server) removeAvatar(ctx *gin.Context) {
|
||||
authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload)
|
||||
|
||||
_, err := server.Store.UpdateAvatar(ctx, db.UpdateAvatarParams{
|
||||
AvatarPicture: sql.NullString{String: "", Valid: false},
|
||||
ID: int32(authPayload.UserID),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, ErrorResponse(err, "Something went wrong while try to update user avatar"))
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Writer.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (server *Server) login(ctx *gin.Context) {
|
||||
var req createUserRequest
|
||||
|
||||
|
@ -6,6 +6,7 @@ package mockdb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
sql "database/sql"
|
||||
reflect "reflect"
|
||||
|
||||
db "git.nochill.in/nochill/hiling_go/db/sqlc"
|
||||
@ -391,6 +392,21 @@ func (mr *MockStoreMockRecorder) RemoveFollowUser(arg0, arg1 interface{}) *gomoc
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveFollowUser", reflect.TypeOf((*MockStore)(nil).RemoveFollowUser), arg0, arg1)
|
||||
}
|
||||
|
||||
// UpdateAvatar mocks base method.
|
||||
func (m *MockStore) UpdateAvatar(arg0 context.Context, arg1 db.UpdateAvatarParams) (sql.NullString, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateAvatar", arg0, arg1)
|
||||
ret0, _ := ret[0].(sql.NullString)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// UpdateAvatar indicates an expected call of UpdateAvatar.
|
||||
func (mr *MockStoreMockRecorder) UpdateAvatar(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAvatar", reflect.TypeOf((*MockStore)(nil).UpdateAvatar), arg0, arg1)
|
||||
}
|
||||
|
||||
// UpdateLocationThumbnail mocks base method.
|
||||
func (m *MockStore) UpdateLocationThumbnail(arg0 context.Context, arg1 db.UpdateLocationThumbnailParams) error {
|
||||
m.ctrl.T.Helper()
|
||||
@ -420,10 +436,10 @@ func (mr *MockStoreMockRecorder) UpdatePassword(arg0, arg1 interface{}) *gomock.
|
||||
}
|
||||
|
||||
// UpdateUser mocks base method.
|
||||
func (m *MockStore) UpdateUser(arg0 context.Context, arg1 db.UpdateUserParams) (db.User, error) {
|
||||
func (m *MockStore) UpdateUser(arg0 context.Context, arg1 db.UpdateUserParams) (db.UpdateUserRow, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateUser", arg0, arg1)
|
||||
ret0, _ := ret[0].(db.User)
|
||||
ret0, _ := ret[0].(db.UpdateUserRow)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
@ -5,17 +5,13 @@ INSERT INTO users (
|
||||
) VALUES ($1, $2)
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUser :one
|
||||
UPDATE users
|
||||
SET
|
||||
email = COALESCE(sqlc.narg(email), email),
|
||||
username = COALESCE(sqlc.narg(username), username),
|
||||
avatar_picture = COALESCE(sqlc.narg(avatar_picture), avatar_picture)
|
||||
WHERE
|
||||
id = sqlc.arg(id)
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdatePassword :exec
|
||||
UPDATE users
|
||||
SET password = $1
|
||||
WHERE id = $2;
|
||||
|
||||
-- name: UpdateAvatar :one
|
||||
UPDATE users
|
||||
SET avatar_picture = $1
|
||||
WHERE id = $2
|
||||
RETURNING avatar_picture;
|
||||
|
@ -269,6 +269,8 @@ type User struct {
|
||||
SocialMedia pqtype.NullRawMessage `json:"social_media"`
|
||||
CreatedAt sql.NullTime `json:"created_at"`
|
||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||
About sql.NullString `json:"about"`
|
||||
Website sql.NullString `json:"website"`
|
||||
}
|
||||
|
||||
type UserActivity struct {
|
||||
|
@ -6,6 +6,7 @@ package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
type Querier interface {
|
||||
@ -23,9 +24,9 @@ type Querier interface {
|
||||
GetSession(ctx context.Context, id int32) (UserSession, error)
|
||||
GetUserReviewByLocation(ctx context.Context, arg GetUserReviewByLocationParams) (GetUserReviewByLocationRow, error)
|
||||
RemoveFollowUser(ctx context.Context, arg RemoveFollowUserParams) error
|
||||
UpdateAvatar(ctx context.Context, arg UpdateAvatarParams) (sql.NullString, error)
|
||||
UpdateLocationThumbnail(ctx context.Context, arg UpdateLocationThumbnailParams) error
|
||||
UpdatePassword(ctx context.Context, arg UpdatePasswordParams) error
|
||||
UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error)
|
||||
}
|
||||
|
||||
var _ Querier = (*Queries)(nil)
|
||||
|
@ -14,6 +14,7 @@ type Store interface {
|
||||
GetImagesByLocation(ctx context.Context, arg GetImagesByLocationParams) ([]GetImagesByLocationRow, error)
|
||||
GetLocation(ctx context.Context, location_id int32) (GetLocationRow, error)
|
||||
GetUser(ctx context.Context, username string) (GetUserRow, error)
|
||||
UpdateUser(ctx context.Context, arg UpdateUserParams) (UpdateUserRow, error)
|
||||
GetUserStats(ctx context.Context, user_id int32) (GetUserStatsRow, error)
|
||||
CreateReview(ctx context.Context, arg CreateReviewParams) (Review, error)
|
||||
GetListLocationReviews(ctx context.Context, arg GetListLocationReviewsParams) ([]GetListLocationReviewsRow, error)
|
||||
|
139
db/sqlc/users.go
139
db/sqlc/users.go
@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/sqlc-dev/pqtype"
|
||||
)
|
||||
@ -15,6 +15,9 @@ SELECT
|
||||
COALESCE(email, '') as email,
|
||||
password,
|
||||
username,
|
||||
COALESCE(google_sign_in_payload, '') as google_sign_in_payload,
|
||||
COALESCE(about, '') as about,
|
||||
COALESCE(website, '') as website,
|
||||
COALESCE(avatar_picture, '') as avatar_picture,
|
||||
banned_at,
|
||||
banned_until,
|
||||
@ -23,25 +26,32 @@ SELECT
|
||||
is_admin,
|
||||
is_critics,
|
||||
is_verified,
|
||||
social_media
|
||||
COALESCE(social_media, '[]'),
|
||||
created_at,
|
||||
updated_at
|
||||
FROM USERS
|
||||
WHERE username = $1
|
||||
`
|
||||
|
||||
type GetUserRow struct {
|
||||
ID int32 `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"-"`
|
||||
Username string `json:"username"`
|
||||
AvatarPicture string `json:"avatar_picture"`
|
||||
BannedAt sql.NullTime `json:"banned_at"`
|
||||
BannedUntil sql.NullTime `json:"banned_until"`
|
||||
BanReason string `json:"ban_reason"`
|
||||
IsPermaban bool `json:"is_permaban"`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
IsCritics bool `json:"is_critics"`
|
||||
IsVerified bool `json:"is_verified"`
|
||||
SocialMedia pqtype.NullRawMessage `json:"social_media"`
|
||||
ID int32 `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"-"`
|
||||
About string `json:"about"`
|
||||
Website string `json:"website"`
|
||||
Username string `json:"username"`
|
||||
GoogleSignInPayload string `json:"google_sign_in_payload"`
|
||||
AvatarPicture string `json:"avatar_picture"`
|
||||
BannedAt sql.NullTime `json:"banned_at"`
|
||||
BannedUntil sql.NullTime `json:"banned_until"`
|
||||
BanReason string `json:"ban_reason"`
|
||||
IsPermaban bool `json:"is_permaban"`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
IsCritics bool `json:"is_critics"`
|
||||
IsVerified bool `json:"is_verified"`
|
||||
SocialMedia json.RawMessage `json:"social_media"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetUser(ctx context.Context, username string) (GetUserRow, error) {
|
||||
@ -52,6 +62,9 @@ func (q *Queries) GetUser(ctx context.Context, username string) (GetUserRow, err
|
||||
&i.Email,
|
||||
&i.Password,
|
||||
&i.Username,
|
||||
&i.GoogleSignInPayload,
|
||||
&i.About,
|
||||
&i.Website,
|
||||
&i.AvatarPicture,
|
||||
&i.BannedAt,
|
||||
&i.BannedUntil,
|
||||
@ -61,6 +74,8 @@ func (q *Queries) GetUser(ctx context.Context, username string) (GetUserRow, err
|
||||
&i.IsCritics,
|
||||
&i.IsVerified,
|
||||
&i.SocialMedia,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
@ -126,12 +141,94 @@ func (q *Queries) GetUserStats(ctx context.Context, user_id int32) (GetUserStats
|
||||
&i.ScoreCount,
|
||||
&i.ScoresDistribution,
|
||||
)
|
||||
|
||||
var r []map[string]any
|
||||
|
||||
err = json.Unmarshal(i.ScoresDistribution, &r)
|
||||
fmt.Println(r)
|
||||
|
||||
return i, err
|
||||
|
||||
}
|
||||
|
||||
const updateUser = `-- name: UpdateUser :one
|
||||
UPDATE users
|
||||
SET
|
||||
about = $1,
|
||||
social_media = $2,
|
||||
website = $3
|
||||
WHERE
|
||||
id = $4
|
||||
RETURNING
|
||||
id,
|
||||
COALESCE(email, ''),
|
||||
username,
|
||||
COALESCE(avatar_picture, ''),
|
||||
COALESCE(about, ''),
|
||||
COALESCE(website, ''),
|
||||
COALESCE(google_sign_in_payload, ''),
|
||||
banned_at,
|
||||
banned_until,
|
||||
COALESCE(ban_reason, ''),
|
||||
is_permaban,
|
||||
is_admin,
|
||||
is_critics,
|
||||
is_verified,
|
||||
is_active,
|
||||
COALESCE(social_media, '[]'),
|
||||
created_at,
|
||||
updated_at
|
||||
`
|
||||
|
||||
type UpdateUserParams struct {
|
||||
About sql.NullString `json:"about"`
|
||||
SocialMedia pqtype.NullRawMessage `json:"social_media"`
|
||||
Website sql.NullString `json:"website"`
|
||||
ID int32 `json:"id"`
|
||||
}
|
||||
|
||||
type UpdateUserRow struct {
|
||||
ID int32 `json:"id"`
|
||||
Email string `json:"email"`
|
||||
Username string `json:"username"`
|
||||
AvatarPicture string `json:"avatar_picture"`
|
||||
About string `json:"about"`
|
||||
Website string `json:"website"`
|
||||
GoogleSignInPayload string `json:"google_sign_in_payload"`
|
||||
BannedAt sql.NullTime `json:"banned_at"`
|
||||
BannedUntil sql.NullTime `json:"banned_until"`
|
||||
BanReason string `json:"ban_reason"`
|
||||
IsPermaban bool `json:"is_permaban"`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
IsCritics bool `json:"is_critics"`
|
||||
IsVerified bool `json:"is_verified"`
|
||||
IsActive bool `json:"is_active"`
|
||||
SocialMedia json.RawMessage `json:"social_media"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (UpdateUserRow, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateUser,
|
||||
arg.About,
|
||||
arg.SocialMedia,
|
||||
arg.Website,
|
||||
arg.ID,
|
||||
)
|
||||
var i UpdateUserRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.AvatarPicture,
|
||||
&i.About,
|
||||
&i.Website,
|
||||
&i.GoogleSignInPayload,
|
||||
&i.BannedAt,
|
||||
&i.BannedUntil,
|
||||
&i.BanReason,
|
||||
&i.IsPermaban,
|
||||
&i.IsAdmin,
|
||||
&i.IsCritics,
|
||||
&i.IsVerified,
|
||||
&i.IsActive,
|
||||
&i.SocialMedia,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ INSERT INTO users (
|
||||
username,
|
||||
password
|
||||
) VALUES ($1, $2)
|
||||
RETURNING id, email, username, password, avatar_picture, google_sign_in_payload, banned_at, banned_until, ban_reason, is_permaban, is_admin, is_critics, is_verified, is_active, social_media, created_at, updated_at
|
||||
RETURNING id, email, username, password, avatar_picture, google_sign_in_payload, banned_at, banned_until, ban_reason, is_permaban, is_admin, is_critics, is_verified, is_active, social_media, created_at, updated_at, about, website
|
||||
`
|
||||
|
||||
type CreateUserParams struct {
|
||||
@ -44,10 +44,31 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, e
|
||||
&i.SocialMedia,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.About,
|
||||
&i.Website,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateAvatar = `-- name: UpdateAvatar :one
|
||||
UPDATE users
|
||||
SET avatar_picture = $1
|
||||
WHERE id = $2
|
||||
RETURNING avatar_picture
|
||||
`
|
||||
|
||||
type UpdateAvatarParams struct {
|
||||
AvatarPicture sql.NullString `json:"avatar_picture"`
|
||||
ID int32 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateAvatar(ctx context.Context, arg UpdateAvatarParams) (sql.NullString, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateAvatar, arg.AvatarPicture, arg.ID)
|
||||
var avatar_picture sql.NullString
|
||||
err := row.Scan(&avatar_picture)
|
||||
return avatar_picture, err
|
||||
}
|
||||
|
||||
const updatePassword = `-- name: UpdatePassword :exec
|
||||
UPDATE users
|
||||
SET password = $1
|
||||
@ -63,51 +84,3 @@ func (q *Queries) UpdatePassword(ctx context.Context, arg UpdatePasswordParams)
|
||||
_, err := q.db.ExecContext(ctx, updatePassword, arg.Password, arg.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
const updateUser = `-- name: UpdateUser :one
|
||||
UPDATE users
|
||||
SET
|
||||
email = COALESCE($1, email),
|
||||
username = COALESCE($2, username),
|
||||
avatar_picture = COALESCE($3, avatar_picture)
|
||||
WHERE
|
||||
id = $4
|
||||
RETURNING id, email, username, password, avatar_picture, google_sign_in_payload, banned_at, banned_until, ban_reason, is_permaban, is_admin, is_critics, is_verified, is_active, social_media, created_at, updated_at
|
||||
`
|
||||
|
||||
type UpdateUserParams struct {
|
||||
Email sql.NullString `json:"email"`
|
||||
Username sql.NullString `json:"username"`
|
||||
AvatarPicture sql.NullString `json:"avatar_picture"`
|
||||
ID int32 `json:"id"`
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error) {
|
||||
row := q.db.QueryRowContext(ctx, updateUser,
|
||||
arg.Email,
|
||||
arg.Username,
|
||||
arg.AvatarPicture,
|
||||
arg.ID,
|
||||
)
|
||||
var i User
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.Email,
|
||||
&i.Username,
|
||||
&i.Password,
|
||||
&i.AvatarPicture,
|
||||
&i.GoogleSignInPayload,
|
||||
&i.BannedAt,
|
||||
&i.BannedUntil,
|
||||
&i.BanReason,
|
||||
&i.IsPermaban,
|
||||
&i.IsAdmin,
|
||||
&i.IsCritics,
|
||||
&i.IsVerified,
|
||||
&i.IsActive,
|
||||
&i.SocialMedia,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user