feat: Updated admin panel styles
This commit is contained in:
@@ -17,6 +17,8 @@ import (
|
||||
type AdminService struct {
|
||||
userRepo repositories.UserRepository
|
||||
groupRepo repositories.GroupRepository
|
||||
providerRepo repositories.AuthProviderRepository
|
||||
linkRepo repositories.UserProviderLinkRepository
|
||||
spaceRepo repositories.SpaceRepository
|
||||
membershipRepo repositories.MembershipRepository
|
||||
noteRepo repositories.NoteRepository
|
||||
@@ -30,6 +32,8 @@ type AdminService struct {
|
||||
func NewAdminService(
|
||||
userRepo repositories.UserRepository,
|
||||
groupRepo repositories.GroupRepository,
|
||||
providerRepo repositories.AuthProviderRepository,
|
||||
linkRepo repositories.UserProviderLinkRepository,
|
||||
spaceRepo repositories.SpaceRepository,
|
||||
membershipRepo repositories.MembershipRepository,
|
||||
noteRepo repositories.NoteRepository,
|
||||
@@ -41,6 +45,8 @@ func NewAdminService(
|
||||
return &AdminService{
|
||||
userRepo: userRepo,
|
||||
groupRepo: groupRepo,
|
||||
providerRepo: providerRepo,
|
||||
linkRepo: linkRepo,
|
||||
spaceRepo: spaceRepo,
|
||||
membershipRepo: membershipRepo,
|
||||
noteRepo: noteRepo,
|
||||
@@ -51,6 +57,114 @@ func NewAdminService(
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteUser deletes a user and related memberships/provider links.
|
||||
func (s *AdminService) DeleteUser(ctx context.Context, currentUserID, targetUserID bson.ObjectID) error {
|
||||
if currentUserID == targetUserID {
|
||||
return errors.New("you cannot delete your own account")
|
||||
}
|
||||
|
||||
spaces, err := s.spaceRepo.GetAllSpaces(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, space := range spaces {
|
||||
if space.OwnerID == targetUserID {
|
||||
return errors.New("cannot delete user that owns spaces; transfer or delete spaces first")
|
||||
}
|
||||
}
|
||||
|
||||
memberships, err := s.membershipRepo.GetUserMemberships(ctx, targetUserID)
|
||||
if err == nil {
|
||||
for _, membership := range memberships {
|
||||
if err := s.membershipRepo.DeleteMembership(ctx, membership.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.linkRepo != nil {
|
||||
links, err := s.linkRepo.GetUserLinks(ctx, targetUserID)
|
||||
if err == nil {
|
||||
for _, link := range links {
|
||||
if err := s.linkRepo.DeleteLink(ctx, link.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s.userRepo.DeleteUser(ctx, targetUserID)
|
||||
}
|
||||
|
||||
// DeleteGroup deletes a non-system group and removes it from users.
|
||||
func (s *AdminService) DeleteGroup(ctx context.Context, groupID bson.ObjectID) error {
|
||||
group, err := s.groupRepo.GetGroupByID(ctx, groupID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if group.IsSystem {
|
||||
return errors.New("system groups cannot be deleted")
|
||||
}
|
||||
|
||||
users, err := s.userRepo.ListAllUsers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, user := range users {
|
||||
filtered := make([]bson.ObjectID, 0, len(user.GroupIDs))
|
||||
changed := false
|
||||
for _, assignedGroupID := range user.GroupIDs {
|
||||
if assignedGroupID == groupID {
|
||||
changed = true
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, assignedGroupID)
|
||||
}
|
||||
if !changed {
|
||||
continue
|
||||
}
|
||||
user.GroupIDs = filtered
|
||||
if err := s.userRepo.UpdateUser(ctx, user); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.groupRepo.DeleteGroup(ctx, groupID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.refreshAllUserPermissions(ctx)
|
||||
}
|
||||
|
||||
// DeleteProvider deletes an auth provider and all user-provider links connected to it.
|
||||
func (s *AdminService) DeleteProvider(ctx context.Context, providerID bson.ObjectID) error {
|
||||
if s.providerRepo == nil {
|
||||
return errors.New("provider repository unavailable")
|
||||
}
|
||||
|
||||
if s.linkRepo != nil {
|
||||
users, err := s.userRepo.ListAllUsers(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, user := range users {
|
||||
links, err := s.linkRepo.GetUserLinks(ctx, user.ID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, link := range links {
|
||||
if link.ProviderID == providerID {
|
||||
if err := s.linkRepo.DeleteLink(ctx, link.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s.providerRepo.DeleteProvider(ctx, providerID)
|
||||
}
|
||||
|
||||
// ListUsers returns all users as admin DTOs
|
||||
func (s *AdminService) ListUsers(ctx context.Context) ([]*dto.AdminUserDTO, error) {
|
||||
users, err := s.userRepo.ListAllUsers(ctx)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/noteapp/backend/internal/interfaces/middleware"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
|
||||
"github.com/noteapp/backend/internal/application/dto"
|
||||
@@ -32,6 +33,33 @@ func (h *AdminHandler) ListUsers(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{"users": users})
|
||||
}
|
||||
|
||||
// DeleteUser handles DELETE /admin/users/{userId}
|
||||
func (h *AdminHandler) DeleteUser(w http.ResponseWriter, r *http.Request) {
|
||||
targetUserID, err := bson.ObjectIDFromHex(mux.Vars(r)["userId"])
|
||||
if err != nil {
|
||||
http.Error(w, "invalid user id", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
currentUserIDHex, err := middleware.GetUserIDFromContext(r.Context())
|
||||
if err != nil {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
currentUserID, err := bson.ObjectIDFromHex(currentUserIDHex)
|
||||
if err != nil {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.adminService.DeleteUser(r.Context(), currentUserID, targetUserID); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// UpdateUserGroups handles PUT /admin/users/{userId}/groups
|
||||
func (h *AdminHandler) UpdateUserGroups(w http.ResponseWriter, r *http.Request) {
|
||||
userID, err := bson.ObjectIDFromHex(mux.Vars(r)["userId"])
|
||||
@@ -66,6 +94,22 @@ func (h *AdminHandler) UpdateUserGroups(w http.ResponseWriter, r *http.Request)
|
||||
json.NewEncoder(w).Encode(user)
|
||||
}
|
||||
|
||||
// DeleteGroup handles DELETE /admin/groups/{groupId}
|
||||
func (h *AdminHandler) DeleteGroup(w http.ResponseWriter, r *http.Request) {
|
||||
groupID, err := bson.ObjectIDFromHex(mux.Vars(r)["groupId"])
|
||||
if err != nil {
|
||||
http.Error(w, "invalid group id", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.adminService.DeleteGroup(r.Context(), groupID); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// ListGroups handles GET /admin/groups
|
||||
func (h *AdminHandler) ListGroups(w http.ResponseWriter, r *http.Request) {
|
||||
groups, err := h.adminService.ListGroups(r.Context())
|
||||
@@ -292,3 +336,19 @@ func (h *AdminHandler) UpdateFeatureFlags(w http.ResponseWriter, r *http.Request
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(flags)
|
||||
}
|
||||
|
||||
// DeleteProvider handles DELETE /admin/auth/providers/{providerId}
|
||||
func (h *AdminHandler) DeleteProvider(w http.ResponseWriter, r *http.Request) {
|
||||
providerID, err := bson.ObjectIDFromHex(mux.Vars(r)["providerId"])
|
||||
if err != nil {
|
||||
http.Error(w, "invalid provider id", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.adminService.DeleteProvider(r.Context(), providerID); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user