diff --git a/app/pages/admin/groups/[id].vue b/app/pages/admin/groups/[id].vue
index 43a9cfe..eaa30cc 100644
--- a/app/pages/admin/groups/[id].vue
+++ b/app/pages/admin/groups/[id].vue
@@ -16,7 +16,7 @@
-
@@ -139,6 +175,19 @@ const addMember = async (userId) => {
}
}
+const updateMemberRole = async (userId, role) => {
+ try {
+ await $fetch(`/api/groups/${route.params.id}/members`, {
+ method: 'PATCH',
+ body: { userId, role },
+ headers: { Authorization: `Bearer ${auth.token.value}` }
+ })
+ await fetchGroup()
+ } catch (e) {
+ alert('Ошибка при смене роли')
+ }
+}
+
const removeMember = async (userId) => {
if (!confirm('Удалить участника из группы?')) return
try {
@@ -153,6 +202,20 @@ const removeMember = async (userId) => {
}
}
+const unassignCanvas = async (canvasId) => {
+ if (!confirm('Отвязать карту от группы? Она станет личной картой владельца.')) return
+ try {
+ await $fetch(`/api/canvases/${canvasId}`, {
+ method: 'PATCH',
+ body: { groupId: null },
+ headers: { Authorization: `Bearer ${auth.token.value}` }
+ })
+ await fetchGroup()
+ } catch (e) {
+ alert('Ошибка при отвязке карты')
+ }
+}
+
const fetchGroup = async () => {
try {
const data = await $fetch(`/api/groups/${route.params.id}`, {
diff --git a/app/server/api/groups/[id]/index.get.ts b/app/server/api/groups/[id]/index.get.ts
index 0380aa9..bedd040 100644
--- a/app/server/api/groups/[id]/index.get.ts
+++ b/app/server/api/groups/[id]/index.get.ts
@@ -11,13 +11,12 @@ export default defineEventHandler(async (event) => {
members: {
include: {
user: {
- select: {
- id: true,
- username: true,
- email: true
- }
+ select: { id: true, username: true, email: true }
}
}
+ },
+ canvases: {
+ select: { id: true, name: true, updatedAt: true }
}
}
})
diff --git a/app/server/api/groups/[id]/members.patch.ts b/app/server/api/groups/[id]/members.patch.ts
new file mode 100644
index 0000000..5df1f54
--- /dev/null
+++ b/app/server/api/groups/[id]/members.patch.ts
@@ -0,0 +1,41 @@
+import { requireAuth } from '~/server/utils/auth'
+import { prisma } from '~/server/utils/prisma'
+
+export default defineEventHandler(async (event) => {
+ const adminUser = requireAuth(event)
+ const groupId = getRouterParam(event, 'id')
+ const body = await readBody(event)
+ const { userId, role } = body
+
+ if (!groupId || !userId || !role) {
+ throw createError({ statusCode: 400, message: 'Missing required fields' })
+ }
+
+ // 1. Проверяем права: только владелец группы или глобальный админ может менять роли
+ const group = await prisma.group.findUnique({
+ where: { id: groupId }
+ })
+
+ if (!group || (group.ownerId !== adminUser.id && adminUser.role !== 'admin')) {
+ throw createError({ statusCode: 403, message: 'Permission denied' })
+ }
+
+ // 2. Нельзя менять роль самому владельцу (он всегда админ)
+ if (userId === group.ownerId) {
+ throw createError({ statusCode: 400, message: 'Cannot change owner role' })
+ }
+
+ // 3. Обновляем роль
+ try {
+ const updated = await prisma.groupMember.update({
+ where: {
+ userId_groupId: { userId, groupId }
+ },
+ data: { role }
+ })
+
+ return { success: true, updated }
+ } catch (e) {
+ throw createError({ statusCode: 500, message: 'Failed to update member role' })
+ }
+})