From d1ed6347482c853e7386d1145aa2985cabc4a9fb Mon Sep 17 00:00:00 2001 From: Suresh N Date: Fri, 5 Nov 2021 20:42:44 +0530 Subject: [PATCH 1/6] removed email_verified field from users in query --- internal/db/query/users.sql_gen.go | 15 ++++++--------- internal/db/sql/users.sql | 5 ++--- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/internal/db/query/users.sql_gen.go b/internal/db/query/users.sql_gen.go index ab64625..0d4eeb3 100644 --- a/internal/db/query/users.sql_gen.go +++ b/internal/db/query/users.sql_gen.go @@ -112,18 +112,16 @@ const updateUser = `-- name: UpdateUser :one UPDATE users SET name = $1, email = $2, - role = $3, - email_verified = $4 -WHERE id = $5 + role = $3 +WHERE id = $4 RETURNING id, name, email, password, role, email_verified, created_at, updated_at ` type UpdateUserParams struct { - Name string `db:"name"` - Email string `db:"email"` - Role UserRole `db:"role"` - EmailVerified bool `db:"email_verified"` - ID int32 `db:"id"` + Name string `db:"name"` + Email string `db:"email"` + Role UserRole `db:"role"` + ID int32 `db:"id"` } func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error) { @@ -131,7 +129,6 @@ func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, e arg.Name, arg.Email, arg.Role, - arg.EmailVerified, arg.ID, ) var i User diff --git a/internal/db/sql/users.sql b/internal/db/sql/users.sql index 0e17a08..9040f26 100644 --- a/internal/db/sql/users.sql +++ b/internal/db/sql/users.sql @@ -13,9 +13,8 @@ RETURNING *; UPDATE users SET name = $1, email = $2, - role = $3, - email_verified = $4 -WHERE id = $5 + role = $3 +WHERE id = $4 RETURNING *; -- name: DeleteUser :exec From bf58a04535762afa44a99c42177e2485b6c2f5b4 Mon Sep 17 00:00:00 2001 From: Suresh N Date: Fri, 5 Nov 2021 20:50:42 +0530 Subject: [PATCH 2/6] update: sqlc generated files --- internal/db/migrations.go | 2 +- internal/db/query/models.go | 15 +- internal/db/query/users.sql_gen.go | 15 +- internal/users/handler.go | 307 ++++++++++++++++++++++++++++- internal/users/repository.go | 67 +++++++ internal/users/route.go | 7 + 6 files changed, 390 insertions(+), 23 deletions(-) diff --git a/internal/db/migrations.go b/internal/db/migrations.go index 296e748..2c8f3c7 100644 --- a/internal/db/migrations.go +++ b/internal/db/migrations.go @@ -14,7 +14,7 @@ import ( // migrationVersion defines the current migration version. This ensures the app // is always compatible with the version of the database. -const migrationVersion = 1 +const migrationVersion = 2 //go:embed migrations/*.sql var migrations embed.FS diff --git a/internal/db/query/models.go b/internal/db/query/models.go index cb06db6..14d65f9 100644 --- a/internal/db/query/models.go +++ b/internal/db/query/models.go @@ -113,12 +113,11 @@ type Topic struct { } type User struct { - ID int32 `db:"id"` - Name string `db:"name"` - Email string `db:"email"` - Password string `db:"password"` - Role UserRole `db:"role"` - EmailVerified bool `db:"email_verified"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` + ID int32 `db:"id"` + Name string `db:"name"` + Email string `db:"email"` + Password string `db:"password"` + Role UserRole `db:"role"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` } diff --git a/internal/db/query/users.sql_gen.go b/internal/db/query/users.sql_gen.go index 0d4eeb3..6f8d32b 100644 --- a/internal/db/query/users.sql_gen.go +++ b/internal/db/query/users.sql_gen.go @@ -10,7 +10,7 @@ import ( const addUser = `-- name: AddUser :one INSERT INTO users(name, email, password, role) VALUES ($1, $2, $3, $4) -RETURNING id, name, email, password, role, email_verified, created_at, updated_at +RETURNING id, name, email, password, role, created_at, updated_at ` type AddUserParams struct { @@ -34,7 +34,6 @@ func (q *Queries) AddUser(ctx context.Context, arg AddUserParams) (User, error) &i.Email, &i.Password, &i.Role, - &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) @@ -53,7 +52,7 @@ func (q *Queries) DeleteUser(ctx context.Context, id int32) error { } const fetchAllUsers = `-- name: FetchAllUsers :many -SELECT id, name, email, password, role, email_verified, created_at, updated_at +SELECT id, name, email, password, role, created_at, updated_at FROM users ` @@ -72,7 +71,6 @@ func (q *Queries) FetchAllUsers(ctx context.Context) ([]User, error) { &i.Email, &i.Password, &i.Role, - &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ); err != nil { @@ -87,7 +85,7 @@ func (q *Queries) FetchAllUsers(ctx context.Context) ([]User, error) { } const fetchUser = `-- name: FetchUser :one -SELECT id, name, email, password, role, email_verified, created_at, updated_at +SELECT id, name, email, password, role, created_at, updated_at FROM users WHERE id = $1 ` @@ -101,7 +99,6 @@ func (q *Queries) FetchUser(ctx context.Context, id int32) (User, error) { &i.Email, &i.Password, &i.Role, - &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) @@ -114,7 +111,7 @@ SET name = $1, email = $2, role = $3 WHERE id = $4 -RETURNING id, name, email, password, role, email_verified, created_at, updated_at +RETURNING id, name, email, password, role, created_at, updated_at ` type UpdateUserParams struct { @@ -138,7 +135,6 @@ func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, e &i.Email, &i.Password, &i.Role, - &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) @@ -149,7 +145,7 @@ const updateUserPassword = `-- name: UpdateUserPassword :one UPDATE users SET password = $1 WHERE id = $2 -RETURNING id, name, email, password, role, email_verified, created_at, updated_at +RETURNING id, name, email, password, role, created_at, updated_at ` type UpdateUserPasswordParams struct { @@ -166,7 +162,6 @@ func (q *Queries) UpdateUserPassword(ctx context.Context, arg UpdateUserPassword &i.Email, &i.Password, &i.Role, - &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) diff --git a/internal/users/handler.go b/internal/users/handler.go index bb1b472..c1f682d 100644 --- a/internal/users/handler.go +++ b/internal/users/handler.go @@ -1,6 +1,7 @@ package users import ( + "github.com/aveloper/blog/internal/utils" "net/http" "time" @@ -38,7 +39,6 @@ func (h *Handler) addUser() http.HandlerFunc { Name string `json:"name"` Email string `json:"email"` Role string `json:"role"` - EmailVerified bool `json:"email_verified"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } @@ -51,11 +51,77 @@ func (h *Handler) addUser() http.HandlerFunc { return } + hash, valid ,err := utils.ValidateAndHashPassword(req.Password) + if !valid { + if err == nil { + h.log.Error("Password is not meeting the requirement "+ req.Password) + h.jsonWriter.InvalidPasswordErr(w, r) + } else { + //TODO: need to change the DefaultError method + h.log.Error("Failed to hash the password ", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + } + + return + } + // FIXME: Hash password before saving user, err := h.repository.AddUser(r.Context(), query.AddUserParams{ Name: req.Name, Email: req.Email, - Password: req.Password, + Password: hash, + Role: query.UserRole(req.Role), + }) + if err != nil { + // TODO: Handle user constraint errors separately + h.log.Error("Failed adding user to DB", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + return + } + + resp := &Response{ + ID: user.ID, + Name: user.Name, + Email: user.Email, + Role: string(user.Role), + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + + + h.jsonWriter.Ok(w, r, resp) + } +} + +func (h *Handler) updateUser() http.HandlerFunc{ + type Request struct { + ID int32 `json:"id" validate:"required"` + Name string `json:"name" validate:"required"` + Email string `json:"email" validate:"required,email"` + Role string `json:"role" validate:"required,oneof=admin editor author contributor"` + } + + type Response struct { + ID int32 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + return func(w http.ResponseWriter, r *http.Request) { + req := &Request{} + + ok := h.reader.ReadJSONAndValidate(w, r, req) + if !ok { + return + } + + user, err := h.repository.UpdateUser(r.Context(), query.UpdateUserParams{ + ID: req.ID, + Name: req.Name, + Email: req.Email, Role: query.UserRole(req.Role), }) if err != nil { @@ -70,13 +136,246 @@ func (h *Handler) addUser() http.HandlerFunc { Name: user.Name, Email: user.Email, Role: string(user.Role), - EmailVerified: user.EmailVerified, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, } - // TODO: Send verification Email h.jsonWriter.Ok(w, r, resp) } } + +func (h *Handler) updateUserName() http.HandlerFunc{ + type Request struct { + ID int32 `json:"id" validate:"required"` + Name string `json:"name" validate:"required"` + } + + type Response struct { + ID int32 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + return func(w http.ResponseWriter, r *http.Request) { + req := &Request{} + + ok := h.reader.ReadJSONAndValidate(w, r, req) + if !ok { + return + } + + user, err := h.repository.UpdateUserName(r.Context(), query.UpdateUserNameParams{ + ID: req.ID, + Name: req.Name, + }) + if err != nil { + h.log.Error("Failed updating user name to DB", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + return + } + + resp := &Response{ + ID: user.ID, + Name: user.Name, + Email: user.Email, + Role: string(user.Role), + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + + + h.jsonWriter.Ok(w, r, resp) + } +} + +func (h *Handler) updateUserEmail() http.HandlerFunc{ + type Request struct { + ID int32 `json:"id" validate:"required"` + Email string `json:"email" validate:"required,email"` + } + + type Response struct { + ID int32 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + return func(w http.ResponseWriter, r *http.Request) { + req := &Request{} + + ok := h.reader.ReadJSONAndValidate(w, r, req) + if !ok { + return + } + + user, err := h.repository.UpdateUserEmail(r.Context(), query.UpdateUserEmailParams{ + ID: req.ID, + Email: req.Email, + }) + if err != nil { + h.log.Error("Failed updating user email to DB", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + return + } + + resp := &Response{ + ID: user.ID, + Name: user.Name, + Email: user.Email, + Role: string(user.Role), + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + + + h.jsonWriter.Ok(w, r, resp) + } +} + +func (h *Handler) updateUserPassword() http.HandlerFunc{ + type Request struct { + ID int32 `json:"id" validate:"required"` + Password string `json:"password" validate:"required,gte=8"` + } + + type Response struct { + ID int32 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + return func(w http.ResponseWriter, r *http.Request) { + req := &Request{} + + ok := h.reader.ReadJSONAndValidate(w, r, req) + if !ok { + return + } + + hash, valid ,err := utils.ValidateAndHashPassword(req.Password) + if !valid { + if err == nil { + h.log.Error("Password is not meeting the requirement "+ req.Password) + h.jsonWriter.InvalidPasswordErr(w, r) + } else { + //TODO: need to change the DefaultError method + h.log.Error("Failed to hash the password ", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + } + + return + } + + user, err := h.repository.UpdateUserPassword(r.Context(), query.UpdateUserPasswordParams{ + ID: req.ID, + Password: hash, + }) + if err != nil { + // TODO: Handle user constraint errors separately + h.log.Error("Failed updating user password to DB", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + return + } + + resp := &Response{ + ID: user.ID, + Name: user.Name, + Email: user.Email, + Role: string(user.Role), + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + + + h.jsonWriter.Ok(w, r, resp) + } +} + +func (h *Handler) updateUserRole() http.HandlerFunc{ + type Request struct { + ID int32 `json:"id" validate:"required"` + Role string `json:"role" validate:"required,oneof=admin editor author contributor"` + } + + type Response struct { + ID int32 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + return func(w http.ResponseWriter, r *http.Request) { + req := &Request{} + + ok := h.reader.ReadJSONAndValidate(w, r, req) + if !ok { + return + } + + user, err := h.repository.UpdateUserRole(r.Context(), query.UpdateUserRoleParams{ + ID: req.ID, + Role: query.UserRole(req.Role), + }) + if err != nil { + h.log.Error("Failed updating user role to DB", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + return + } + + resp := &Response{ + ID: user.ID, + Name: user.Name, + Email: user.Email, + Role: string(user.Role), + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + + + h.jsonWriter.Ok(w, r, resp) + } +} + +func (h *Handler) DeleteUser() http.HandlerFunc { + type Request struct { + ID int32 `json:"id" validate:"required"` + } + + type Response struct { + Message string `json:"message"` + } + + return func(w http.ResponseWriter, r *http.Request) { + req := &Request{} + + ok := h.reader.ReadJSONAndValidate(w, r, req) + if !ok { + return + } + + err := h.repository.DeleteUser(r.Context(), req.ID) + if err != nil { + h.log.Error("Failed to delete user from DB", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + return + } + + resp := &Response{ + Message: "User successfully deleted", + } + + h.jsonWriter.Ok(w, r, resp) + } +} \ No newline at end of file diff --git a/internal/users/repository.go b/internal/users/repository.go index 062cc86..50731b8 100644 --- a/internal/users/repository.go +++ b/internal/users/repository.go @@ -33,3 +33,70 @@ func (r *Repository) AddUser(ctx context.Context, user query.AddUserParams) (*qu return &u, nil } + +//UpdateUser update the existing user +func (r *Repository) UpdateUser(ctx context.Context, user query.UpdateUserParams) (*query.User, error) { + u, err := r.q.UpdateUser(ctx, user) + if err != nil { + r.log.Error("failed to update user", zap.Error(err)) + return nil, err + } + + return &u, nil +} + +//UpdateUserName update the existing user username +func (r *Repository) UpdateUserName(ctx context.Context, user query.UpdateUserNameParams) (*query.User, error) { + u, err := r.q.UpdateUserName(ctx, user) + if err != nil { + r.log.Error("failed to update user name", zap.Error(err)) + return nil, err + } + + return &u, nil +} + +//UpdateUserEmail update the existing user email +func (r *Repository) UpdateUserEmail(ctx context.Context, user query.UpdateUserEmailParams) (*query.User, error) { + u, err := r.q.UpdateUserEmail(ctx, user) + if err != nil { + r.log.Error("failed to update user email", zap.Error(err)) + return nil, err + } + + return &u, nil +} + +//UpdateUserRole update the existing user +func (r *Repository) UpdateUserRole(ctx context.Context, user query.UpdateUserRoleParams) (*query.User, error) { + u, err := r.q.UpdateUserRole(ctx, user) + if err != nil { + r.log.Error("failed to update user role", zap.Error(err)) + return nil, err + } + + return &u, nil +} + +//UpdateUserPassword update the existing user password +func (r *Repository) UpdateUserPassword(ctx context.Context, user query.UpdateUserPasswordParams) (*query.User, error) { + u, err := r.q.UpdateUserPassword(ctx, user) + if err != nil { + r.log.Error("failed to update user password", zap.Error(err)) + return nil, err + } + + return &u, nil +} + +//DeleteUser delete the existing user +func (r *Repository) DeleteUser(ctx context.Context, id int32) error { + err := r.q.DeleteUser(ctx, id) + if err != nil { + r.log.Error("failed to delete the user ", zap.Error(err)) + return err + } + + return nil +} + diff --git a/internal/users/route.go b/internal/users/route.go index ffc8512..b94b38e 100644 --- a/internal/users/route.go +++ b/internal/users/route.go @@ -11,4 +11,11 @@ func UserRoutes(r *mux.Router, uh *Handler) { r = r.PathPrefix("/users").Subrouter() r.HandleFunc("/", uh.addUser()).Methods(http.MethodPost) + r.HandleFunc("/edit", uh.updateUser()).Methods(http.MethodPost) + r.HandleFunc("/edit/name", uh.updateUserName()).Methods(http.MethodPost) + r.HandleFunc("/edit/role", uh.updateUserRole()).Methods(http.MethodPost) + r.HandleFunc("/edit/email", uh.updateUserEmail()).Methods(http.MethodPost) + r.HandleFunc("/edit/password", uh.updateUserPassword()).Methods(http.MethodPost) + //FIXME: it can also be changed to /delete/{id} for better use + r.HandleFunc("/delete", uh.DeleteUser()).Methods(http.MethodPost) } From 50aef5aa3fa2b46c152f5e3e276aba953303b31d Mon Sep 17 00:00:00 2001 From: Suresh N Date: Fri, 5 Nov 2021 20:58:45 +0530 Subject: [PATCH 3/6] Revert "update: sqlc generated files" This reverts commit bf58a04535762afa44a99c42177e2485b6c2f5b4. --- internal/db/migrations.go | 2 +- internal/db/query/models.go | 15 +- internal/db/query/users.sql_gen.go | 15 +- internal/users/handler.go | 307 +---------------------------- internal/users/repository.go | 67 ------- internal/users/route.go | 7 - 6 files changed, 23 insertions(+), 390 deletions(-) diff --git a/internal/db/migrations.go b/internal/db/migrations.go index 2c8f3c7..296e748 100644 --- a/internal/db/migrations.go +++ b/internal/db/migrations.go @@ -14,7 +14,7 @@ import ( // migrationVersion defines the current migration version. This ensures the app // is always compatible with the version of the database. -const migrationVersion = 2 +const migrationVersion = 1 //go:embed migrations/*.sql var migrations embed.FS diff --git a/internal/db/query/models.go b/internal/db/query/models.go index 14d65f9..cb06db6 100644 --- a/internal/db/query/models.go +++ b/internal/db/query/models.go @@ -113,11 +113,12 @@ type Topic struct { } type User struct { - ID int32 `db:"id"` - Name string `db:"name"` - Email string `db:"email"` - Password string `db:"password"` - Role UserRole `db:"role"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` + ID int32 `db:"id"` + Name string `db:"name"` + Email string `db:"email"` + Password string `db:"password"` + Role UserRole `db:"role"` + EmailVerified bool `db:"email_verified"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` } diff --git a/internal/db/query/users.sql_gen.go b/internal/db/query/users.sql_gen.go index 6f8d32b..0d4eeb3 100644 --- a/internal/db/query/users.sql_gen.go +++ b/internal/db/query/users.sql_gen.go @@ -10,7 +10,7 @@ import ( const addUser = `-- name: AddUser :one INSERT INTO users(name, email, password, role) VALUES ($1, $2, $3, $4) -RETURNING id, name, email, password, role, created_at, updated_at +RETURNING id, name, email, password, role, email_verified, created_at, updated_at ` type AddUserParams struct { @@ -34,6 +34,7 @@ func (q *Queries) AddUser(ctx context.Context, arg AddUserParams) (User, error) &i.Email, &i.Password, &i.Role, + &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) @@ -52,7 +53,7 @@ func (q *Queries) DeleteUser(ctx context.Context, id int32) error { } const fetchAllUsers = `-- name: FetchAllUsers :many -SELECT id, name, email, password, role, created_at, updated_at +SELECT id, name, email, password, role, email_verified, created_at, updated_at FROM users ` @@ -71,6 +72,7 @@ func (q *Queries) FetchAllUsers(ctx context.Context) ([]User, error) { &i.Email, &i.Password, &i.Role, + &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ); err != nil { @@ -85,7 +87,7 @@ func (q *Queries) FetchAllUsers(ctx context.Context) ([]User, error) { } const fetchUser = `-- name: FetchUser :one -SELECT id, name, email, password, role, created_at, updated_at +SELECT id, name, email, password, role, email_verified, created_at, updated_at FROM users WHERE id = $1 ` @@ -99,6 +101,7 @@ func (q *Queries) FetchUser(ctx context.Context, id int32) (User, error) { &i.Email, &i.Password, &i.Role, + &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) @@ -111,7 +114,7 @@ SET name = $1, email = $2, role = $3 WHERE id = $4 -RETURNING id, name, email, password, role, created_at, updated_at +RETURNING id, name, email, password, role, email_verified, created_at, updated_at ` type UpdateUserParams struct { @@ -135,6 +138,7 @@ func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, e &i.Email, &i.Password, &i.Role, + &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) @@ -145,7 +149,7 @@ const updateUserPassword = `-- name: UpdateUserPassword :one UPDATE users SET password = $1 WHERE id = $2 -RETURNING id, name, email, password, role, created_at, updated_at +RETURNING id, name, email, password, role, email_verified, created_at, updated_at ` type UpdateUserPasswordParams struct { @@ -162,6 +166,7 @@ func (q *Queries) UpdateUserPassword(ctx context.Context, arg UpdateUserPassword &i.Email, &i.Password, &i.Role, + &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) diff --git a/internal/users/handler.go b/internal/users/handler.go index c1f682d..bb1b472 100644 --- a/internal/users/handler.go +++ b/internal/users/handler.go @@ -1,7 +1,6 @@ package users import ( - "github.com/aveloper/blog/internal/utils" "net/http" "time" @@ -39,6 +38,7 @@ func (h *Handler) addUser() http.HandlerFunc { Name string `json:"name"` Email string `json:"email"` Role string `json:"role"` + EmailVerified bool `json:"email_verified"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } @@ -51,77 +51,11 @@ func (h *Handler) addUser() http.HandlerFunc { return } - hash, valid ,err := utils.ValidateAndHashPassword(req.Password) - if !valid { - if err == nil { - h.log.Error("Password is not meeting the requirement "+ req.Password) - h.jsonWriter.InvalidPasswordErr(w, r) - } else { - //TODO: need to change the DefaultError method - h.log.Error("Failed to hash the password ", zap.Error(err)) - h.jsonWriter.DefaultError(w, r) - } - - return - } - // FIXME: Hash password before saving user, err := h.repository.AddUser(r.Context(), query.AddUserParams{ Name: req.Name, Email: req.Email, - Password: hash, - Role: query.UserRole(req.Role), - }) - if err != nil { - // TODO: Handle user constraint errors separately - h.log.Error("Failed adding user to DB", zap.Error(err)) - h.jsonWriter.DefaultError(w, r) - return - } - - resp := &Response{ - ID: user.ID, - Name: user.Name, - Email: user.Email, - Role: string(user.Role), - CreatedAt: user.CreatedAt, - UpdatedAt: user.UpdatedAt, - } - - - h.jsonWriter.Ok(w, r, resp) - } -} - -func (h *Handler) updateUser() http.HandlerFunc{ - type Request struct { - ID int32 `json:"id" validate:"required"` - Name string `json:"name" validate:"required"` - Email string `json:"email" validate:"required,email"` - Role string `json:"role" validate:"required,oneof=admin editor author contributor"` - } - - type Response struct { - ID int32 `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Role string `json:"role"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - } - - return func(w http.ResponseWriter, r *http.Request) { - req := &Request{} - - ok := h.reader.ReadJSONAndValidate(w, r, req) - if !ok { - return - } - - user, err := h.repository.UpdateUser(r.Context(), query.UpdateUserParams{ - ID: req.ID, - Name: req.Name, - Email: req.Email, + Password: req.Password, Role: query.UserRole(req.Role), }) if err != nil { @@ -136,246 +70,13 @@ func (h *Handler) updateUser() http.HandlerFunc{ Name: user.Name, Email: user.Email, Role: string(user.Role), + EmailVerified: user.EmailVerified, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, } + // TODO: Send verification Email h.jsonWriter.Ok(w, r, resp) } } - -func (h *Handler) updateUserName() http.HandlerFunc{ - type Request struct { - ID int32 `json:"id" validate:"required"` - Name string `json:"name" validate:"required"` - } - - type Response struct { - ID int32 `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Role string `json:"role"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - } - - return func(w http.ResponseWriter, r *http.Request) { - req := &Request{} - - ok := h.reader.ReadJSONAndValidate(w, r, req) - if !ok { - return - } - - user, err := h.repository.UpdateUserName(r.Context(), query.UpdateUserNameParams{ - ID: req.ID, - Name: req.Name, - }) - if err != nil { - h.log.Error("Failed updating user name to DB", zap.Error(err)) - h.jsonWriter.DefaultError(w, r) - return - } - - resp := &Response{ - ID: user.ID, - Name: user.Name, - Email: user.Email, - Role: string(user.Role), - CreatedAt: user.CreatedAt, - UpdatedAt: user.UpdatedAt, - } - - - h.jsonWriter.Ok(w, r, resp) - } -} - -func (h *Handler) updateUserEmail() http.HandlerFunc{ - type Request struct { - ID int32 `json:"id" validate:"required"` - Email string `json:"email" validate:"required,email"` - } - - type Response struct { - ID int32 `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Role string `json:"role"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - } - - return func(w http.ResponseWriter, r *http.Request) { - req := &Request{} - - ok := h.reader.ReadJSONAndValidate(w, r, req) - if !ok { - return - } - - user, err := h.repository.UpdateUserEmail(r.Context(), query.UpdateUserEmailParams{ - ID: req.ID, - Email: req.Email, - }) - if err != nil { - h.log.Error("Failed updating user email to DB", zap.Error(err)) - h.jsonWriter.DefaultError(w, r) - return - } - - resp := &Response{ - ID: user.ID, - Name: user.Name, - Email: user.Email, - Role: string(user.Role), - CreatedAt: user.CreatedAt, - UpdatedAt: user.UpdatedAt, - } - - - h.jsonWriter.Ok(w, r, resp) - } -} - -func (h *Handler) updateUserPassword() http.HandlerFunc{ - type Request struct { - ID int32 `json:"id" validate:"required"` - Password string `json:"password" validate:"required,gte=8"` - } - - type Response struct { - ID int32 `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Role string `json:"role"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - } - - return func(w http.ResponseWriter, r *http.Request) { - req := &Request{} - - ok := h.reader.ReadJSONAndValidate(w, r, req) - if !ok { - return - } - - hash, valid ,err := utils.ValidateAndHashPassword(req.Password) - if !valid { - if err == nil { - h.log.Error("Password is not meeting the requirement "+ req.Password) - h.jsonWriter.InvalidPasswordErr(w, r) - } else { - //TODO: need to change the DefaultError method - h.log.Error("Failed to hash the password ", zap.Error(err)) - h.jsonWriter.DefaultError(w, r) - } - - return - } - - user, err := h.repository.UpdateUserPassword(r.Context(), query.UpdateUserPasswordParams{ - ID: req.ID, - Password: hash, - }) - if err != nil { - // TODO: Handle user constraint errors separately - h.log.Error("Failed updating user password to DB", zap.Error(err)) - h.jsonWriter.DefaultError(w, r) - return - } - - resp := &Response{ - ID: user.ID, - Name: user.Name, - Email: user.Email, - Role: string(user.Role), - CreatedAt: user.CreatedAt, - UpdatedAt: user.UpdatedAt, - } - - - h.jsonWriter.Ok(w, r, resp) - } -} - -func (h *Handler) updateUserRole() http.HandlerFunc{ - type Request struct { - ID int32 `json:"id" validate:"required"` - Role string `json:"role" validate:"required,oneof=admin editor author contributor"` - } - - type Response struct { - ID int32 `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Role string `json:"role"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - } - - return func(w http.ResponseWriter, r *http.Request) { - req := &Request{} - - ok := h.reader.ReadJSONAndValidate(w, r, req) - if !ok { - return - } - - user, err := h.repository.UpdateUserRole(r.Context(), query.UpdateUserRoleParams{ - ID: req.ID, - Role: query.UserRole(req.Role), - }) - if err != nil { - h.log.Error("Failed updating user role to DB", zap.Error(err)) - h.jsonWriter.DefaultError(w, r) - return - } - - resp := &Response{ - ID: user.ID, - Name: user.Name, - Email: user.Email, - Role: string(user.Role), - CreatedAt: user.CreatedAt, - UpdatedAt: user.UpdatedAt, - } - - - h.jsonWriter.Ok(w, r, resp) - } -} - -func (h *Handler) DeleteUser() http.HandlerFunc { - type Request struct { - ID int32 `json:"id" validate:"required"` - } - - type Response struct { - Message string `json:"message"` - } - - return func(w http.ResponseWriter, r *http.Request) { - req := &Request{} - - ok := h.reader.ReadJSONAndValidate(w, r, req) - if !ok { - return - } - - err := h.repository.DeleteUser(r.Context(), req.ID) - if err != nil { - h.log.Error("Failed to delete user from DB", zap.Error(err)) - h.jsonWriter.DefaultError(w, r) - return - } - - resp := &Response{ - Message: "User successfully deleted", - } - - h.jsonWriter.Ok(w, r, resp) - } -} \ No newline at end of file diff --git a/internal/users/repository.go b/internal/users/repository.go index 50731b8..062cc86 100644 --- a/internal/users/repository.go +++ b/internal/users/repository.go @@ -33,70 +33,3 @@ func (r *Repository) AddUser(ctx context.Context, user query.AddUserParams) (*qu return &u, nil } - -//UpdateUser update the existing user -func (r *Repository) UpdateUser(ctx context.Context, user query.UpdateUserParams) (*query.User, error) { - u, err := r.q.UpdateUser(ctx, user) - if err != nil { - r.log.Error("failed to update user", zap.Error(err)) - return nil, err - } - - return &u, nil -} - -//UpdateUserName update the existing user username -func (r *Repository) UpdateUserName(ctx context.Context, user query.UpdateUserNameParams) (*query.User, error) { - u, err := r.q.UpdateUserName(ctx, user) - if err != nil { - r.log.Error("failed to update user name", zap.Error(err)) - return nil, err - } - - return &u, nil -} - -//UpdateUserEmail update the existing user email -func (r *Repository) UpdateUserEmail(ctx context.Context, user query.UpdateUserEmailParams) (*query.User, error) { - u, err := r.q.UpdateUserEmail(ctx, user) - if err != nil { - r.log.Error("failed to update user email", zap.Error(err)) - return nil, err - } - - return &u, nil -} - -//UpdateUserRole update the existing user -func (r *Repository) UpdateUserRole(ctx context.Context, user query.UpdateUserRoleParams) (*query.User, error) { - u, err := r.q.UpdateUserRole(ctx, user) - if err != nil { - r.log.Error("failed to update user role", zap.Error(err)) - return nil, err - } - - return &u, nil -} - -//UpdateUserPassword update the existing user password -func (r *Repository) UpdateUserPassword(ctx context.Context, user query.UpdateUserPasswordParams) (*query.User, error) { - u, err := r.q.UpdateUserPassword(ctx, user) - if err != nil { - r.log.Error("failed to update user password", zap.Error(err)) - return nil, err - } - - return &u, nil -} - -//DeleteUser delete the existing user -func (r *Repository) DeleteUser(ctx context.Context, id int32) error { - err := r.q.DeleteUser(ctx, id) - if err != nil { - r.log.Error("failed to delete the user ", zap.Error(err)) - return err - } - - return nil -} - diff --git a/internal/users/route.go b/internal/users/route.go index b94b38e..ffc8512 100644 --- a/internal/users/route.go +++ b/internal/users/route.go @@ -11,11 +11,4 @@ func UserRoutes(r *mux.Router, uh *Handler) { r = r.PathPrefix("/users").Subrouter() r.HandleFunc("/", uh.addUser()).Methods(http.MethodPost) - r.HandleFunc("/edit", uh.updateUser()).Methods(http.MethodPost) - r.HandleFunc("/edit/name", uh.updateUserName()).Methods(http.MethodPost) - r.HandleFunc("/edit/role", uh.updateUserRole()).Methods(http.MethodPost) - r.HandleFunc("/edit/email", uh.updateUserEmail()).Methods(http.MethodPost) - r.HandleFunc("/edit/password", uh.updateUserPassword()).Methods(http.MethodPost) - //FIXME: it can also be changed to /delete/{id} for better use - r.HandleFunc("/delete", uh.DeleteUser()).Methods(http.MethodPost) } From 29e11e6524b66f2bbfbefeb4fd30d1459182d2ba Mon Sep 17 00:00:00 2001 From: Suresh N Date: Fri, 5 Nov 2021 21:02:53 +0530 Subject: [PATCH 4/6] updated sqlc gen files --- internal/db/query/models.go | 15 +++++++-------- internal/db/query/users.sql_gen.go | 15 +++++---------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/internal/db/query/models.go b/internal/db/query/models.go index cb06db6..14d65f9 100644 --- a/internal/db/query/models.go +++ b/internal/db/query/models.go @@ -113,12 +113,11 @@ type Topic struct { } type User struct { - ID int32 `db:"id"` - Name string `db:"name"` - Email string `db:"email"` - Password string `db:"password"` - Role UserRole `db:"role"` - EmailVerified bool `db:"email_verified"` - CreatedAt time.Time `db:"created_at"` - UpdatedAt time.Time `db:"updated_at"` + ID int32 `db:"id"` + Name string `db:"name"` + Email string `db:"email"` + Password string `db:"password"` + Role UserRole `db:"role"` + CreatedAt time.Time `db:"created_at"` + UpdatedAt time.Time `db:"updated_at"` } diff --git a/internal/db/query/users.sql_gen.go b/internal/db/query/users.sql_gen.go index 0d4eeb3..6f8d32b 100644 --- a/internal/db/query/users.sql_gen.go +++ b/internal/db/query/users.sql_gen.go @@ -10,7 +10,7 @@ import ( const addUser = `-- name: AddUser :one INSERT INTO users(name, email, password, role) VALUES ($1, $2, $3, $4) -RETURNING id, name, email, password, role, email_verified, created_at, updated_at +RETURNING id, name, email, password, role, created_at, updated_at ` type AddUserParams struct { @@ -34,7 +34,6 @@ func (q *Queries) AddUser(ctx context.Context, arg AddUserParams) (User, error) &i.Email, &i.Password, &i.Role, - &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) @@ -53,7 +52,7 @@ func (q *Queries) DeleteUser(ctx context.Context, id int32) error { } const fetchAllUsers = `-- name: FetchAllUsers :many -SELECT id, name, email, password, role, email_verified, created_at, updated_at +SELECT id, name, email, password, role, created_at, updated_at FROM users ` @@ -72,7 +71,6 @@ func (q *Queries) FetchAllUsers(ctx context.Context) ([]User, error) { &i.Email, &i.Password, &i.Role, - &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ); err != nil { @@ -87,7 +85,7 @@ func (q *Queries) FetchAllUsers(ctx context.Context) ([]User, error) { } const fetchUser = `-- name: FetchUser :one -SELECT id, name, email, password, role, email_verified, created_at, updated_at +SELECT id, name, email, password, role, created_at, updated_at FROM users WHERE id = $1 ` @@ -101,7 +99,6 @@ func (q *Queries) FetchUser(ctx context.Context, id int32) (User, error) { &i.Email, &i.Password, &i.Role, - &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) @@ -114,7 +111,7 @@ SET name = $1, email = $2, role = $3 WHERE id = $4 -RETURNING id, name, email, password, role, email_verified, created_at, updated_at +RETURNING id, name, email, password, role, created_at, updated_at ` type UpdateUserParams struct { @@ -138,7 +135,6 @@ func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, e &i.Email, &i.Password, &i.Role, - &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) @@ -149,7 +145,7 @@ const updateUserPassword = `-- name: UpdateUserPassword :one UPDATE users SET password = $1 WHERE id = $2 -RETURNING id, name, email, password, role, email_verified, created_at, updated_at +RETURNING id, name, email, password, role, created_at, updated_at ` type UpdateUserPasswordParams struct { @@ -166,7 +162,6 @@ func (q *Queries) UpdateUserPassword(ctx context.Context, arg UpdateUserPassword &i.Email, &i.Password, &i.Role, - &i.EmailVerified, &i.CreatedAt, &i.UpdatedAt, ) From e73e49e553bd081acdcdb90e83e5ba588afc6192 Mon Sep 17 00:00:00 2001 From: Suresh N Date: Fri, 5 Nov 2021 21:12:02 +0530 Subject: [PATCH 5/6] add CRUD methods in user repository --- internal/users/repository.go | 54 ++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/internal/users/repository.go b/internal/users/repository.go index 062cc86..bb258fd 100644 --- a/internal/users/repository.go +++ b/internal/users/repository.go @@ -23,6 +23,26 @@ func NewRepository(db *db.DB, log *zap.Logger) *Repository { } } +func (r *Repository) GetUser(ctx context.Context, id int32) (*query.User, error) { + u, err := r.q.FetchUser(ctx, id) + if err != nil { + r.log.Error("failed to get the user", zap.Error(err)) + return nil, err + } + + return &u, nil +} + +func (r *Repository) GetAllUsers(ctx context.Context) (*[]query.User, error) { + u, err := r.q.FetchAllUsers(ctx) + if err != nil { + r.log.Error("failed to get the user", zap.Error(err)) + return nil, err + } + + return &u, nil +} + //AddUser adds a new User func (r *Repository) AddUser(ctx context.Context, user query.AddUserParams) (*query.User, error) { u, err := r.q.AddUser(ctx, user) @@ -33,3 +53,37 @@ func (r *Repository) AddUser(ctx context.Context, user query.AddUserParams) (*qu return &u, nil } + +//UpdateUser update the existing user +func (r *Repository) UpdateUser(ctx context.Context, user query.UpdateUserParams) (*query.User, error) { + u, err := r.q.UpdateUser(ctx, user) + if err != nil { + r.log.Error("failed to update user", zap.Error(err)) + return nil, err + } + + return &u, nil +} + +//UpdateUserPassword update the existing user password +func (r *Repository) UpdateUserPassword(ctx context.Context, user query.UpdateUserPasswordParams) (*query.User, error) { + u, err := r.q.UpdateUserPassword(ctx, user) + if err != nil { + r.log.Error("failed to update user password", zap.Error(err)) + return nil, err + } + + return &u, nil +} + +//DeleteUser delete the existing user +func (r *Repository) DeleteUser(ctx context.Context, id int32) error { + err := r.q.DeleteUser(ctx, id) + if err != nil { + r.log.Error("failed to delete the user ", zap.Error(err)) + return err + } + + return nil +} + From 2adf1e7f507df6c9d26d712e6bc71c883501cf2d Mon Sep 17 00:00:00 2001 From: Suresh N Date: Fri, 5 Nov 2021 23:13:28 +0530 Subject: [PATCH 6/6] add methods for read, update & delete from users --- internal/users/handler.go | 222 ++++++++++++++++++++++++++++++++- internal/users/repository.go | 6 +- internal/users/responseType.go | 22 ++++ internal/users/route.go | 6 + 4 files changed, 251 insertions(+), 5 deletions(-) create mode 100644 internal/users/responseType.go diff --git a/internal/users/handler.go b/internal/users/handler.go index bb1b472..0328782 100644 --- a/internal/users/handler.go +++ b/internal/users/handler.go @@ -1,7 +1,9 @@ package users import ( + "github.com/gorilla/mux" "net/http" + "strconv" "time" "github.com/aveloper/blog/internal/db/query" @@ -24,6 +26,91 @@ func NewHandler(log *zap.Logger, reader *request.Reader, jsonWriter *response.JS return &Handler{log: log, reader: reader, jsonWriter: jsonWriter, repository: repository} } +func (h *Handler) getUser() http.HandlerFunc { + // TODO: Add better password validation(verify for special characters, number etc. + + type Response struct { + ID int32 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + return func(w http.ResponseWriter, r *http.Request) { + + params := mux.Vars(r) + id, err := strconv.Atoi(params["id"]) + if err != nil { + h.log.Error("ID should be int type", zap.Error(err)) + h.jsonWriter.BadRequest(w, r, &UserNotFound{}) + return + } + + + user, err := h.repository.GetUser(r.Context(), int32(id)) + if err != nil { + // TODO: Handle user constraint errors separately + h.log.Error("Failed get the user from DB", zap.Error(err)) + h.jsonWriter.BadRequest(w, r, &UserNotFound{ID: int32(id)}) + return + } + + resp := &Response{ + ID: user.ID, + Name: user.Name, + Email: user.Email, + Role: string(user.Role), + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + + + h.jsonWriter.Ok(w, r, resp) + } +} + +func (h *Handler) getAllUser() http.HandlerFunc { + type Response struct { + ID int32 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + return func(w http.ResponseWriter, r *http.Request) { + // FIXME: Hash password before saving + users, err := h.repository.GetAllUsers(r.Context()) + if err != nil { + // TODO: Handle user constraint errors separately + h.log.Error("Failed get all the user from DB", zap.Error(err)) + h.jsonWriter.BadRequest(w, r, &UserNotFound{}) + return + } + + resp := make([]Response, 0) + + for _, user := range users { + r := Response{ + ID: user.ID, + Name: user.Name, + Email: user.Email, + Role: string(user.Role), + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + + resp = append(resp, r) + } + + h.jsonWriter.Ok(w, r, resp) + } +} + + func (h *Handler) addUser() http.HandlerFunc { // TODO: Add better password validation(verify for special characters, number etc. type Request struct { @@ -38,7 +125,6 @@ func (h *Handler) addUser() http.HandlerFunc { Name string `json:"name"` Email string `json:"email"` Role string `json:"role"` - EmailVerified bool `json:"email_verified"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } @@ -70,13 +156,143 @@ func (h *Handler) addUser() http.HandlerFunc { Name: user.Name, Email: user.Email, Role: string(user.Role), - EmailVerified: user.EmailVerified, CreatedAt: user.CreatedAt, UpdatedAt: user.UpdatedAt, } - // TODO: Send verification Email h.jsonWriter.Ok(w, r, resp) } } + +func (h *Handler) updateUser() http.HandlerFunc{ + type Request struct { + ID int32 `json:"id" validate:"required"` + Name string `json:"name" validate:"required"` + Email string `json:"email" validate:"required,email"` + Role string `json:"role" validate:"required,oneof=admin editor author contributor"` + } + + type Response struct { + ID int32 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + return func(w http.ResponseWriter, r *http.Request) { + req := &Request{} + + ok := h.reader.ReadJSONAndValidate(w, r, req) + if !ok { + return + } + + user, err := h.repository.UpdateUser(r.Context(), query.UpdateUserParams{ + ID: req.ID, + Name: req.Name, + Email: req.Email, + Role: query.UserRole(req.Role), + }) + if err != nil { + // TODO: Handle user constraint errors separately + h.log.Error("Failed adding user to DB", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + return + } + + resp := &Response{ + ID: user.ID, + Name: user.Name, + Email: user.Email, + Role: string(user.Role), + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + + + h.jsonWriter.Ok(w, r, resp) + } +} + +func (h *Handler) updateUserPassword() http.HandlerFunc{ + type Request struct { + ID int32 `json:"id" validate:"required"` + Password string `json:"password" validate:"required,gte=8"` + } + + type Response struct { + ID int32 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + } + + return func(w http.ResponseWriter, r *http.Request) { + req := &Request{} + + ok := h.reader.ReadJSONAndValidate(w, r, req) + if !ok { + return + } + + user, err := h.repository.UpdateUserPassword(r.Context(), query.UpdateUserPasswordParams{ + ID: req.ID, + Password: req.Password, + }) + if err != nil { + // TODO: Handle user constraint errors separately + h.log.Error("Failed updating user password to DB", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + return + } + + resp := &Response{ + ID: user.ID, + Name: user.Name, + Email: user.Email, + Role: string(user.Role), + CreatedAt: user.CreatedAt, + UpdatedAt: user.UpdatedAt, + } + + + h.jsonWriter.Ok(w, r, resp) + } +} + +func (h *Handler) DeleteUser() http.HandlerFunc { + type Request struct { + ID int32 `json:"id" validate:"required"` + } + + type Response struct { + Message string `json:"message"` + } + + return func(w http.ResponseWriter, r *http.Request) { + req := &Request{} + + ok := h.reader.ReadJSONAndValidate(w, r, req) + if !ok { + return + } + + err := h.repository.DeleteUser(r.Context(), req.ID) + if err != nil { + h.log.Error("Failed to delete user from DB", zap.Error(err)) + h.jsonWriter.DefaultError(w, r) + return + } + + resp := &Response{ + Message: "User successfully deleted", + } + + h.jsonWriter.Ok(w, r, resp) + } +} \ No newline at end of file diff --git a/internal/users/repository.go b/internal/users/repository.go index bb258fd..271b9d8 100644 --- a/internal/users/repository.go +++ b/internal/users/repository.go @@ -23,6 +23,7 @@ func NewRepository(db *db.DB, log *zap.Logger) *Repository { } } +//GetUser fetch the user from users by given id func (r *Repository) GetUser(ctx context.Context, id int32) (*query.User, error) { u, err := r.q.FetchUser(ctx, id) if err != nil { @@ -33,14 +34,15 @@ func (r *Repository) GetUser(ctx context.Context, id int32) (*query.User, error) return &u, nil } -func (r *Repository) GetAllUsers(ctx context.Context) (*[]query.User, error) { +//GetAllUsers fetch all the users from users +func (r *Repository) GetAllUsers(ctx context.Context) ([]query.User, error) { u, err := r.q.FetchAllUsers(ctx) if err != nil { r.log.Error("failed to get the user", zap.Error(err)) return nil, err } - return &u, nil + return u, nil } //AddUser adds a new User diff --git a/internal/users/responseType.go b/internal/users/responseType.go new file mode 100644 index 0000000..ded89a9 --- /dev/null +++ b/internal/users/responseType.go @@ -0,0 +1,22 @@ +package users + +import ( + "fmt" + "github.com/aveloper/blog/internal/http/response" +) + +type UserNotFound struct { + ID int32 `json:"id"` +} + +func (d *UserNotFound) Message() string { + return fmt.Sprintf("User not Found for the id %d", d.ID) +} + +func (d *UserNotFound) Code() response.ErrorCode { + return response.DefaultErrorCode +} + +func (d *UserNotFound) Data() interface{} { + return nil +} \ No newline at end of file diff --git a/internal/users/route.go b/internal/users/route.go index ffc8512..68ba94f 100644 --- a/internal/users/route.go +++ b/internal/users/route.go @@ -10,5 +10,11 @@ import ( func UserRoutes(r *mux.Router, uh *Handler) { r = r.PathPrefix("/users").Subrouter() + r.HandleFunc("/edit/password", uh.updateUserPassword()).Methods(http.MethodPost) + r.HandleFunc("/edit", uh.updateUser()).Methods(http.MethodPost) + //FIXME: it can also be changed to /delete/{id} for better use + r.HandleFunc("/delete", uh.DeleteUser()).Methods(http.MethodPost) + r.HandleFunc("/all", uh.getAllUser()).Methods(http.MethodGet) + r.HandleFunc("/{id}", uh.getUser()).Methods(http.MethodGet) r.HandleFunc("/", uh.addUser()).Methods(http.MethodPost) }