diff --git a/app/pages/galleries/index.vue b/app/pages/galleries/index.vue new file mode 100644 index 0000000..31a62bb --- /dev/null +++ b/app/pages/galleries/index.vue @@ -0,0 +1,21 @@ + + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b5797b7..44eb727 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,8 @@ "devDependencies": { "@types/minio": "^7.1.1", "nuxt": "^3.13.1", - "nuxt-file-storage": "^0.2.6" + "nuxt-file-storage": "^0.2.6", + "prisma": "^5.20.0" } }, "node_modules/@alloc/quick-lru": { @@ -2268,6 +2269,56 @@ } } }, + "node_modules/@prisma/debug": { + "version": "5.20.0", + "resolved": "http://npm.117112.xyz/@prisma/debug/-/debug-5.20.0.tgz", + "integrity": "sha512-oCx79MJ4HSujokA8S1g0xgZUGybD4SyIOydoHMngFYiwEwYDQ5tBQkK5XoEHuwOYDKUOKRn/J0MEymckc4IgsQ==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines": { + "version": "5.20.0", + "resolved": "http://npm.117112.xyz/@prisma/engines/-/engines-5.20.0.tgz", + "integrity": "sha512-DtqkP+hcZvPEbj8t8dK5df2b7d3B8GNauKqaddRRqQBBlgkbdhJkxhoJTrOowlS3vaRt2iMCkU0+CSNn0KhqAQ==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.20.0", + "@prisma/engines-version": "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284", + "@prisma/fetch-engine": "5.20.0", + "@prisma/get-platform": "5.20.0" + } + }, + "node_modules/@prisma/engines-version": { + "version": "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284", + "resolved": "http://npm.117112.xyz/@prisma/engines-version/-/engines-version-5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284.tgz", + "integrity": "sha512-Lg8AS5lpi0auZe2Mn4gjuCg081UZf88k3cn0RCwHgR+6cyHHpttPZBElJTHf83ZGsRNAmVCZCfUGA57WB4u4JA==", + "devOptional": true, + "license": "Apache-2.0" + }, + "node_modules/@prisma/fetch-engine": { + "version": "5.20.0", + "resolved": "http://npm.117112.xyz/@prisma/fetch-engine/-/fetch-engine-5.20.0.tgz", + "integrity": "sha512-JVcaPXC940wOGpCOwuqQRTz6I9SaBK0c1BAyC1pcz9xBi+dzFgUu3G/p9GV1FhFs9OKpfSpIhQfUJE9y00zhqw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.20.0", + "@prisma/engines-version": "5.20.0-12.06fc58a368dc7be9fbbbe894adf8d445d208c284", + "@prisma/get-platform": "5.20.0" + } + }, + "node_modules/@prisma/get-platform": { + "version": "5.20.0", + "resolved": "http://npm.117112.xyz/@prisma/get-platform/-/get-platform-5.20.0.tgz", + "integrity": "sha512-8/+CehTZZNzJlvuryRgc77hZCWrUDYd/PmlZ7p2yNXtmf2Una4BWnTbak3us6WVdqoz5wmptk6IhsXdG2v5fmA==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "5.20.0" + } + }, "node_modules/@remirror/core-constants": { "version": "2.0.2", "resolved": "http://npm.117112.xyz/@remirror/core-constants/-/core-constants-2.0.2.tgz", @@ -12089,6 +12140,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/prisma": { + "version": "5.20.0", + "resolved": "http://npm.117112.xyz/prisma/-/prisma-5.20.0.tgz", + "integrity": "sha512-6obb3ucKgAnsGS9x9gLOe8qa51XxvJ3vLQtmyf52CTey1Qcez3A6W6ROH5HIz5Q5bW+0VpmZb8WBohieMFGpig==", + "devOptional": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/engines": "5.20.0" + }, + "bin": { + "prisma": "build/index.js" + }, + "engines": { + "node": ">=16.13" + }, + "optionalDependencies": { + "fsevents": "2.3.3" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "http://npm.117112.xyz/process/-/process-0.11.10.tgz", diff --git a/package.json b/package.json index fcb359a..51caad9 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "devDependencies": { "@types/minio": "^7.1.1", "nuxt": "^3.13.1", - "nuxt-file-storage": "^0.2.6" + "nuxt-file-storage": "^0.2.6", + "prisma": "^5.20.0" } } diff --git a/server/api/v1/categories.get.ts b/server/api/v1/categories.get.ts new file mode 100644 index 0000000..10d7cf2 --- /dev/null +++ b/server/api/v1/categories.get.ts @@ -0,0 +1,45 @@ +import { PrismaClient } from '@prisma/client' +const prisma = new PrismaClient() +export default defineEventHandler(async (event) => { + const query = getQuery(event) + try { + let pageIndex: number = 0 + let pageAmount: number = 90 + if (query.pagination != null && query.paginatePerPage != null) { + pageIndex = parseInt(query.pagination as any) + pageAmount = parseInt(query.paginatePerPage as any) + } + let data = null + if (query.ids != null) { + const queryIds = Array.isArray(query.ids) + ? query.ids.map(Number) + : [Number(query.ids)]; + data = await prisma.category.findMany({ + where: { + id: { + in: Array.from(queryIds as any[] as number[], Number) + } + } + }) + } else { + data = await prisma.category.findMany({ + select: { + id: true, + name: true, + galleries: true, + } + }) + } + + return data + } catch (error: any) { + if (error) { + console.log(`${event.toString()} -> Error at ${error.message}`) + + return sendError(event, createError({ + status: error.code as any as number, + message: error.message, + })) + } + } +}) \ No newline at end of file diff --git a/server/api/v1/category/delete.post.ts b/server/api/v1/category/delete.post.ts new file mode 100644 index 0000000..3bcb720 --- /dev/null +++ b/server/api/v1/category/delete.post.ts @@ -0,0 +1,35 @@ +//@ts-ignore +import { v4 as uuidv4 } from 'uuid'; +//@ts-ignore +import jwt from 'jsonwebtoken'; +import { setCookie } from 'h3'; +import { PrismaClient } from '@prisma/client' +import useAuth from "~/composables/useAuth"; +import useServerAuth from "~/composables/useServerAuth"; +const prisma = new PrismaClient() + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + + if(!body.id) + return sendError(event, createError({statusCode: 400, statusMessage: 'Not enough parameters.'})) + + const header = getHeader(event, 'Authorization') + const auth = useServerAuth(event, header as any as string) + + const isServerAuthenticated = await auth.validateServerToken() + if (!isServerAuthenticated) { + return sendError(event, createError({ statusCode: 403, statusMessage: 'Unauthorized; Please re-login.'})); + } + + let data = await prisma.gallery.delete({ + where: { + id: body.id as number, + } + }) + + if (!data) + return sendError(event, createError({statusCode: 401, statusMessage: 'Gallery not found' })); + + return data; +}); \ No newline at end of file diff --git a/server/api/v1/category/edit.post.ts b/server/api/v1/category/edit.post.ts new file mode 100644 index 0000000..61a1505 --- /dev/null +++ b/server/api/v1/category/edit.post.ts @@ -0,0 +1,43 @@ +//@ts-ignore +import { v4 as uuidv4 } from 'uuid'; +//@ts-ignore +import jwt from 'jsonwebtoken'; +import {Media, PrismaClient} from '@prisma/client' +import useServerAuth from "~/composables/useServerAuth"; +const prisma = new PrismaClient() + +export default defineEventHandler(async (event) => { + const body = await readBody<{ id: number, name: string, galleries: number[]}>(event); + const header = getHeader(event, 'Authorization') + + if (!body.id || !body.name || !body.galleries || !header) { + return sendError(event, createError({ statusCode: 400, statusMessage: 'Cannot access without authorization header.' })); + } + + const auth = useServerAuth(event, header) + + const isServerAuthenticated = await auth.validateServerToken() + if (!isServerAuthenticated) { + return sendError(event, createError({ statusCode: 403, statusMessage: 'Unauthorized; Please re-login.'})); + } + + let {error} = await prisma.category.update({ + where: { + id: body.id, + }, + data: { + updatedAt: new Date().toISOString(), + name: body.name, + galleries: { + connect: galleryIds.map(galleryId => ({ + id: galleryId, + })), + }, + } + }) + + if (error) + return sendError(event, createError({statusCode: 401, statusMessage: 'Gallery not found' })); + + return edit; +}); \ No newline at end of file diff --git a/server/api/v1/category/new.post.ts b/server/api/v1/category/new.post.ts new file mode 100644 index 0000000..3f5a99f --- /dev/null +++ b/server/api/v1/category/new.post.ts @@ -0,0 +1,31 @@ +import {PrismaClient} from '@prisma/client' +import useServerAuth from "~/composables/useServerAuth"; +const prisma = new PrismaClient() + +export default defineEventHandler(async (event) => { + const body = await readBody<{name: string}>(event); + const header = getHeader(event, 'Authorization') + console.log(header) + + if (!body.name || !header) { + return sendError(event, createError({ statusCode: 400, statusMessage: 'Requires full parameters or headers' })); + } + + const auth = useServerAuth(event, header) + + const isServerAuthenticated = await auth.validateServerToken() + if (!isServerAuthenticated) { + return sendError(event, createError({ statusCode: 403, statusMessage: 'Unauthorized; Please re-login.'})); + } + + let {data, error} = await prisma.category.create({ + data: { + name: body.name as string + } + }) + + if (error) + return sendError(event, createError({statusCode: 401, statusMessage: 'Unsuccessful creation. Try again later.' })); + + return data; +}); \ No newline at end of file diff --git a/server/api/v1/galleries.get.ts b/server/api/v1/galleries.get.ts index e8f6907..09889b5 100644 --- a/server/api/v1/galleries.get.ts +++ b/server/api/v1/galleries.get.ts @@ -4,7 +4,7 @@ export default defineEventHandler(async (event) => { const query = getQuery(event) try { let pageIndex: number = 0 - let pageAmount: number = 9 + let pageAmount: number = 90 if (query.pagination != null && query.paginatePerPage != null) { pageIndex = parseInt(query.pagination as any) pageAmount = parseInt(query.paginatePerPage as any) diff --git a/server/api/v1/gallery/delete.post.ts b/server/api/v1/gallery/delete.post.ts new file mode 100644 index 0000000..ffc07fe --- /dev/null +++ b/server/api/v1/gallery/delete.post.ts @@ -0,0 +1,35 @@ +//@ts-ignore +import { v4 as uuidv4 } from 'uuid'; +//@ts-ignore +import jwt from 'jsonwebtoken'; +import { setCookie } from 'h3'; +import { PrismaClient } from '@prisma/client' +import useAuth from "~/composables/useAuth"; +import useServerAuth from "~/composables/useServerAuth"; +const prisma = new PrismaClient() + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + + if(!body.id) + return sendError(event, createError({statusCode: 400, statusMessage: 'Not enough parameters.'})) + + const header = getHeader(event, 'Authorization') + const auth = useServerAuth(event, header as any as string) + + const isServerAuthenticated = await auth.validateServerToken() + if (!isServerAuthenticated) { + return sendError(event, createError({ statusCode: 403, statusMessage: 'Unauthorized; Please re-login.'})); + } + + let {data, error} = await prisma.gallery.delete({ + where: { + id: body.id as number, + } + }) + + if (error) + return sendError(event, createError({statusCode: 401, statusMessage: 'Gallery not found' })); + + return data; +}); \ No newline at end of file diff --git a/server/api/v1/gallery/edit.post.ts b/server/api/v1/gallery/edit.post.ts index c5c4a04..b467743 100644 --- a/server/api/v1/gallery/edit.post.ts +++ b/server/api/v1/gallery/edit.post.ts @@ -21,19 +21,24 @@ export default defineEventHandler(async (event) => { return sendError(event, createError({ statusCode: 403, statusMessage: 'Unauthorized; Please re-login.'})); } - let edit = await prisma.gallery.update({ + let {data: edit, error} = await prisma.gallery.update({ where: { id: body.id, }, data: { updatedAt: new Date().toISOString(), name: body.name, - published: body.published + published: body.published, + medias: { + connect: body.medias.map(mediaId => ({ + mediaId: mediaId, + })), + }, } }) - if (!edit) - return sendError(event, createError({statusCode: 401, statusMessage: 'Article not found' })); + if (error) + return sendError(event, createError({statusCode: 401, statusMessage: 'Gallery not found' })); return edit; }); \ No newline at end of file diff --git a/server/api/v1/gallery/get-slug.get.ts b/server/api/v1/gallery/get-slug.get.ts new file mode 100644 index 0000000..cd7705d --- /dev/null +++ b/server/api/v1/gallery/get-slug.get.ts @@ -0,0 +1,29 @@ +import { PrismaClient } from '@prisma/client' +const prisma = new PrismaClient() +export default defineEventHandler(async (event) => { + const query = getQuery(event) + + try { + let data = null + if (query.slug != null) { + data = await prisma.gallery.findFirst({ + where: { + id: query.id as any as number + } + }) + } else { + return null + } + + return data + } catch (error: any) { + if (error) { + console.log(`${event.toString()} -> Error at ${error.message}`) + + return sendError(event, createError({ + status: error.code as any as number, + message: error.message, + })) + } + } +}) \ No newline at end of file diff --git a/server/api/v1/gallery/new.post.ts b/server/api/v1/gallery/new.post.ts index df53163..cb8b988 100644 --- a/server/api/v1/gallery/new.post.ts +++ b/server/api/v1/gallery/new.post.ts @@ -15,18 +15,17 @@ export default defineEventHandler(async (event) => { const isServerAuthenticated = await auth.validateServerToken() if (!isServerAuthenticated) { - return sendError(event, createError({ statusCode: 403, statusMessage: 'Unauthorized; Please re-login.'})); } - let data = await prisma.gallery.create({ + let {data, error} = await prisma.gallery.create({ data: { name: body.name as string, published: false } }) - if (!data) + if (error) return sendError(event, createError({statusCode: 401, statusMessage: 'Unsuccessful creation. Try again later.' })); return data; diff --git a/server/api/v1/gallery/publish.post.ts b/server/api/v1/gallery/publish.post.ts new file mode 100644 index 0000000..4ba68c8 --- /dev/null +++ b/server/api/v1/gallery/publish.post.ts @@ -0,0 +1,39 @@ +//@ts-ignore +import { v4 as uuidv4 } from 'uuid'; +//@ts-ignore +import jwt from 'jsonwebtoken'; +import { setCookie } from 'h3'; +import { PrismaClient } from '@prisma/client' +import useAuth from "~/composables/useAuth"; +import useServerAuth from "~/composables/useServerAuth"; +const prisma = new PrismaClient() + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + + if (!body.id) { + return sendError(event, createError({ statusCode: 400, statusMessage: 'Requires full parameters' })); + } + + const header = getHeader(event, 'Authorization') + const auth = useServerAuth(event, header as any as string) + + const isServerAuthenticated = await auth.validateServerToken() + if (!isServerAuthenticated) { + return sendError(event, createError({ statusCode: 403, statusMessage: 'Unauthorized; Please re-login.'})); + } + + let {data, error} = await prisma.gallery.update({ + where: { + id: body.id as number, + }, + data: { + published: true + } + }) + + if (error) + return sendError(event, createError({statusCode: 401, statusMessage: 'An error occurred while publishing this gallery. Try again later.' })); + + return data; +}); \ No newline at end of file diff --git a/server/api/v1/gallery/unpublish.post.ts b/server/api/v1/gallery/unpublish.post.ts new file mode 100644 index 0000000..ba18527 --- /dev/null +++ b/server/api/v1/gallery/unpublish.post.ts @@ -0,0 +1,39 @@ +//@ts-ignore +import { v4 as uuidv4 } from 'uuid'; +//@ts-ignore +import jwt from 'jsonwebtoken'; +import { setCookie } from 'h3'; +import { PrismaClient } from '@prisma/client' +import useAuth from "~/composables/useAuth"; +import useServerAuth from "~/composables/useServerAuth"; +const prisma = new PrismaClient() + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + + if (!body.id) { + return sendError(event, createError({ statusCode: 400, statusMessage: 'Requires full parameters' })); + } + + const header = getHeader(event, 'Authorization') + const auth = useServerAuth(event, header as any as string) + + const isServerAuthenticated = await auth.validateServerToken() + if (!isServerAuthenticated) { + return sendError(event, createError({ statusCode: 403, statusMessage: 'Unauthorized; Please re-login.'})); + } + + let {data, error} = await prisma.gallery.update({ + where: { + id: body.id as number, + }, + data: { + published: false + } + }) + + if (error) + return sendError(event, createError({statusCode: 401, statusMessage: 'An error occurred while unpublishing this gallery. Try again later.' })); + + return data; +}); \ No newline at end of file