ALL 0.1.0 Code
This commit is contained in:
633
server/internal/handlers/projects.go
Normal file
633
server/internal/handlers/projects.go
Normal file
@@ -0,0 +1,633 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/fpmb/server/internal/database"
|
||||
"github.com/fpmb/server/internal/models"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
func getProjectRole(ctx context.Context, projectID, userID primitive.ObjectID) (int, error) {
|
||||
var pm models.ProjectMember
|
||||
err := database.GetCollection("project_members").FindOne(ctx, bson.M{
|
||||
"project_id": projectID,
|
||||
"user_id": userID,
|
||||
}).Decode(&pm)
|
||||
if err == nil {
|
||||
return pm.RoleFlags, nil
|
||||
}
|
||||
|
||||
var project models.Project
|
||||
if err := database.GetCollection("projects").FindOne(ctx, bson.M{"_id": projectID}).Decode(&project); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if project.TeamID == primitive.NilObjectID {
|
||||
return 0, fiber.ErrForbidden
|
||||
}
|
||||
|
||||
return getTeamRole(ctx, project.TeamID, userID)
|
||||
}
|
||||
|
||||
func ListProjects(c *fiber.Ctx) error {
|
||||
userID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
type ProjectResponse struct {
|
||||
ID primitive.ObjectID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
TeamID primitive.ObjectID `json:"team_id"`
|
||||
TeamName string `json:"team_name"`
|
||||
RoleFlags int `json:"role_flags"`
|
||||
RoleName string `json:"role_name"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
IsArchived bool `json:"is_archived"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
result := []ProjectResponse{}
|
||||
|
||||
cursor, err := database.GetCollection("team_members").Find(ctx, bson.M{"user_id": userID})
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to fetch teams"})
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
var memberships []models.TeamMember
|
||||
cursor.All(ctx, &memberships)
|
||||
|
||||
for _, m := range memberships {
|
||||
var team models.Team
|
||||
database.GetCollection("teams").FindOne(ctx, bson.M{"_id": m.TeamID}).Decode(&team)
|
||||
|
||||
projCursor, err := database.GetCollection("projects").Find(ctx, bson.M{"team_id": m.TeamID})
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var projects []models.Project
|
||||
projCursor.All(ctx, &projects)
|
||||
projCursor.Close(ctx)
|
||||
|
||||
for _, p := range projects {
|
||||
roleFlags := m.RoleFlags
|
||||
var pm models.ProjectMember
|
||||
if err := database.GetCollection("project_members").FindOne(ctx, bson.M{
|
||||
"project_id": p.ID,
|
||||
"user_id": userID,
|
||||
}).Decode(&pm); err == nil {
|
||||
roleFlags = pm.RoleFlags
|
||||
}
|
||||
|
||||
result = append(result, ProjectResponse{
|
||||
ID: p.ID,
|
||||
Name: p.Name,
|
||||
Description: p.Description,
|
||||
TeamID: p.TeamID,
|
||||
TeamName: team.Name,
|
||||
RoleFlags: roleFlags,
|
||||
RoleName: roleName(roleFlags),
|
||||
IsPublic: p.IsPublic,
|
||||
IsArchived: p.IsArchived,
|
||||
UpdatedAt: p.UpdatedAt,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
personalCursor, err := database.GetCollection("project_members").Find(ctx, bson.M{
|
||||
"user_id": userID,
|
||||
})
|
||||
if err == nil {
|
||||
defer personalCursor.Close(ctx)
|
||||
var pms []models.ProjectMember
|
||||
personalCursor.All(ctx, &pms)
|
||||
for _, pm := range pms {
|
||||
var p models.Project
|
||||
if err := database.GetCollection("projects").FindOne(ctx, bson.M{
|
||||
"_id": pm.ProjectID,
|
||||
"team_id": primitive.NilObjectID,
|
||||
}).Decode(&p); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, ProjectResponse{
|
||||
ID: p.ID,
|
||||
Name: p.Name,
|
||||
Description: p.Description,
|
||||
TeamID: p.TeamID,
|
||||
TeamName: "Personal",
|
||||
RoleFlags: pm.RoleFlags,
|
||||
RoleName: roleName(pm.RoleFlags),
|
||||
IsPublic: p.IsPublic,
|
||||
IsArchived: p.IsArchived,
|
||||
UpdatedAt: p.UpdatedAt,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return c.JSON(result)
|
||||
}
|
||||
|
||||
func CreatePersonalProject(c *fiber.Ctx) error {
|
||||
userID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
var body struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
}
|
||||
if err := c.BodyParser(&body); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"})
|
||||
}
|
||||
if body.Name == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Project name is required"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
now := time.Now()
|
||||
project := &models.Project{
|
||||
ID: primitive.NewObjectID(),
|
||||
TeamID: primitive.NilObjectID,
|
||||
Name: body.Name,
|
||||
Description: body.Description,
|
||||
IsPublic: body.IsPublic,
|
||||
IsArchived: false,
|
||||
CreatedBy: userID,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
if _, err := database.GetCollection("projects").InsertOne(ctx, project); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to create project"})
|
||||
}
|
||||
|
||||
member := &models.ProjectMember{
|
||||
ID: primitive.NewObjectID(),
|
||||
ProjectID: project.ID,
|
||||
UserID: userID,
|
||||
RoleFlags: RoleOwner,
|
||||
AddedAt: now,
|
||||
}
|
||||
database.GetCollection("project_members").InsertOne(ctx, member)
|
||||
|
||||
defaultColumns := []string{"To Do", "In Progress", "Done"}
|
||||
for i, title := range defaultColumns {
|
||||
col := &models.BoardColumn{
|
||||
ID: primitive.NewObjectID(),
|
||||
ProjectID: project.ID,
|
||||
Title: title,
|
||||
Position: i,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
database.GetCollection("board_columns").InsertOne(ctx, col)
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(project)
|
||||
}
|
||||
|
||||
func ListTeamProjects(c *fiber.Ctx) error {
|
||||
userID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
teamID, err := primitive.ObjectIDFromHex(c.Params("teamId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid team ID"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
teamRole, err := getTeamRole(ctx, teamID, userID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "Access denied"})
|
||||
}
|
||||
|
||||
cursor, err := database.GetCollection("projects").Find(ctx, bson.M{"team_id": teamID},
|
||||
options.Find().SetSort(bson.M{"updated_at": -1}))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to fetch projects"})
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
var projects []models.Project
|
||||
cursor.All(ctx, &projects)
|
||||
|
||||
type ProjectResponse struct {
|
||||
models.Project
|
||||
RoleFlags int `json:"role_flags"`
|
||||
RoleName string `json:"role_name"`
|
||||
}
|
||||
|
||||
result := []ProjectResponse{}
|
||||
for _, p := range projects {
|
||||
flags := teamRole
|
||||
var pm models.ProjectMember
|
||||
if err := database.GetCollection("project_members").FindOne(ctx, bson.M{
|
||||
"project_id": p.ID, "user_id": userID,
|
||||
}).Decode(&pm); err == nil {
|
||||
flags = pm.RoleFlags
|
||||
}
|
||||
result = append(result, ProjectResponse{Project: p, RoleFlags: flags, RoleName: roleName(flags)})
|
||||
}
|
||||
|
||||
return c.JSON(result)
|
||||
}
|
||||
|
||||
func CreateProject(c *fiber.Ctx) error {
|
||||
userID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
teamID, err := primitive.ObjectIDFromHex(c.Params("teamId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid team ID"})
|
||||
}
|
||||
|
||||
var body struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
IsPublic bool `json:"is_public"`
|
||||
}
|
||||
if err := c.BodyParser(&body); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"})
|
||||
}
|
||||
if body.Name == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Project name is required"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
roleFlags, err := getTeamRole(ctx, teamID, userID)
|
||||
if err != nil || !hasPermission(roleFlags, RoleEditor) {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "Insufficient permissions"})
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
project := &models.Project{
|
||||
ID: primitive.NewObjectID(),
|
||||
TeamID: teamID,
|
||||
Name: body.Name,
|
||||
Description: body.Description,
|
||||
IsPublic: body.IsPublic,
|
||||
IsArchived: false,
|
||||
CreatedBy: userID,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
if _, err := database.GetCollection("projects").InsertOne(ctx, project); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to create project"})
|
||||
}
|
||||
|
||||
defaultColumns := []string{"To Do", "In Progress", "Done"}
|
||||
for i, title := range defaultColumns {
|
||||
col := &models.BoardColumn{
|
||||
ID: primitive.NewObjectID(),
|
||||
ProjectID: project.ID,
|
||||
Title: title,
|
||||
Position: i,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
database.GetCollection("board_columns").InsertOne(ctx, col)
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusCreated).JSON(project)
|
||||
}
|
||||
|
||||
func GetProject(c *fiber.Ctx) error {
|
||||
userID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
projectID, err := primitive.ObjectIDFromHex(c.Params("projectId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid project ID"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
roleFlags, err := getProjectRole(ctx, projectID, userID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "Access denied"})
|
||||
}
|
||||
|
||||
var project models.Project
|
||||
if err := database.GetCollection("projects").FindOne(ctx, bson.M{"_id": projectID}).Decode(&project); err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Project not found"})
|
||||
}
|
||||
|
||||
return c.JSON(fiber.Map{
|
||||
"id": project.ID,
|
||||
"team_id": project.TeamID,
|
||||
"name": project.Name,
|
||||
"description": project.Description,
|
||||
"visibility": project.Visibility,
|
||||
"is_public": project.IsPublic,
|
||||
"is_archived": project.IsArchived,
|
||||
"role_flags": roleFlags,
|
||||
"role_name": roleName(roleFlags),
|
||||
"created_at": project.CreatedAt,
|
||||
"updated_at": project.UpdatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
func UpdateProject(c *fiber.Ctx) error {
|
||||
userID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
projectID, err := primitive.ObjectIDFromHex(c.Params("projectId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid project ID"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
roleFlags, err := getProjectRole(ctx, projectID, userID)
|
||||
if err != nil || !hasPermission(roleFlags, RoleAdmin) {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "Insufficient permissions"})
|
||||
}
|
||||
|
||||
var body struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
IsPublic *bool `json:"is_public"`
|
||||
Visibility string `json:"visibility"`
|
||||
}
|
||||
if err := c.BodyParser(&body); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"})
|
||||
}
|
||||
|
||||
update := bson.M{"updated_at": time.Now()}
|
||||
if body.Name != "" {
|
||||
update["name"] = body.Name
|
||||
}
|
||||
if body.Description != "" {
|
||||
update["description"] = body.Description
|
||||
}
|
||||
if body.IsPublic != nil {
|
||||
update["is_public"] = *body.IsPublic
|
||||
}
|
||||
if body.Visibility != "" {
|
||||
update["visibility"] = body.Visibility
|
||||
update["is_public"] = body.Visibility == "public"
|
||||
}
|
||||
|
||||
col := database.GetCollection("projects")
|
||||
col.UpdateOne(ctx, bson.M{"_id": projectID}, bson.M{"$set": update})
|
||||
|
||||
var project models.Project
|
||||
col.FindOne(ctx, bson.M{"_id": projectID}).Decode(&project)
|
||||
return c.JSON(project)
|
||||
}
|
||||
|
||||
func ArchiveProject(c *fiber.Ctx) error {
|
||||
userID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
projectID, err := primitive.ObjectIDFromHex(c.Params("projectId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid project ID"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
roleFlags, err := getProjectRole(ctx, projectID, userID)
|
||||
if err != nil || !hasPermission(roleFlags, RoleAdmin) {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "Insufficient permissions"})
|
||||
}
|
||||
|
||||
var project models.Project
|
||||
if err := database.GetCollection("projects").FindOne(ctx, bson.M{"_id": projectID}).Decode(&project); err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "Project not found"})
|
||||
}
|
||||
|
||||
database.GetCollection("projects").UpdateOne(ctx, bson.M{"_id": projectID}, bson.M{"$set": bson.M{
|
||||
"is_archived": !project.IsArchived,
|
||||
"updated_at": time.Now(),
|
||||
}})
|
||||
|
||||
return c.JSON(fiber.Map{"is_archived": !project.IsArchived})
|
||||
}
|
||||
|
||||
func DeleteProject(c *fiber.Ctx) error {
|
||||
userID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
projectID, err := primitive.ObjectIDFromHex(c.Params("projectId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid project ID"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
roleFlags, err := getProjectRole(ctx, projectID, userID)
|
||||
if err != nil || !hasPermission(roleFlags, RoleOwner) {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "Only owners can delete projects"})
|
||||
}
|
||||
|
||||
database.GetCollection("projects").DeleteOne(ctx, bson.M{"_id": projectID})
|
||||
database.GetCollection("board_columns").DeleteMany(ctx, bson.M{"project_id": projectID})
|
||||
database.GetCollection("cards").DeleteMany(ctx, bson.M{"project_id": projectID})
|
||||
database.GetCollection("project_members").DeleteMany(ctx, bson.M{"project_id": projectID})
|
||||
database.GetCollection("events").DeleteMany(ctx, bson.M{"scope_id": projectID, "scope": "project"})
|
||||
database.GetCollection("files").DeleteMany(ctx, bson.M{"project_id": projectID})
|
||||
database.GetCollection("webhooks").DeleteMany(ctx, bson.M{"project_id": projectID})
|
||||
database.GetCollection("whiteboards").DeleteMany(ctx, bson.M{"project_id": projectID})
|
||||
|
||||
return c.JSON(fiber.Map{"message": "Project deleted"})
|
||||
}
|
||||
|
||||
func ListProjectMembers(c *fiber.Ctx) error {
|
||||
userID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
projectID, err := primitive.ObjectIDFromHex(c.Params("projectId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid project ID"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
if _, err := getProjectRole(ctx, projectID, userID); err != nil {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "Access denied"})
|
||||
}
|
||||
|
||||
cursor, err := database.GetCollection("project_members").Find(ctx, bson.M{"project_id": projectID})
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to fetch members"})
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
var members []models.ProjectMember
|
||||
cursor.All(ctx, &members)
|
||||
|
||||
type MemberResponse struct {
|
||||
UserID primitive.ObjectID `json:"user_id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
RoleFlags int `json:"role_flags"`
|
||||
RoleName string `json:"role_name"`
|
||||
}
|
||||
|
||||
result := []MemberResponse{}
|
||||
for _, m := range members {
|
||||
var user models.User
|
||||
if err := database.GetCollection("users").FindOne(ctx, bson.M{"_id": m.UserID}).Decode(&user); err != nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, MemberResponse{
|
||||
UserID: m.UserID,
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
RoleFlags: m.RoleFlags,
|
||||
RoleName: roleName(m.RoleFlags),
|
||||
})
|
||||
}
|
||||
return c.JSON(result)
|
||||
}
|
||||
|
||||
func AddProjectMember(c *fiber.Ctx) error {
|
||||
requesterID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
projectID, err := primitive.ObjectIDFromHex(c.Params("projectId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid project ID"})
|
||||
}
|
||||
|
||||
var body struct {
|
||||
UserID string `json:"user_id"`
|
||||
RoleFlags int `json:"role_flags"`
|
||||
}
|
||||
if err := c.BodyParser(&body); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid request body"})
|
||||
}
|
||||
|
||||
targetUserID, err := primitive.ObjectIDFromHex(body.UserID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid user_id"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
roleFlags, err := getProjectRole(ctx, projectID, requesterID)
|
||||
if err != nil || !hasPermission(roleFlags, RoleAdmin) {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "Insufficient permissions"})
|
||||
}
|
||||
|
||||
flags := body.RoleFlags
|
||||
if flags == 0 {
|
||||
flags = RoleViewer
|
||||
}
|
||||
|
||||
member := &models.ProjectMember{
|
||||
ID: primitive.NewObjectID(),
|
||||
ProjectID: projectID,
|
||||
UserID: targetUserID,
|
||||
RoleFlags: flags,
|
||||
AddedAt: time.Now(),
|
||||
}
|
||||
database.GetCollection("project_members").InsertOne(ctx, member)
|
||||
return c.Status(fiber.StatusCreated).JSON(member)
|
||||
}
|
||||
|
||||
func UpdateProjectMemberRole(c *fiber.Ctx) error {
|
||||
requesterID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
projectID, err := primitive.ObjectIDFromHex(c.Params("projectId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid project ID"})
|
||||
}
|
||||
|
||||
targetUserID, err := primitive.ObjectIDFromHex(c.Params("userId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid user ID"})
|
||||
}
|
||||
|
||||
var body struct {
|
||||
RoleFlags int `json:"role_flags"`
|
||||
}
|
||||
c.BodyParser(&body)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
roleFlags, err := getProjectRole(ctx, projectID, requesterID)
|
||||
if err != nil || !hasPermission(roleFlags, RoleAdmin) {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "Insufficient permissions"})
|
||||
}
|
||||
|
||||
database.GetCollection("project_members").UpdateOne(ctx,
|
||||
bson.M{"project_id": projectID, "user_id": targetUserID},
|
||||
bson.M{"$set": bson.M{"role_flags": body.RoleFlags}},
|
||||
)
|
||||
return c.JSON(fiber.Map{"user_id": targetUserID, "role_flags": body.RoleFlags, "role_name": roleName(body.RoleFlags)})
|
||||
}
|
||||
|
||||
func RemoveProjectMember(c *fiber.Ctx) error {
|
||||
requesterID, err := primitive.ObjectIDFromHex(c.Locals("user_id").(string))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid user"})
|
||||
}
|
||||
|
||||
projectID, err := primitive.ObjectIDFromHex(c.Params("projectId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid project ID"})
|
||||
}
|
||||
|
||||
targetUserID, err := primitive.ObjectIDFromHex(c.Params("userId"))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid user ID"})
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
roleFlags, err := getProjectRole(ctx, projectID, requesterID)
|
||||
if err != nil || !hasPermission(roleFlags, RoleAdmin) {
|
||||
return c.Status(fiber.StatusForbidden).JSON(fiber.Map{"error": "Insufficient permissions"})
|
||||
}
|
||||
|
||||
database.GetCollection("project_members").DeleteOne(ctx, bson.M{"project_id": projectID, "user_id": targetUserID})
|
||||
return c.JSON(fiber.Map{"message": "Member removed"})
|
||||
}
|
||||
Reference in New Issue
Block a user