Skip to content

Commit 92d2789

Browse files
authored
Merge pull request #46 from Arjuna-Ragil/feat/41-project-invite
Feat/41 project invite
2 parents 39bc529 + 9571a10 commit 92d2789

18 files changed

Lines changed: 684 additions & 75 deletions

File tree

Internal/adapters/repository/postgres.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func (db *DBContainer) Migrate() error {
4242
&domain.User{},
4343
&domain.Invitation{},
4444
&domain.Project{},
45+
&domain.ProjectUser{},
4546
)
4647
if err != nil {
4748
log.Fatalf("Failed to migrate users: %v", err)

Internal/adapters/repository/projectRepo.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,31 @@ func (pr *ProjectRepo) FetchProjects(projects []domain.Project) ([]domain.Projec
2828

2929
func (pr *ProjectRepo) ProjectById(id string) (*domain.Project, error) {
3030
var project domain.Project
31-
if err := pr.DB.Gorm.First(&project, id).Error; err != nil {
31+
if err := pr.DB.Gorm.Preload("ProjectUsers.User").First(&project, id).Error; err != nil {
3232
return nil, err
3333
}
3434
return &project, nil
3535
}
36+
37+
func (pr *ProjectRepo) InviteProject(projectuser *domain.ProjectUser) (*domain.ProjectUser, error) {
38+
if err := pr.DB.Gorm.Create(projectuser).Error; err != nil {
39+
return nil, err
40+
}
41+
return projectuser, nil
42+
}
43+
44+
func (pr *ProjectRepo) ProjectUserCheck(userID uint) (*domain.ProjectUser, error) {
45+
var projectuser domain.ProjectUser
46+
if err := pr.DB.Gorm.First(&projectuser, userID).Error; err != nil {
47+
return nil, err
48+
}
49+
return &projectuser, nil
50+
}
51+
52+
func (pr *ProjectRepo) RemoveProjectUser(id uint) error {
53+
var projectuser domain.ProjectUser
54+
if err := pr.DB.Gorm.Delete(&projectuser, id).Error; err != nil {
55+
return err
56+
}
57+
return nil
58+
}

Internal/adapters/repository/userRepo.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,21 @@ func NewUserRepository(db *DBContainer) *UserRepository {
1717
// Query
1818

1919
func (ur *UserRepository) save(user *domain.User) error {
20+
2021
return ur.db.Gorm.Create(user).Error
2122
}
2223

2324
func (ur *UserRepository) FindById(id uint) (*domain.User, error) {
2425
var user domain.User
25-
err := ur.db.Gorm.First(&user, id).Error
26+
if err := ur.db.Gorm.Preload("Projects.Project").First(&user, id).Error; err != nil {
27+
return nil, err
28+
}
29+
return &user, nil
30+
}
31+
32+
func (ur *UserRepository) FindByEmail(email string) (*domain.User, error) {
33+
var user domain.User
34+
err := ur.db.Gorm.Where("email = ?", email).First(&user).Error
2635
if err != nil {
2736
return nil, err
2837
}

Internal/api/Routes/routev1.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ func SetupRouterV1(r *gin.Engine, deps Deps) {
5252
{
5353
project.GET("/projects", deps.Project.GetAllProjectHandler)
5454
project.GET("/:projectid", deps.Project.GetProjectHandler)
55+
56+
manage := project.Group("/manage")
57+
{
58+
manage.POST("/invite/:projectid", deps.Project.InviteProjectHandler)
59+
manage.DELETE("/remove/:projuserid", deps.Project.RemoveProjectUserHandler)
60+
}
5561
}
5662
}
5763
}

Internal/api/handlers/projectHandler.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package handlers
22

33
import (
4+
"strconv"
5+
46
"github.com/Arjuna-Ragil/Localbase/Internal/core/services"
57
"github.com/gin-gonic/gin"
68
)
@@ -77,3 +79,62 @@ func (ph *ProjectHandler) GetProjectHandler(c *gin.Context) {
7779
"data": project,
7880
})
7981
}
82+
83+
func (ph *ProjectHandler) InviteProjectHandler(c *gin.Context) {
84+
projectIDStr := c.Param("projectid")
85+
projectID, err := strconv.Atoi(projectIDStr)
86+
if err != nil {
87+
c.JSON(400, gin.H{
88+
"message": "Invalid Project ID",
89+
"error": err.Error(),
90+
})
91+
return
92+
}
93+
userRole := c.GetString("userRole")
94+
userID := c.GetUint("userId")
95+
var input services.InviteProjectInput
96+
if err := c.ShouldBindJSON(&input); err != nil {
97+
c.JSON(400, gin.H{
98+
"message": "Invalid input",
99+
"data": err.Error(),
100+
})
101+
return
102+
}
103+
invite, err := ph.ProjectService.InviteProject(&input, userRole, userID, uint(projectID))
104+
if err != nil {
105+
c.JSON(500, gin.H{
106+
"message": "failed to invite project",
107+
"data": err.Error(),
108+
})
109+
return
110+
}
111+
c.JSON(200, gin.H{
112+
"message": "successfully invited project",
113+
"data": invite,
114+
})
115+
}
116+
117+
func (ph *ProjectHandler) RemoveProjectUserHandler(c *gin.Context) {
118+
projectUserSTR := c.Param("projuserid")
119+
projectUserID, err := strconv.Atoi(projectUserSTR)
120+
if err != nil {
121+
c.JSON(400, gin.H{
122+
"message": "Invalid Project ID",
123+
"error": err.Error(),
124+
})
125+
return
126+
}
127+
userRole := c.GetString("userRole")
128+
userID := c.GetUint("userId")
129+
if err := ph.ProjectService.DeleteProjectUser(uint(projectUserID), userRole, userID); err != nil {
130+
c.JSON(500, gin.H{
131+
"message": "failed to remove project user",
132+
"data": err.Error(),
133+
})
134+
return
135+
}
136+
c.JSON(200, gin.H{
137+
"message": "successfully removed project user",
138+
"data": nil,
139+
})
140+
}

Internal/api/middleware/auth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func AuthMiddleware(userRepo *repository.UserRepository, cfg *config.Config) gin
7171
return
7272
}
7373

74-
c.Set("userID", user.Id)
74+
c.Set("userID", user.ID)
7575
c.Set("userRole", user.Role)
7676
c.Next()
7777

Internal/core/domain/projectdb.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,22 @@ package domain
33
import "time"
44

55
type Project struct {
6-
ID uint `gorm:"primary_key;auto_increment" json:"id"`
7-
Name string `gorm:"size:255;not null" json:"name"`
8-
Desc string `gorm:"size:255;" json:"desc"`
9-
AdminID uint `json:"admin_id"`
6+
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
7+
Name string `gorm:"size:255;not null" json:"name"`
8+
Desc string `gorm:"size:255;" json:"desc"`
9+
AdminID uint `json:"admin_id"`
10+
ProjectUsers []ProjectUser `json:"project_users,omitempty"`
11+
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
12+
}
13+
14+
type ProjectUser struct {
15+
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
16+
ProjectID uint `json:"project_id"`
17+
UserID uint `json:"user_id"`
18+
Project *Project `json:"project,omitempty"`
19+
User *User `json:"user,omitempty"`
20+
Role string `gorm:"size:255;not null" json:"role"`
1021
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
1122
}
23+
24+
//Changes last savepoint

Internal/core/domain/userdb.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,18 @@ import (
88
)
99

1010
type User struct {
11-
Id uint `gorm:"primary_key;AUTO_INCREMENT" json:"id"`
12-
Email string `gorm:"size:255;unique;not null" json:"email"`
13-
Password string `json:"-"`
14-
Username string `gorm:"size:255;unique;not null" json:"username"`
15-
Role string `gorm:"size:255;not null" json:"role"`
16-
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
17-
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
11+
ID uint `gorm:"primaryKey;autoIncrement" json:"id"`
12+
Email string `gorm:"size:255;unique;not null" json:"email"`
13+
Password string `json:"-"`
14+
Username string `gorm:"size:255;unique;not null" json:"username"`
15+
Role string `gorm:"size:255;not null" json:"role"`
16+
Projects []ProjectUser `json:"projects"`
17+
CreatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"created_at"`
18+
UpdatedAt time.Time `gorm:"default:CURRENT_TIMESTAMP" json:"updated_at"`
1819
}
1920

21+
//last chnages savepoint
22+
2023
func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
2124
if len(u.Password) < 50 {
2225
hashed, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)

Internal/core/services/authService.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ func (as *AuthService) LoginService(input *LoginInput) (string, error) {
9595
return "", err
9696
}
9797
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
98-
"sub": user.Id,
98+
"sub": user.ID,
9999
"exp": time.Now().Add(time.Hour * 48).Unix(),
100100
})
101101
tokenString, err := token.SignedString([]byte(cfg.SecretKey))

Internal/core/services/projectService.go

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import (
99

1010
type ProjectService struct {
1111
ProjectRepo *repository.ProjectRepo
12+
UserRepo *repository.UserRepository
1213
}
1314

14-
func NewProjectService(projectRepo *repository.ProjectRepo) *ProjectService {
15-
return &ProjectService{ProjectRepo: projectRepo}
15+
func NewProjectService(project *repository.ProjectRepo, user *repository.UserRepository) *ProjectService {
16+
return &ProjectService{ProjectRepo: project, UserRepo: user}
1617
}
1718

1819
type CreateInput struct {
@@ -21,6 +22,11 @@ type CreateInput struct {
2122
AdminID uint `json:"admin_id"`
2223
}
2324

25+
type InviteProjectInput struct {
26+
Email string `json:"email"`
27+
Role string `json:"role"`
28+
}
29+
2430
func (ps *ProjectService) CreateProject(input *CreateInput) (*domain.Project, error) {
2531
projectInfo := domain.Project{
2632
Name: input.Name,
@@ -53,3 +59,45 @@ func (ps *ProjectService) GetProjectById(id string) (*domain.Project, error) {
5359
}
5460
return project, nil
5561
}
62+
63+
func (ps *ProjectService) InviteProject(input *InviteProjectInput, Role string, userID uint, projectID uint) (*domain.ProjectUser, error) {
64+
if Role != "admin" {
65+
prorole, err := ps.ProjectRepo.ProjectUserCheck(userID)
66+
if err != nil {
67+
return nil, errors.New("user is not part of project")
68+
}
69+
if prorole.Role != "lead" {
70+
return nil, errors.New("permission denied")
71+
}
72+
}
73+
user, err := ps.UserRepo.FindByEmail(input.Email)
74+
if err != nil {
75+
return nil, err
76+
}
77+
var inviteInfo = domain.ProjectUser{
78+
ProjectID: projectID,
79+
UserID: user.ID,
80+
Role: input.Role,
81+
}
82+
project, err := ps.ProjectRepo.InviteProject(&inviteInfo)
83+
if err != nil {
84+
return nil, err
85+
}
86+
return project, nil
87+
}
88+
89+
func (ps *ProjectService) DeleteProjectUser(id uint, Role string, userID uint) error {
90+
if Role != "admin" {
91+
prorole, err := ps.ProjectRepo.ProjectUserCheck(userID)
92+
if err != nil {
93+
return errors.New("user is not part of project")
94+
}
95+
if prorole.Role != "lead" {
96+
return errors.New("permission denied")
97+
}
98+
}
99+
if err := ps.ProjectRepo.RemoveProjectUser(id); err != nil {
100+
return err
101+
}
102+
return nil
103+
}

0 commit comments

Comments
 (0)