fix: username sanitization, canvas creation modal fixes, and auth headers for tasks
This commit is contained in:
@@ -159,7 +159,7 @@ const fetchGroup = async () => {
|
|||||||
headers: { Authorization: `Bearer ${auth.token.value}` }
|
headers: { Authorization: `Bearer ${auth.token.value}` }
|
||||||
})
|
})
|
||||||
group.value = data.group
|
group.value = data.group
|
||||||
members.value = data.members || []
|
members.value = data.group.members || []
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to fetch group', e)
|
console.error('Failed to fetch group', e)
|
||||||
navigateTo('/admin/groups')
|
navigateTo('/admin/groups')
|
||||||
|
|||||||
+13
-5
@@ -9,13 +9,13 @@
|
|||||||
|
|
||||||
<div class="flex items-center justify-between mb-8">
|
<div class="flex items-center justify-between mb-8">
|
||||||
<h1 class="text-2xl font-bold text-slate-100">Мои Карты</h1>
|
<h1 class="text-2xl font-bold text-slate-100">Мои Карты</h1>
|
||||||
<div class="flex gap-2">
|
<div class="flex items-center gap-3">
|
||||||
<button @click="triggerImport" class="px-4 py-2 bg-slate-700 hover:bg-slate-600 text-white rounded-lg font-medium transition">
|
<button @click="triggerImport" class="px-4 py-2 bg-slate-700 hover:bg-slate-600 text-white rounded-lg font-medium transition">
|
||||||
Импорт .canvas
|
Импорт .canvas
|
||||||
</button>
|
</button>
|
||||||
<input ref="importInput" type="file" accept=".canvas,.json" class="hidden" @change="handleImport" />
|
<input ref="importInput" type="file" accept=".canvas,.json" class="hidden" @change="handleImport" />
|
||||||
<button @click="showCreateModal = true" class="px-4 py-2 bg-blue-600 hover:bg-blue-500 text-white rounded-lg font-medium transition">
|
<button @click="openCreateModal" class="px-4 py-2 bg-blue-600 hover:bg-blue-500 text-white rounded-lg font-bold shadow-lg shadow-blue-900/20 transition flex items-center gap-2">
|
||||||
+ Новая Карта
|
<span>➕</span> Создать
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -229,6 +229,14 @@ const activeTab = ref('personal')
|
|||||||
groupId: ''
|
groupId: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const openCreateModal = () => {
|
||||||
|
newCanvas.name = ''
|
||||||
|
newCanvas.visibility = 'private'
|
||||||
|
newCanvas.groupId = ''
|
||||||
|
showSettingsModal.value = false
|
||||||
|
showCreateModal.value = true
|
||||||
|
}
|
||||||
|
|
||||||
const showSettingsModal = ref(false)
|
const showSettingsModal = ref(false)
|
||||||
const saving = ref(false)
|
const saving = ref(false)
|
||||||
const editCanvas = reactive({
|
const editCanvas = reactive({
|
||||||
@@ -293,9 +301,9 @@ const filteredCanvases = computed(() => {
|
|||||||
|
|
||||||
switch (activeTab.value) {
|
switch (activeTab.value) {
|
||||||
case 'personal':
|
case 'personal':
|
||||||
return canvases.value.filter(c => c.ownerId === userId && !c.groupId)
|
return canvases.value.filter(c => c.ownerId === userId && (!c.groupId || c.groupId === ''))
|
||||||
case 'team':
|
case 'team':
|
||||||
return canvases.value.filter(c => !!c.groupId)
|
return canvases.value.filter(c => c.groupId && c.groupId !== '')
|
||||||
case 'public':
|
case 'public':
|
||||||
return canvases.value.filter(c => c.isPublic)
|
return canvases.value.filter(c => c.isPublic)
|
||||||
default:
|
default:
|
||||||
|
|||||||
+5
-6
@@ -163,11 +163,9 @@ const columns = [
|
|||||||
// Fetch all tasks for current user
|
// Fetch all tasks for current user
|
||||||
const fetchTasks = async () => {
|
const fetchTasks = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/tasks', {
|
const data = await $fetch('/api/tasks', {
|
||||||
headers: { Authorization: `Bearer ${auth.token.value}` }
|
headers: { Authorization: `Bearer ${auth.token.value}` }
|
||||||
})
|
})
|
||||||
if (res.ok) {
|
|
||||||
const data = await res.json()
|
|
||||||
tasks.value = data.tasks || []
|
tasks.value = data.tasks || []
|
||||||
|
|
||||||
// Split tasks into columns
|
// Split tasks into columns
|
||||||
@@ -177,7 +175,6 @@ const fetchTasks = async () => {
|
|||||||
return taskState === col.id
|
return taskState === col.id
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to load tasks', e)
|
console.error('Failed to load tasks', e)
|
||||||
} finally {
|
} finally {
|
||||||
@@ -187,8 +184,10 @@ const fetchTasks = async () => {
|
|||||||
|
|
||||||
const fetchCanvases = async () => {
|
const fetchCanvases = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await $fetch('/api/canvas')
|
const data = await $fetch('/api/canvas', {
|
||||||
availableCanvases.value = res.canvases || []
|
headers: { Authorization: `Bearer ${auth.token.value}` }
|
||||||
|
})
|
||||||
|
availableCanvases.value = data.canvases || []
|
||||||
if (availableCanvases.value.length > 0) {
|
if (availableCanvases.value.length > 0) {
|
||||||
newTask.canvasId = availableCanvases.value[0].id
|
newTask.canvasId = availableCanvases.value[0].id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ export default defineEventHandler(async (event) => {
|
|||||||
|
|
||||||
const fbUser: FirebaseUser = verifyRes.users[0]
|
const fbUser: FirebaseUser = verifyRes.users[0]
|
||||||
const email = fbUser.email
|
const email = fbUser.email
|
||||||
const username = email.split('@')[0]
|
// Очищаем username: заменяем пробелы на дефисы и убираем спецсимволы
|
||||||
|
const username = email.split('@')[0].toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-_]/g, '')
|
||||||
const userId = fbUser.localId
|
const userId = fbUser.localId
|
||||||
|
|
||||||
const user = await prisma.user.upsert({
|
const user = await prisma.user.upsert({
|
||||||
|
|||||||
@@ -5,28 +5,28 @@ export default defineEventHandler(async (event) => {
|
|||||||
const adminUser = requireAuth(event)
|
const adminUser = requireAuth(event)
|
||||||
const groupId = getRouterParam(event, 'id')
|
const groupId = getRouterParam(event, 'id')
|
||||||
const body = await readBody(event)
|
const body = await readBody(event)
|
||||||
const { email, role = 'member' } = body
|
const { email, userId, role = 'member' } = body
|
||||||
|
|
||||||
if (!groupId || !email) {
|
if (!groupId || (!email && !userId)) {
|
||||||
throw createError({ statusCode: 400, message: 'Group ID and Email are required' })
|
throw createError({ statusCode: 400, message: 'Group ID and either Email or User ID are required' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Проверяем, является ли текущий пользователь админом группы или глобальным админом
|
// 1. Проверяем права
|
||||||
const group = await prisma.group.findUnique({
|
const group = await prisma.group.findUnique({ where: { id: groupId } })
|
||||||
where: { id: groupId }
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!group || (group.ownerId !== adminUser.id && adminUser.role !== 'admin')) {
|
if (!group || (group.ownerId !== adminUser.id && adminUser.role !== 'admin')) {
|
||||||
throw createError({ statusCode: 403, message: 'Only group owners or admins can add members' })
|
throw createError({ statusCode: 403, message: 'Only group owners or admins can add members' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Ищем пользователя по email
|
// 2. Находим пользователя
|
||||||
const userToAdd = await prisma.user.findUnique({
|
let userToAdd = null
|
||||||
where: { email }
|
if (userId) {
|
||||||
})
|
userToAdd = await prisma.user.findUnique({ where: { id: userId } })
|
||||||
|
} else if (email) {
|
||||||
|
userToAdd = await prisma.user.findUnique({ where: { email } })
|
||||||
|
}
|
||||||
|
|
||||||
if (!userToAdd) {
|
if (!userToAdd) {
|
||||||
throw createError({ statusCode: 404, message: 'User with this email not found in system' })
|
throw createError({ statusCode: 404, message: 'User not found' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Добавляем в группу
|
// 3. Добавляем в группу
|
||||||
|
|||||||
Reference in New Issue
Block a user