Skip to content

Commit

Permalink
add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukmanern committed Feb 1, 2024
1 parent 503629b commit db91557
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 22 deletions.
6 changes: 1 addition & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Techs and tools were used in this project:
- [Github CLI](https://cli.github.com/) → Github management for repository's secrets & etc.
- [Github Action](https://github.com/features/actions) → Automated testing and building across multiple versions of Go.
- [Snyk](https://app.snyk.io/) → Dependency scanning.
- [SonarLint, VSCode ext.](https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarlint-vscode) → Detects & highlights issues that can lead to bugs & vulnerabilities.
- [SonarLint as VSCode ext.](https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarlint-vscode) → Detects & highlights issues that can lead to bugs & vulnerabilities.
- [GoLint](https://github.com/golang/lint) → CLI static code analytic for code-styling & many more.

 
Expand All @@ -40,7 +40,3 @@ Techs and tools were used in this project:
This project is under license from MIT. For more details, see the [LICENSE](LICENSE) file.

 

## Todo

- Add password and password confirm at DeleteProfile (permanent) by User
8 changes: 7 additions & 1 deletion application/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ var (
})
)

// setup initializes the application
// by checking the environment and
// database configuration.
func setup() {
// Check env and database
env.ReadConfig("./.env")
config := env.Configuration()
privKey := config.GetPrivateKey()
Expand All @@ -68,6 +70,7 @@ func setup() {
connector.LoadRedisCache()
}

// checkLocalPort checks if a given port is available for local use.
func checkLocalPort(port int) {
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
Expand All @@ -76,6 +79,9 @@ func checkLocalPort(port int) {
defer listener.Close()
}

// RunApp initializes and runs the application,
// handling setup, port checking, middleware,
// and route registration.
func RunApp() {
setup()
checkLocalPort(port)
Expand Down
23 changes: 22 additions & 1 deletion controller/role/role_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,29 @@ import (
service "github.com/Lukmanern/gost/service/role"
)

// RoleController defines all methods for handling
// role-related operations and logic.
// All these operations should be performed by an admin
// or other roles that defined in route-file.
type RoleController interface {
// auth + admin
// Create handles the creation of a new role.
Create(c *fiber.Ctx) error

// Get retrieves information about a specific role.
Get(c *fiber.Ctx) error

// GetAll retrieves information about all roles.
GetAll(c *fiber.Ctx) error

// Update handles updating role information.
Update(c *fiber.Ctx) error

// Delete handles the deletion of a role.
Delete(c *fiber.Ctx) error
}

// RoleControllerImpl is the implementation of
// RoleController with a RoleService dependency.
type RoleControllerImpl struct {
service service.RoleService
}
Expand All @@ -32,6 +46,8 @@ var (
roleControllerImplOnce sync.Once
)

// NewRoleController creates a singleton RoleController
// instance with the provided RoleService.
func NewRoleController(service service.RoleService) RoleController {
roleControllerImplOnce.Do(func() {
roleControllerImpl = &RoleControllerImpl{
Expand All @@ -41,6 +57,7 @@ func NewRoleController(service service.RoleService) RoleController {
return roleControllerImpl
}

// Create handles the creation of a new role.
func (ctr *RoleControllerImpl) Create(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand Down Expand Up @@ -73,6 +90,7 @@ func (ctr *RoleControllerImpl) Create(c *fiber.Ctx) error {
return response.SuccessCreated(c, data)
}

// Get retrieves information about a specific role.
func (ctr *RoleControllerImpl) Get(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand All @@ -98,6 +116,7 @@ func (ctr *RoleControllerImpl) Get(c *fiber.Ctx) error {
return response.SuccessLoaded(c, role)
}

// GetAll retrieves information about all roles.
func (ctr *RoleControllerImpl) GetAll(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand Down Expand Up @@ -135,6 +154,7 @@ func (ctr *RoleControllerImpl) GetAll(c *fiber.Ctx) error {
return response.SuccessLoaded(c, responseData)
}

// Update handles updating role information.
func (ctr *RoleControllerImpl) Update(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand Down Expand Up @@ -169,6 +189,7 @@ func (ctr *RoleControllerImpl) Update(c *fiber.Ctx) error {
return response.SuccessNoContent(c)
}

// Delete handles the deletion of a role.
func (ctr *RoleControllerImpl) Delete(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand Down
63 changes: 58 additions & 5 deletions controller/user/user_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,58 @@ import (
service "github.com/Lukmanern/gost/service/user"
)

// UserController defines methods for handling
// user-related operations.
type UserController interface {
// no-auth
// NO-AUTH

// Register handles for user registration for all roles.
// This handler will send an email for confirmation.
Register(c *fiber.Ctx) error

// AccountActivation handles the account activation
// process after registration.
AccountActivation(c *fiber.Ctx) error

// Login handles user login.
Login(c *fiber.Ctx) error

// ForgetPassword handles the forget password request.
// This handler will send an email for reset password.
ForgetPassword(c *fiber.Ctx) error

// ResetPassword handles the password reset process.
ResetPassword(c *fiber.Ctx) error
// auth

// AUTH

// MyProfile retrieves the user's own profile information.
MyProfile(c *fiber.Ctx) error

// Logout handles user logout.
// Black-listing the user token / JWT.
Logout(c *fiber.Ctx) error

// UpdateProfile handles updating user profile information.
UpdateProfile(c *fiber.Ctx) error

// UpdatePassword handles updating user password.
UpdatePassword(c *fiber.Ctx) error

// DeleteAccount handles the account deletion process.
DeleteAccount(c *fiber.Ctx) error
// auth + admin

// AUTH and ROLE-ADMIN AREA

// GetAll retrieves all user accounts (need admin access).
GetAll(c *fiber.Ctx) error

// BanAccount handles banning a user account (need admin access).
BanAccount(c *fiber.Ctx) error
}

// UserControllerImpl is the implementation of
// UserController with a UserService dependency.
type UserControllerImpl struct {
service service.UserService
}
Expand All @@ -43,6 +77,8 @@ var (
userControllerOnce sync.Once
)

// NewUserController creates a singleton UserController
// instance with the given UserService.
func NewUserController(service service.UserService) UserController {
userControllerOnce.Do(func() {
userController = &UserControllerImpl{
Expand All @@ -53,16 +89,19 @@ func NewUserController(service service.UserService) UserController {
return userController
}

// Register handles for user registration for all roles.
// This handler will send an email for confirmation.
func (ctr *UserControllerImpl) Register(c *fiber.Ctx) error {
var user model.UserRegister
if err := c.BodyParser(&user); err != nil {
return response.BadRequest(c, consts.InvalidJSONBody+err.Error())
}
user.Email = strings.ToLower(user.Email)
validate := validator.New()
if len(user.RoleIDs) < 1 {
return response.BadRequest(c, "please choose one or more role")
}
user.Email = strings.ToLower(user.Email)

validate := validator.New()
if err := validate.Struct(&user); err != nil {
return response.BadRequest(c, consts.InvalidJSONBody+err.Error())
}
Expand Down Expand Up @@ -91,6 +130,8 @@ func (ctr *UserControllerImpl) Register(c *fiber.Ctx) error {
})
}

// AccountActivation handles the account activation
// process after registration.
func (ctr *UserControllerImpl) AccountActivation(c *fiber.Ctx) error {
var user model.UserActivation
if err := c.BodyParser(&user); err != nil {
Expand Down Expand Up @@ -119,6 +160,7 @@ func (ctr *UserControllerImpl) AccountActivation(c *fiber.Ctx) error {
})
}

// Login handles user login.
func (ctr *UserControllerImpl) Login(c *fiber.Ctx) error {
var user model.UserLogin
if err := c.BodyParser(&user); err != nil {
Expand Down Expand Up @@ -152,6 +194,8 @@ func (ctr *UserControllerImpl) Login(c *fiber.Ctx) error {
})
}

// ForgetPassword handles the forget password request.
// This handler will send an email for reset password.
func (ctr *UserControllerImpl) ForgetPassword(c *fiber.Ctx) error {
var user model.UserForgetPassword
if err := c.BodyParser(&user); err != nil {
Expand Down Expand Up @@ -181,6 +225,7 @@ func (ctr *UserControllerImpl) ForgetPassword(c *fiber.Ctx) error {
})
}

// ResetPassword handles the password reset process.
func (ctr *UserControllerImpl) ResetPassword(c *fiber.Ctx) error {
var user model.UserResetPassword
if err := c.BodyParser(&user); err != nil {
Expand Down Expand Up @@ -213,6 +258,7 @@ func (ctr *UserControllerImpl) ResetPassword(c *fiber.Ctx) error {
})
}

// MyProfile retrieves the user's own profile information.
func (ctr *UserControllerImpl) MyProfile(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand All @@ -233,6 +279,8 @@ func (ctr *UserControllerImpl) MyProfile(c *fiber.Ctx) error {
return response.SuccessLoaded(c, userProfile)
}

// Logout handles user logout.
// Black-listing the user token / JWT.
func (ctr *UserControllerImpl) Logout(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand All @@ -245,6 +293,7 @@ func (ctr *UserControllerImpl) Logout(c *fiber.Ctx) error {
return response.SuccessNoContent(c)
}

// UpdateProfile handles updating user profile information.
func (ctr *UserControllerImpl) UpdateProfile(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand Down Expand Up @@ -275,6 +324,7 @@ func (ctr *UserControllerImpl) UpdateProfile(c *fiber.Ctx) error {
return response.SuccessNoContent(c)
}

// UpdatePassword handles updating user password.
func (ctr *UserControllerImpl) UpdatePassword(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand Down Expand Up @@ -312,6 +362,7 @@ func (ctr *UserControllerImpl) UpdatePassword(c *fiber.Ctx) error {
return response.SuccessNoContent(c)
}

// DeleteAccount handles the account deletion process.
func (ctr *UserControllerImpl) DeleteAccount(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand Down Expand Up @@ -350,6 +401,7 @@ func (ctr *UserControllerImpl) DeleteAccount(c *fiber.Ctx) error {
return response.SuccessNoContent(c)
}

// GetAll retrieves all user accounts (need admin access).
func (ctr *UserControllerImpl) GetAll(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand Down Expand Up @@ -387,6 +439,7 @@ func (ctr *UserControllerImpl) GetAll(c *fiber.Ctx) error {
return response.SuccessLoaded(c, responseData)
}

// BanAccount handles banning a user account (need admin access).
func (ctr *UserControllerImpl) BanAccount(c *fiber.Ctx) error {
userClaims, ok := c.Locals("claims").(*middleware.Claims)
if !ok || userClaims == nil {
Expand Down
4 changes: 2 additions & 2 deletions controller/user/user_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ func TestAccountActivation(t *testing.T) {
assert.Nil(t, err, consts.ShouldNil, headerTestName)

redisConTest := connector.LoadRedisCache()
key := validUser.Email + service.KEY_ACCOUNT_ACTIVATION
key := validUser.Email + service.KeyAccountActivation
validCode := redisConTest.Get(key).Val()

type testCase struct {
Expand Down Expand Up @@ -516,7 +516,7 @@ func TestResetPassword(t *testing.T) {
assert.Nil(t, err, consts.ShouldNil, headerTestName)

redisConTest := connector.LoadRedisCache()
key := validUser.Email + service.KEY_FORGET_PASSWORD
key := validUser.Email + service.KeyResetPassword
validCode := redisConTest.Get(key).Val()
assert.True(t, len(validCode) >= 21, "should true", headerTestName)

Expand Down
14 changes: 8 additions & 6 deletions service/user/user_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@ type UserServiceImpl struct {
emailService service.EmailService
}

// KeyResetPassword and KeyAccountActivation are
// used for addition key to get value from redis
const (
KEY_FORGET_PASSWORD = "-forget-password"
KEY_ACCOUNT_ACTIVATION = "-account-activation"
KeyResetPassword = "-forget-password"
KeyAccountActivation = "-account-activation"
)

var (
Expand Down Expand Up @@ -102,7 +104,7 @@ func (svc *UserServiceImpl) Register(ctx context.Context, data model.UserRegiste
}

code := helper.RandomString(32) // verification code
key := data.Email + KEY_ACCOUNT_ACTIVATION
key := data.Email + KeyAccountActivation
exp := time.Hour * 3
redisStatus := svc.redis.Set(key, code, exp)
if redisStatus.Err() != nil {
Expand Down Expand Up @@ -132,7 +134,7 @@ func (svc *UserServiceImpl) AccountActivation(ctx context.Context, data model.Us
return fiber.NewError(fiber.StatusBadRequest, "activation failed, account is active or already deleted")
}

key := data.Email + KEY_ACCOUNT_ACTIVATION
key := data.Email + KeyAccountActivation
redisStatus := svc.redis.Get(key)
if redisStatus.Err() != nil {
return errors.New("error while getting data from redis")
Expand Down Expand Up @@ -192,7 +194,7 @@ func (svc *UserServiceImpl) ForgetPassword(ctx context.Context, data model.UserF
return errors.New("error while getting user data")
}

key := data.Email + KEY_FORGET_PASSWORD
key := data.Email + KeyResetPassword
code := helper.RandomString(32)
exp := time.Hour * 1
redisStatus := svc.redis.Set(key, code, exp)
Expand All @@ -218,7 +220,7 @@ func (svc *UserServiceImpl) ResetPassword(ctx context.Context, data model.UserRe
if getErr != nil || user == nil {
return errors.New("error while getting user data")
}
key := data.Email + KEY_FORGET_PASSWORD
key := data.Email + KeyResetPassword
code := svc.redis.Get(key).Val()
if code == "" || code != data.Code {
return fiber.NewError(fiber.StatusNotFound, "verfication code isn't found")
Expand Down
4 changes: 2 additions & 2 deletions service/user/user_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ func TestAccountActivation(t *testing.T) {
assert.Nil(t, err, consts.ShouldNotNil, headerTestName)
defer repository.Delete(ctx, id)

key := validUser.Email + KEY_ACCOUNT_ACTIVATION
key := validUser.Email + KeyAccountActivation
validCode := redisConTest.Get(key).Val()
assert.True(t, len(validCode) > 0, consts.ShouldNotNil, headerTestName)

Expand Down Expand Up @@ -333,7 +333,7 @@ func TestResetPassword(t *testing.T) {
err := service.ForgetPassword(ctx, model.UserForgetPassword{Email: validUser.Email})
assert.Nil(t, err, consts.ShouldNil, headerTestName)

key := validUser.Email + KEY_FORGET_PASSWORD
key := validUser.Email + KeyResetPassword
validCode := redisConTest.Get(key).Val()
assert.True(t, len(validCode) > 0, consts.ShouldNotNil, headerTestName)

Expand Down

0 comments on commit db91557

Please sign in to comment.