Compare commits

...

24 Commits

Author SHA1 Message Date
nima ae8ec1c3ab new routes registerd 2024-06-17 19:06:27 +03:30
nima 40187810ad authorization added 2024-06-17 19:06:02 +03:30
nima d1181f31a2 user service 2024-06-17 19:05:19 +03:30
nima b58103f8ac sms service 2024-06-17 19:05:06 +03:30
nima d70d2b1621 role service 2024-06-17 19:04:55 +03:30
nima 3e301f7387 bug fix 2024-06-17 19:04:42 +03:30
nima fd1d4b7c07 user queries 2024-06-17 19:02:30 +03:30
nima 4497f6db02 role queries 2024-06-17 19:02:17 +03:30
nima 0a48d7104c user commands 2024-06-17 19:01:09 +03:30
nima dd6c3666af role commands 2024-06-17 19:00:52 +03:30
nima d4722e4d17 user repository 2024-06-17 18:59:34 +03:30
nima 43ef003928 role repository 2024-06-17 18:59:22 +03:30
nima 6cb35a83f7 bug fix 2024-06-17 18:59:06 +03:30
nima 8be115d534 user model 2024-06-17 18:58:18 +03:30
nima c747a20b7f user commands model 2024-06-17 18:57:56 +03:30
nima 1d5433142f role commands model 2024-06-17 18:57:01 +03:30
nima b329569a79 role model 2024-06-17 18:54:50 +03:30
nima 323157bec7 phone number model 2024-06-17 18:54:36 +03:30
nima 0b8a592bf1 loginCode model 2024-06-17 18:54:08 +03:30
nima 0e534f5a2d jwtmiddleware 2024-06-17 18:52:29 +03:30
nima 7ea71224f3 root user added 2024-06-17 18:51:39 +03:30
nima a4ccda1227 user , role and loginCode tables added to database 2024-06-17 18:50:44 +03:30
nima 6d11f53425 user , role , login routes added 2024-06-17 18:48:41 +03:30
nima 380a4570d9 authentication service added 2024-06-17 18:46:27 +03:30
29 changed files with 1140 additions and 15 deletions

View File

@ -0,0 +1,60 @@
package commands
import (
m "netina/models"
c "netina/models/commands"
p "netina/repositories/role"
"netina/validation"
"time"
)
type CreateRoleHandler struct {
Repository p.RoleCommandRepository
}
func (r *CreateRoleHandler) Handle(command c.CreateRoleCommand) error {
if err := validation.ValidateStruct(command); err != nil {
return err
}
role := &m.Role{
Name: command.Name,
Created_at: time.Now(),
Modified_by: command.Modified_by ,
}
return r.Repository.CreateRole(role)
}
type UpdateRoleHandler struct {
Repository p.RoleCommandRepository
}
func (r *UpdateRoleHandler) Handle (id uint , command c.UpdateRoleCommand)(*m.Role , error) {
if err := validation.ValidateStruct(command); err != nil {
return nil , err
}
role := &m.Role{
Name: command.Name,
Modified_by: command.Modified_by,
Modified_at: time.Now(),
}
return r.Repository.UpdateRole(id , role)
}
type RemoveRoleHandler struct {
Repository p.RoleCommandRepository
}
func (r *RemoveRoleHandler) Handle (id uint )error {
return r.Repository.RemoveRole(id)
}

View File

@ -0,0 +1,65 @@
package commands
import (
m "netina/models"
c "netina/models/commands"
u "netina/repositories/user"
"netina/validation"
"time"
)
type CreateUserHandler struct {
Repository u.UserCommandRepository
}
func (r *CreateUserHandler) Handle(command c.CreateUserCommand) error {
if err := validation.ValidateStruct(command); err != nil {
return err
}
User := &m.User{
Name: command.Name,
PhoneNumber: command.PhoneNumber,
Role_id: command.Role_id,
Created_at: time.Now(),
Modified_by: command.Modified_by,
}
return r.Repository.CreateUser(User)
}
type UpdateUserHandler struct {
Repository u.UserCommandRepository
}
func (r *UpdateUserHandler) Handle (id uint , command c.UpdateUserCommand)(*m.User , error) {
if err := validation.ValidateStruct(command); err != nil {
return nil , err
}
User := &m.User{
Name: command.Name,
PhoneNumber: command.PhoneNumber,
Role_id: command.Role_id,
Modified_by: command.Modified_by,
Modified_at: time.Now(),
}
return r.Repository.UpdateUser(id , User)
}
type RemoveUserHandler struct {
Repository u.UserCommandRepository
}
func (r *RemoveUserHandler) Handle (id uint )error {
return r.Repository.RemoveUser(id)
}

View File

@ -59,6 +59,18 @@ func Create_tables()error{
if err != nil {
return err
}
err = db.AutoMigrate(&models.User{})
if err != nil {
return err
}
err = db.AutoMigrate(&models.Role{})
if err != nil {
return err
}
err = db.AutoMigrate(&models.LoginCode{})
if err != nil {
return err
}
return nil
}

62
initialize/init.go 100644
View File

@ -0,0 +1,62 @@
package initialize
import (
"netina/database"
m "netina/models"
"os"
"time"
Role_repository "netina/repositories/role"
User_repository "netina/repositories/user"
"github.com/joho/godotenv"
)
func Init()error {
err := godotenv.Load("./config/.env")
if err != nil {
panic(err)
}
db := database.Db()
role_command := Role_repository.RoleCommandRepository{DB: &db}
role_query := Role_repository.RoleQueryRepository{DB: &db}
user_command := User_repository.UserCommandRepository{DB: &db}
role := &m.Role{
Name: "admin",
}
if err := role_command.CreateRole(role) ; err != nil {
return err
}
tempRole , err := role_query.GetRoleByName("admin")
if err != nil {
return err
}
user := &m.User{
Name: "admin",
PhoneNumber: os.Getenv("ADMIN_NUMBER"),
Role_id: tempRole.Role_id,
Created_at: time.Now(),
}
if err := user_command.CreateUser(user) ; err != nil {
return err
}
return nil
}

View File

@ -2,7 +2,7 @@ package main
import (
db "netina/database"
i "netina/initialize"
"netina/router"
"github.com/labstack/echo/v4"
@ -10,12 +10,17 @@ import (
func main(){
db.Create_tables()
e := echo.New()
i.Init()
router.LoginRoutes(e)
router.OwnerRoutes(e)
router.LicenseRoutes(e)
router.PlanRoutes(e)
router.StoreRoutes(e)
e.Logger.Fatal(e.Start(":8000"))
router.UserRoutes(e)
router.RoleRoutes(e)
e.Logger.Fatal(e.Start(":8800"))
}

View File

@ -0,0 +1,26 @@
package middlewares
import (
"fmt"
auth "netina/services/authentication"
"github.com/labstack/echo/v4"
)
func JWTMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
jwt := c.Request().Header.Get("Authorization")
claims, err := auth.ValidateUserToken(jwt)
if err != nil {
fmt.Println("Token validation error:", err)
return echo.ErrUnauthorized
}
//Store claims in the context
c.Set("user", claims)
return next(c)
}
}

11
models/code.go 100644
View File

@ -0,0 +1,11 @@
package models
import "time"
type LoginCode struct {
LoginCode_id uint `gorm:"primaryKey"`
PhoneNumber string `gorm:"not null" validate:"required"`
Code string `gorm:"not null" validate:"required"`
CreatedAt time.Time `gorm:"not null"`
ExpiresAt time.Time `gorm:"not null"`
}

View File

@ -0,0 +1,11 @@
package models
type CreateRoleCommand struct {
Name string `validate:"required"`
Modified_by string `validate:"required"`
}
type UpdateRoleCommand struct {
Name string `validate:"required"`
Modified_by string `validate:"required"`
}

View File

@ -0,0 +1,15 @@
package models
type CreateUserCommand struct {
Name string `validate:"required"`
PhoneNumber string `validate:"required"`
Role_id uint `validate:"required"`
Modified_by string `validate:"required"`
}
type UpdateUserCommand struct {
Name string `validate:"required"`
PhoneNumber string `validate:"required"`
Role_id uint `validate:"required"`
Modified_by string `validate:"required"`
}

View File

@ -0,0 +1,5 @@
package models
type CreatePhoneNumber struct {
PhoneNumber string `validate:"required"`
}

12
models/role.go 100644
View File

@ -0,0 +1,12 @@
package models
import "time"
type Role struct {
Role_id uint `gorm:"primaryKey"`
Name string `gorm:"unique;not null;validate:'required'"`
Created_at time.Time
Modified_at time.Time
Modified_by string
Is_removed bool `gorm:"default:false"`
}

19
models/user.go 100644
View File

@ -0,0 +1,19 @@
package models
import "time"
type User struct {
User_id uint `gorm:"primaryKey"`
Name string
PhoneNumber string `gorm:"unique;not null;validate:'required'"`
Role_id uint `gorm:"references:Role_id"`
Role Role
Created_at time.Time
Modified_at time.Time
Modified_by string
Is_removed bool `gorm:"default:false"`
}

View File

@ -0,0 +1,16 @@
package queries
import (
"netina/models"
r "netina/repositories/role"
)
type GetRoleHandler struct {
Repository r.RoleQueryRepository
}
func (r *GetRoleHandler) Handle (id uint)(*models.Role ,error) {
return r.Repository.GetRole(id)
}

View File

@ -0,0 +1,25 @@
package queries
import (
"netina/models"
user_repository "netina/repositories/user"
)
type GetUserByIdHandler struct {
Repository user_repository.UserQueryRepository
}
func (r *GetUserByIdHandler) Handle (id uint)(*models.User ,error) {
return r.Repository.GetUser(id)
}
type GetUserByPhoneNumberHandler struct {
Repository user_repository.UserQueryRepository
}
func(r *GetUserByPhoneNumberHandler) Handle(phoneNumber string)(*models.User , error) {
return r.Repository.GetUserByPhoneNumber(phoneNumber)
}

View File

@ -8,7 +8,6 @@ import (
type PlanCommand interface{
CreatePlan(o *models.Plan) error
GetPlan(id uint)(*models.Plan , error)
UpdatePlan(id uint , o *models.Plan)(*models.Plan , error)
RemovePlan(id uint)error
}

View File

@ -0,0 +1,58 @@
package Role_repository
import (
"netina/models"
"gorm.io/gorm"
)
type RoleCommand interface{
CreateRole(o *models.Role) error
UpdateRole(id uint , o *models.Role)(*models.Role , error)
RemoveRole(id uint)error
}
type RoleCommandRepository struct{
DB *gorm.DB
}
func (r *RoleCommandRepository) CreateRole(Role *models.Role)error{
if err := r.DB.Create(&Role).Error ; err != nil {
return err
}
return nil
}
func (r *RoleCommandRepository) UpdateRole(id uint , role *models.Role)(*models.Role , error){
var temp models.Role
if err := r.DB.Where("is_removed = ?" , false).Where("Role_id = ?" , id).First(&temp).Error ; err != nil {
return nil , err
}
temp.Name = role.Name
temp.Modified_at = role.Modified_at
temp.Modified_by = role.Modified_by
if err := r.DB.Save(&temp).Error; err != nil {
return nil , err
}
return &temp , nil
}
func (r *RoleCommandRepository) RemoveRole(id uint)error{
var Role models.Role
if err := r.DB.Where("role_id = ?" , id).Model(&Role).Update("is_removed" , true).Error;err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,36 @@
package Role_repository
import (
"netina/models"
"gorm.io/gorm"
)
type RoleQuery interface{
GetRole(id uint)(*models.Role , error)
}
type RoleQueryRepository struct{
DB *gorm.DB
}
func (r *RoleQueryRepository) GetRole(id uint)(*models.Role , error){
var role models.Role
if err := r.DB.Where("is_removed = ?" , false).Where("role_id = ?" , id).First(&role).Error; err != nil {
return nil , err
}
return &role , nil
}
func (r *RoleQueryRepository) GetRoleByName(name string)(*models.Role , error) {
var role models.Role
if err := r.DB.Where("is_removed = ?" , false).Where("name = ?" , name).First(&role).Error; err != nil {
return nil , err
}
return &role , nil
}

View File

@ -0,0 +1,59 @@
package user_repository
import (
"netina/models"
"gorm.io/gorm"
)
type UserCommand interface{
CreateUser(o *models.User) error
UpdateUser(id uint , o *models.User)(*models.User , error)
RemoveUser(id uint)error
}
type UserCommandRepository struct{
DB *gorm.DB
}
func (r *UserCommandRepository) CreateUser(user *models.User)error{
if err := r.DB.Create(&user).Error ; err != nil {
return err
}
return nil
}
func (r *UserCommandRepository) UpdateUser(id uint , user *models.User)(*models.User , error){
var temp models.User
if err := r.DB.Where("is_removed = ?" , false).Where("user_id = ?" , id).First(&temp).Error ; err != nil {
return nil , err
}
temp.Name = user.Name
temp.PhoneNumber = user.PhoneNumber
temp.Role_id = user.Role_id
temp.Modified_at = user.Modified_at
temp.Modified_by = user.Modified_by
if err := r.DB.Save(&temp).Error; err != nil {
return nil , err
}
return &temp , nil
}
func (r *UserCommandRepository) RemoveUser(id uint)error{
var user models.User
if err := r.DB.Where("user_id = ?" , id).Model(&user).Update("is_removed" , true).Error;err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,35 @@
package user_repository
import (
"netina/models"
"gorm.io/gorm"
)
type UserQuery interface{
GetUser(id uint)(*models.User , error)
}
type UserQueryRepository struct{
DB *gorm.DB
}
func (r *UserQueryRepository) GetUser(id uint)(*models.User , error){
var user models.User
if err := r.DB.Where("is_removed = ?" , false).Where("user_id = ?" , id).First(&user).Error; err != nil {
return nil , err
}
return &user , nil
}
func (r *UserQueryRepository) GetUserByPhoneNumber(phoneNumber string)(*models.User , error){
var user models.User
if err := r.DB.Where("is_removed = ?" , false).Where("phone_number = ?" , phoneNumber).First(&user).Error; err != nil {
return nil , err
}
return &user , nil
}

View File

@ -2,43 +2,80 @@ package router
import (
"netina/database"
"netina/middlewares"
license_repository "netina/repositories/license"
owner_repository "netina/repositories/owner"
plan_repository "netina/repositories/plan"
role_repository "netina/repositories/role"
store_repository "netina/repositories/store"
user_repository "netina/repositories/user"
"netina/services"
auth "netina/services/authentication"
a "netina/services/authorization"
"github.com/labstack/echo/v4"
)
func LoginRoutes(e *echo.Echo) {
login := e.Group("/login")
login.POST("/phonenumber" , auth.RequestCode)
login.POST("/verifycode" , auth.Login)
}
func UserRoutes(e *echo.Echo){
db := database.Db()
user := e.Group("/user")
user.Use(middlewares.JWTMiddleware)
userCommandRepo := &user_repository.UserCommandRepository{DB: &db}
userQueryRepo := &user_repository.UserQueryRepository{DB: &db}
userService := &services.UserService{
CommandRepo: *userCommandRepo,
QueryRepo: *userQueryRepo,
}
user.POST("/" , userService.CreateUser , a.AdminRole)
user.GET("/:id" , userService.GetUser)
user.GET("/phonenumber" , userService.GetUserByPhoneNumber)
user.PUT("/:id" , userService.UpdateUser , a.AdminRole)
user.DELETE("/:id" , userService.RemoveUser,a.AdminRole)
}
func OwnerRoutes(e *echo.Echo) {
db := database.Db()
owner := e.Group("/owner")
owner.Use(middlewares.JWTMiddleware)
ownerCommandRepo := &owner_repository.OwnerCommandRepository{DB: &db}
ownerQueryRepo := &owner_repository.OwnerQueryRepository{DB: &db}
ownerService := &services.OwnerService{
CommandRepo: *ownerCommandRepo,
QueryRepo: *ownerQueryRepo,
}
owner.POST("/",ownerService.CreateOwner)
owner.POST("/",ownerService.CreateOwner,a.AdminRole)
owner.GET("/:id" , ownerService.GetOwner)
owner.PUT("/:id" , ownerService.UpdateOwner)
owner.DELETE("/:id" , ownerService.RemoveOwner)
owner.PUT("/:id" , ownerService.UpdateOwner,a.AdminRole)
owner.DELETE("/:id" , ownerService.RemoveOwner,a.AdminRole)
}
func LicenseRoutes(e *echo.Echo) {
db := database.Db()
license := e.Group("/license")
license.Use(middlewares.JWTMiddleware)
licenseCommandRepo := &license_repository.LicenseCommandRepository{DB: &db}
licenseQueryRepo := &license_repository.LicenseQueryRepository{DB: &db}
licenseService := &services.LicenseService{
CommandRepo: *licenseCommandRepo,
QueryRepo: *licenseQueryRepo,
}
license.POST("/",licenseService.CreateLicense)
license.POST("/",licenseService.CreateLicense,a.AdminRole)
license.GET("/:id" , licenseService.GetLicense)
license.PUT("/:id" , licenseService.UpdateLicense)
license.DELETE("/:id" , licenseService.RemoveLicense)
license.PUT("/:id" , licenseService.UpdateLicense,a.AdminRole)
license.DELETE("/:id" , licenseService.RemoveLicense,a.AdminRole)
}
@ -46,16 +83,17 @@ func LicenseRoutes(e *echo.Echo) {
func PlanRoutes(e *echo.Echo) {
db := database.Db()
plan := e.Group("/plan")
plan.Use(middlewares.JWTMiddleware)
planCommandRepo := &plan_repository.PlanCommandRepository{DB: &db}
planQueryRepo := &plan_repository.PlanQueryRepository{DB: &db}
planService := &services.PlanService{
CommandRepo: *planCommandRepo,
QueryRepo: *planQueryRepo,
}
plan.POST("/",planService.CreatePlan)
plan.POST("/",planService.CreatePlan,a.AdminRole)
plan.GET("/:id" , planService.GetPlan)
plan.PUT("/:id" , planService.UpdatePlan)
plan.DELETE("/:id" , planService.RemovePlan)
plan.PUT("/:id" , planService.UpdatePlan,a.AdminRole)
plan.DELETE("/:id" , planService.RemovePlan,a.AdminRole)
}
@ -63,16 +101,36 @@ func PlanRoutes(e *echo.Echo) {
func StoreRoutes(e *echo.Echo) {
db := database.Db()
store := e.Group("/store")
store.Use(middlewares.JWTMiddleware)
storeCommandRepo := &store_repository.StoreCommandRepository{DB: &db}
storeQueryRepo := &store_repository.StoreQueryRepository{DB: &db}
storeService := &services.StoreService{
CommandRepo: *storeCommandRepo,
QueryRepo: *storeQueryRepo,
}
store.POST("/",storeService.CreateStore)
store.POST("/",storeService.CreateStore,a.AdminRole)
store.GET("/:id" , storeService.GetStore)
store.GET("/owner/:id" , storeService.GetStoresList)
store.PUT("/:id" , storeService.UpdateStore)
store.DELETE("/:id" , storeService.RemoveStore)
store.PUT("/:id" , storeService.UpdateStore,a.AdminRole)
store.DELETE("/:id" , storeService.RemoveStore,a.AdminRole)
}
func RoleRoutes(e *echo.Echo) {
db := database.Db()
role := e.Group("/role")
role.Use(middlewares.JWTMiddleware)
roleCommandRepo := &role_repository.RoleCommandRepository{DB: &db}
roleQueryRepo := &role_repository.RoleQueryRepository{DB: &db}
roleService := &services.RoleService{
CommandRepo: *roleCommandRepo,
QueryRepo: *roleQueryRepo,
}
role.POST("/",roleService.CreateRole,a.AdminRole)
role.GET("/:id" , roleService.GetRole)
role.PUT("/:id" , roleService.UpdateRole,a.AdminRole)
role.DELETE("/:id" , roleService.RemoveRole,a.AdminRole)
}

View File

@ -0,0 +1,93 @@
package authentication
import (
"errors"
"fmt"
"math/rand"
"netina/models"
"time"
"netina/validation"
"gorm.io/gorm"
)
type GenerateCode struct {
DB *gorm.DB
}
func NewGenerateCode(db *gorm.DB) *GenerateCode {
return &GenerateCode{DB: db}
}
// Generate a random 6-digit code
func generateCode() string {
rand.Seed(time.Now().UnixNano())
return fmt.Sprintf("%06d", rand.Intn(1000000))
}
// CreateLoginCode generates a login code and stores it in the database
func (s *GenerateCode) CreateLoginCode(phoneNumber string) (string, error) {
var code string
var isUnique bool
// Try to generate a unique code
for !isUnique {
code = generateCode()
isUnique, _ = s.isCodeUnique(code)
}
now := time.Now()
expiresAt := now.Add(2 * time.Minute)
loginCode := &models.LoginCode{
PhoneNumber: phoneNumber,
Code: code,
CreatedAt: now,
ExpiresAt: expiresAt,
}
if err := validation.ValidateStruct(loginCode); err != nil {
return "" , err
}
if err := s.DB.Create(loginCode).Error; err != nil {
return "", err
}
return code, nil
}
// Check if the generated code is unique
func (s *GenerateCode) isCodeUnique(code string) (bool, error) {
var loginCode models.LoginCode
if err := s.DB.Where("code = ?", code).First(&loginCode).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return true, nil
}
return false, err
}
return false, nil
}
// VerifyLoginCode verifies the login code and checks if it is still valid
func (s *GenerateCode) VerifyLoginCode(phoneNumber, code string) error {
var loginCode models.LoginCode
// Find the login code
if err := s.DB.Where("phone_number = ? AND code = ?", phoneNumber, code).First(&loginCode).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("code not found")
}
return err
}
// Check if the code has expired
if time.Now().After(loginCode.ExpiresAt) {
return errors.New("code expired")
}
return nil
}

View File

@ -0,0 +1,99 @@
package authentication
import (
"errors"
"netina/database"
Role_repository "netina/repositories/role"
User_repository "netina/repositories/user"
"os"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/joho/godotenv"
)
// JWTClaims defines the structure of JWT claims.
type JWTClaims struct {
ID uint `json:"id"`
Role string `json:"role"`
jwt.StandardClaims
}
// Load the environment variables from the .env file
func loadEnv() {
err := godotenv.Load("./config/.env")
if err != nil {
panic("Error loading .env file")
}
}
// GenerateJWT generates a new JWT token.
func GenerateJWT(claims *JWTClaims) (string, error) {
loadEnv()
secretKey := os.Getenv("SECRET_KEY")
if secretKey == "" {
return "", errors.New("SECRET_KEY is not set in the environment variables")
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(secretKey))
if err != nil {
return "", err
}
return tokenString, nil
}
// ValidateJWT validates a given JWT token.
func ValidateJWT(tokenString string) (*JWTClaims, error) {
loadEnv()
secretKey := os.Getenv("SECRET_KEY")
if secretKey == "" {
return nil, errors.New("SECRET_KEY is not set in the environment variables")
}
token, err := jwt.ParseWithClaims(tokenString, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, errors.New("unexpected signing method")
}
return []byte(secretKey), nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*JWTClaims); ok && token.Valid {
return claims, nil
}
return nil, errors.New("invalid token")
}
// GenerateClaims creates JWT claims.
func GenerateClaims(userID uint) (*JWTClaims , error) {
db := database.Db()
role_query := Role_repository.RoleQueryRepository{DB: &db}
user_query := User_repository.UserQueryRepository{DB: &db}
user , err := user_query.GetUser(userID)
if err != nil {
return nil , err
}
role , err := role_query.GetRole(user.Role_id)
if err != nil {
return nil , err
}
cliams := &JWTClaims{
ID: user.User_id,
Role: role.Name,
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(time.Hour * 2).Unix(),
},
}
return cliams , nil
}

View File

@ -0,0 +1,73 @@
package authentication
import (
"net/http"
"netina/database"
"netina/models"
u "netina/queries"
user_repository "netina/repositories/user"
sms "netina/services"
"netina/validation"
"github.com/labstack/echo/v4"
)
func RequestCode(c echo.Context) error {
db := database.Db()
gc := NewGenerateCode(&db)
phoneNumber := new(models.CreatePhoneNumber)
if err := c.Bind(phoneNumber); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request payload"})
}
if err := validation.ValidateStruct(phoneNumber); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
}
loginCode ,err := gc.CreateLoginCode(phoneNumber.PhoneNumber)
if err != nil {
return err
}
sms.Sms(phoneNumber.PhoneNumber , loginCode)
return nil
}
func Login(c echo.Context) error {
db := database.Db()
code := new(models.LoginCode)
if err := c.Bind(code); err != nil {
return err
}
if err := validation.ValidateStruct(code); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
}
gc := NewGenerateCode(&db)
if gc.VerifyLoginCode(code.PhoneNumber , code.Code) == nil {
ur := user_repository.UserQueryRepository{DB: &db}
userHandller := u.GetUserByPhoneNumberHandler{Repository: ur}
user , err := userHandller.Handle(code.PhoneNumber)
if err != nil {
return c.JSON(http.StatusNotFound , "user not found")
}
token , err:= GenerateTokenForUser(user.User_id)
if err != nil {
return err
}
return c.JSON(http.StatusAccepted , token)
} else {
return c.JSON(http.StatusBadRequest , "invalid Request")
}
}

View File

@ -0,0 +1,21 @@
package authentication
func GenerateTokenForUser(userID uint) (string, error) {
claims, err := GenerateClaims(userID)
if err != nil {
return "", err
}
token, err := GenerateJWT(claims)
if err != nil {
return "", err
}
return token, nil
}
func ValidateUserToken(tokenString string) (*JWTClaims, error) {
claims, err := ValidateJWT(tokenString)
if err != nil {
return nil, err
}
return claims, nil
}

View File

@ -0,0 +1,27 @@
package authorization
import (
j "netina/services/authentication"
"github.com/labstack/echo/v4"
)
func AdminRole(next echo.HandlerFunc)echo.HandlerFunc{
return func(c echo.Context)error{
user := c.Get("user").(*j.JWTClaims)
if user == nil {
return echo.ErrUnauthorized
}
if user.Role != "admin" {
return echo.ErrForbidden
}
return next(c)
}
}

View File

@ -12,6 +12,7 @@ import (
"github.com/labstack/echo/v4"
)
type LicenseService struct {
CommandRepo license_repository.LicenseCommandRepository
QueryRepo license_repository.LicenseQueryRepository

87
services/role.go 100644
View File

@ -0,0 +1,87 @@
package services
import (
"net/http"
"netina/commands"
cm "netina/models/commands"
"netina/queries"
Role_repository "netina/repositories/role"
"netina/validation"
"strconv"
"github.com/labstack/echo/v4"
)
type RoleService struct {
CommandRepo Role_repository.RoleCommandRepository
QueryRepo Role_repository.RoleQueryRepository
}
func (s *RoleService) CreateRole(c echo.Context) error {
role := new(cm.CreateRoleCommand)
if err := c.Bind(role); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request payload"})
}
if err := validation.ValidateStruct(role); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
}
handler := commands.CreateRoleHandler{Repository: s.CommandRepo}
if err := handler.Handle(*role); err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
return c.JSON(http.StatusCreated, role)
}
func (s *RoleService) GetRole(c echo.Context) error {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid role ID"})
}
handler := queries.GetRoleHandler{Repository: s.QueryRepo}
role, err := handler.Handle(uint(id))
if err != nil {
return c.JSON(http.StatusNotFound, map[string]string{"error": err.Error()})
}
return c.JSON(http.StatusOK, role)
}
func (s *RoleService) UpdateRole(c echo.Context) error {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid role ID"})
}
role := new(cm.UpdateRoleCommand)
if err := c.Bind(role); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request payload"})
}
if err := validation.ValidateStruct(role); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
}
handler := commands.UpdateRoleHandler{Repository: s.CommandRepo}
updatedRole, err := handler.Handle(uint(id), *role)
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
return c.JSON(http.StatusOK, updatedRole)
}
func (s *RoleService) RemoveRole(c echo.Context) error {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid Role ID"})
}
handler := commands.RemoveRoleHandler{Repository: s.CommandRepo}
if err := handler.Handle(uint(id)); err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
return c.NoContent(http.StatusNoContent)
}

29
services/sms.go 100644
View File

@ -0,0 +1,29 @@
package services
import (
"fmt"
"github.com/kavenegar/kavenegar-go"
)
func Sms(phoneNumber string , loginCode string) {
api := kavenegar.New("65334B6A70303233432B7A6530795A51683134524945742F74397161785568512B794966623245744C2F773D")
receptor := phoneNumber
template := "verify"
token := loginCode
params := &kavenegar.VerifyLookupParam{
}
if res, err := api.Verify.Lookup(receptor, template, token, params); err != nil {
switch err := err.(type) {
case *kavenegar.APIError:
fmt.Println(err.Error())
case *kavenegar.HTTPError:
fmt.Println(err.Error())
default:
fmt.Println(err.Error())
}
} else {
fmt.Println("MessageID = ", res.MessageID)
fmt.Println("Status = ", res.Status)
//...
}
}

106
services/user.go 100644
View File

@ -0,0 +1,106 @@
package services
import (
"net/http"
"netina/commands"
"netina/models"
cm "netina/models/commands"
"netina/queries"
User_repository "netina/repositories/user"
"netina/validation"
"strconv"
"github.com/labstack/echo/v4"
)
type UserService struct {
CommandRepo User_repository.UserCommandRepository
QueryRepo User_repository.UserQueryRepository
}
func (s *UserService) CreateUser(c echo.Context) error {
user := new(cm.CreateUserCommand)
if err := c.Bind(user); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request payload"})
}
if err := validation.ValidateStruct(user); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
}
handler := commands.CreateUserHandler{Repository: s.CommandRepo}
if err := handler.Handle(*user); err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
return c.JSON(http.StatusCreated, user)
}
func (s *UserService) GetUser(c echo.Context) error {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid User ID"})
}
handler := queries.GetUserByIdHandler{Repository: s.QueryRepo}
User, err := handler.Handle(uint(id))
if err != nil {
return c.JSON(http.StatusNotFound, map[string]string{"error": err.Error()})
}
return c.JSON(http.StatusOK, User)
}
func (s *UserService) GetUserByPhoneNumber(c echo.Context) error {
number := new(models.CreatePhoneNumber)
if err := c.Bind(number); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid phone number"})
}
handler := queries.GetUserByPhoneNumberHandler{Repository: s.QueryRepo}
user , err := handler.Handle(number.PhoneNumber)
if err != nil {
return c.JSON(http.StatusNotFound, map[string]string{"error": err.Error()})
}
return c.JSON(http.StatusOK , user)
}
func (s *UserService) UpdateUser(c echo.Context) error {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid User ID"})
}
User := new(cm.UpdateUserCommand)
if err := c.Bind(User); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid request payload"})
}
if err := validation.ValidateStruct(User); err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": err.Error()})
}
handler := commands.UpdateUserHandler{Repository: s.CommandRepo}
updatedUser, err := handler.Handle(uint(id), *User)
if err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
return c.JSON(http.StatusOK, updatedUser)
}
func (s *UserService) RemoveUser(c echo.Context) error {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "Invalid User ID"})
}
handler := commands.RemoveUserHandler{Repository: s.CommandRepo}
if err := handler.Handle(uint(id)); err != nil {
return c.JSON(http.StatusInternalServerError, map[string]string{"error": err.Error()})
}
return c.NoContent(http.StatusNoContent)
}