From 18589b7de71f6aa371eccbd755502389009529b7 Mon Sep 17 00:00:00 2001 From: amal Date: Fri, 19 Sep 2025 10:56:02 +0800 Subject: [PATCH 1/6] upd: api ai document divisi Deskripsi: - list dokumen dan file divisi NO Issues --- src/app/api/ai/document/route.ts | 146 +++++++++++++++---------------- 1 file changed, 72 insertions(+), 74 deletions(-) diff --git a/src/app/api/ai/document/route.ts b/src/app/api/ai/document/route.ts index 57b619b..2c52ec7 100644 --- a/src/app/api/ai/document/route.ts +++ b/src/app/api/ai/document/route.ts @@ -1,6 +1,4 @@ import { prisma } from "@/module/_global"; -import { funGetUserByCookies } from "@/module/auth"; -import { createLogUser } from "@/module/user"; import _ from "lodash"; import moment from "moment"; import { NextResponse } from "next/server"; @@ -13,88 +11,95 @@ export async function GET(request: Request) { const idDivision = searchParams.get("division"); const villageId = searchParams.get("desa"); const path = searchParams.get("path"); - const category = searchParams.get("category"); const active = searchParams.get("active"); const search = searchParams.get("search"); const page = searchParams.get("page"); const get = searchParams.get("get"); + let getFix = 10; + if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) { + getFix = 10; + } else { + getFix = Number(get); + } + + const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix; let kondisi: any = { - isActive: true, - idDivision: String(idDivision), - path: (path == "undefined" || path == "null" || path == "" || path == null) ? "home" : path + Division: { + idVillage: String(villageId) + }, + isActive: active == 'false' ? false : true, + path: (path == "undefined" || path == "null" || path == "" || path == null || path == undefined) ? "home" : path, + name: { + contains: (search == undefined || search == "null") ? "" : search, + mode: "insensitive" + } + } + + if (idDivision != "null" && idDivision != undefined && idDivision != "") { + kondisi = { + ...kondisi, + idDivision: String(idDivision) + } } let formatDataShare: any[] = []; - if (category == "folder") { - kondisi = { - isActive: true, - idDivision: String(idDivision), - path: (path == "undefined" || path == "null" || path == "" || path == null) ? "home" : path, - category: "FOLDER" - } - } else { - if (path == "home" || path == "null" || path == "undefined") { - const dataShare = await prisma.divisionDocumentShare.findMany({ - where: { - isActive: true, - idDivision: String(idDivision), - DivisionDocumentFolderFile: { - isActive: true - } - }, - select: { - DivisionDocumentFolderFile: { - select: { - idStorage: true, - id: true, - category: true, - name: true, - extension: true, - path: true, - User: { - select: { - name: true - } - }, - createdAt: true, - updatedAt: true - } - } - }, - orderBy: { - DivisionDocumentFolderFile: { - createdAt: 'desc' + if (path == "home" || path == "null" || path == "undefined" || path == null || path == undefined || path == "") { + const dataShare = await prisma.divisionDocumentShare.findMany({ + where: { + isActive: true, + idDivision: String(idDivision), + DivisionDocumentFolderFile: { + isActive: true + } + }, + select: { + DivisionDocumentFolderFile: { + select: { + idStorage: true, + id: true, + category: true, + name: true, + extension: true, + path: true, + User: { + select: { + name: true + } + }, + createdAt: true, + updatedAt: true } } - }) - - formatDataShare = dataShare.map((v: any) => ({ - ..._.omit(v, ["DivisionDocumentFolderFile"]), - idStorage: v.DivisionDocumentFolderFile.idStorage, - id: v.DivisionDocumentFolderFile.id, - category: v.DivisionDocumentFolderFile.category, - name: v.DivisionDocumentFolderFile.name, - extension: v.DivisionDocumentFolderFile.extension, - path: v.DivisionDocumentFolderFile.path, - createdBy: v.DivisionDocumentFolderFile.User.name, - createdAt: v.DivisionDocumentFolderFile.createdAt, - updatedAt: v.DivisionDocumentFolderFile.updatedAt, - share: true - })) - - } else { - kondisi = { - isActive: true, - path: (path == "undefined" || path == "null" || path == null) ? "home" : path + }, + orderBy: { + DivisionDocumentFolderFile: { + createdAt: 'desc' + } } - } + }) + + formatDataShare = dataShare.map((v: any) => ({ + ..._.omit(v, ["DivisionDocumentFolderFile"]), + idStorage: v.DivisionDocumentFolderFile.idStorage, + id: v.DivisionDocumentFolderFile.id, + category: v.DivisionDocumentFolderFile.category, + name: v.DivisionDocumentFolderFile.name, + extension: v.DivisionDocumentFolderFile.extension, + path: v.DivisionDocumentFolderFile.path, + createdBy: v.DivisionDocumentFolderFile.User.name, + createdAt: v.DivisionDocumentFolderFile.createdAt, + updatedAt: v.DivisionDocumentFolderFile.updatedAt, + share: true + })) } const data = await prisma.divisionDocumentFolderFile.findMany({ + skip: dataSkip, + take: getFix, where: kondisi, select: { id: true, @@ -130,15 +135,8 @@ export async function GET(request: Request) { const formatData = _.orderBy(allData, ['category', 'createdAt'], ['desc', 'desc']); - const fixData = formatData.map((v: any) => ({ - ..._.omit(v, ["createdAt", "updatedAt"]), - createdAt: moment(v.createdAt).format("DD-MM-YYYY HH:mm"), - updatedAt: moment(v.updatedAt).format("DD-MM-YYYY HH:mm"), - })) - - - return NextResponse.json({ success: true, message: "Berhasil mendapatkan item", data: fixData }, { status: 200 }); + return NextResponse.json({ success: true, message: "Berhasil mendapatkan item", data: formatData }, { status: 200 }); } catch (error) { console.error(error); From 51b39396ec4fea40076e04ce13dd45bef29c2f26 Mon Sep 17 00:00:00 2001 From: amal Date: Fri, 19 Sep 2025 11:08:19 +0800 Subject: [PATCH 2/6] upd: api ai group Deskripsi: - list group NO Issues --- src/app/api/ai/group/route.ts | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/app/api/ai/group/route.ts diff --git a/src/app/api/ai/group/route.ts b/src/app/api/ai/group/route.ts new file mode 100644 index 0000000..3b85c37 --- /dev/null +++ b/src/app/api/ai/group/route.ts @@ -0,0 +1,45 @@ +import { prisma } from "@/module/_global"; +import _ from "lodash"; +import { NextResponse } from "next/server"; + +export async function GET(request: Request) { + try { + const { searchParams } = new URL(request.url); + const villageId = searchParams.get("desa"); + const isActive = searchParams.get("active"); + const search = searchParams.get('search'); + const page = searchParams.get('page') + const get = searchParams.get('get') + + let getFix = 10; + if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) { + getFix = 10; + } else { + getFix = Number(get); + } + + const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix; + + const data = await prisma.group.findMany({ + skip: dataSkip, + take: getFix, + where: { + isActive: isActive == 'false' ? false : true, + idVillage: String(villageId), + name: { + contains: (search == undefined || search == null) ? "" : search, + mode: "insensitive" + } + }, + orderBy: { + name: 'asc' + } + }); + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan grup", data, }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mendapatkan grup, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} \ No newline at end of file From fbfdc21b9dfa1646ef2e239885746ba12613a810 Mon Sep 17 00:00:00 2001 From: amal Date: Fri, 19 Sep 2025 11:42:45 +0800 Subject: [PATCH 3/6] upd: api ai positision Deskripsi: - list position No Issues --- src/app/api/ai/position/route.ts | 79 ++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 src/app/api/ai/position/route.ts diff --git a/src/app/api/ai/position/route.ts b/src/app/api/ai/position/route.ts new file mode 100644 index 0000000..3aaca1f --- /dev/null +++ b/src/app/api/ai/position/route.ts @@ -0,0 +1,79 @@ +import { prisma } from "@/module/_global"; +import _ from "lodash"; +import { NextResponse } from "next/server"; + + +// GET ALL POSITION +export async function GET(request: Request) { + try { + const { searchParams } = new URL(request.url); + const idVillage = searchParams.get("desa"); + const idGroup = searchParams.get("group"); + const active = searchParams.get('active'); + const search = searchParams.get('search') + const page = searchParams.get('page') + const get = searchParams.get('get') + + let getFix = 10; + if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) { + getFix = 10; + } else { + getFix = Number(get); + } + + const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix; + + let kondisi: any = { + isActive: active == 'false' ? false : true, + Group: { + idVillage: String(idVillage) + }, + name: { + contains: (search == undefined || search == null) ? "" : search, + mode: "insensitive" + } + } + + if (idGroup != "null" && idGroup != undefined && idGroup != "") { + kondisi = { + ...kondisi, + idGroup: String(idGroup) + } + } + + + + const positions = await prisma.position.findMany({ + skip: dataSkip, + take: getFix, + where: kondisi, + select: { + id: true, + name: true, + idGroup: true, + isActive: true, + createdAt: true, + updatedAt: true, + Group: { + select: { + name: true + } + } + }, + orderBy: { + name: 'asc' + } + }); + + const allData = positions.map((v: any) => ({ + ..._.omit(v, ["Group"]), + group: v.Group.name + })) + + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan jabatan", data: allData }, { status: 200 }); + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mendapatkan jabatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} \ No newline at end of file From c51692079efcd6d668bf907966d8d4668b076df7 Mon Sep 17 00:00:00 2001 From: amal Date: Fri, 19 Sep 2025 12:33:31 +0800 Subject: [PATCH 4/6] upd: api ai project Deskripsi: - list project - detail project No Issues' --- src/app/api/ai/project/[id]/route.ts | 172 +++++++++++++++++++++++++++ src/app/api/ai/project/route.ts | 107 +++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 src/app/api/ai/project/[id]/route.ts create mode 100644 src/app/api/ai/project/route.ts diff --git a/src/app/api/ai/project/[id]/route.ts b/src/app/api/ai/project/[id]/route.ts new file mode 100644 index 0000000..83853a9 --- /dev/null +++ b/src/app/api/ai/project/[id]/route.ts @@ -0,0 +1,172 @@ +import { prisma } from "@/module/_global"; +import _ from "lodash"; +import moment from "moment"; +import { NextResponse } from "next/server"; + + +// GET DETAIL PROJECT / GET ONE PROJECT +export async function GET(request: Request, context: { params: { id: string } }) { + try { + let allData + const { id } = context.params; + const { searchParams } = new URL(request.url); + const kategori = searchParams.get("cat"); + + const data = await prisma.project.findUnique({ + where: { + id: String(id), + }, + select: { + id: true, + idVillage: true, + idGroup: true, + title: true, + status: true, + desc: true, + reason: true, + report: true, + isActive: true, + Group: { + select: { + name: true + } + } + } + }); + + if (!data) { + return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", }, { status: 404 }); + } + + + if (kategori == "data") { + const dataProgress = await prisma.projectTask.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + orderBy: { + updatedAt: 'desc' + } + }) + + const semua = dataProgress.length + const selesai = _.filter(dataProgress, { status: 1 }).length + const progress = Math.ceil((selesai / semua) * 100) + + allData = { + id: data.id, + idVillage: data.idVillage, + idGroup: data.idGroup, + group: data.Group.name, + title: data.title, + status: data.status == 3 ? "batal" : data.status == 2 ? "selesai" : data.status == 1 ? "dikerjakan" : "segera", + desc: data.desc, + reason: data.reason, + report: data.report, + isActive: data.isActive, + progress: (_.isNaN(progress)) ? 0 : progress, + } + + } else if (kategori == "task") { + const dataProgress = await prisma.projectTask.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + select: { + id: true, + title: true, + desc: true, + status: true, + dateStart: true, + dateEnd: true, + createdAt: true + }, + orderBy: { + createdAt: 'asc' + } + }) + + const formatData = dataProgress.map((v: any) => ({ + ..._.omit(v, ["dateStart", "dateEnd", "createdAt", "status"]), + status: v.status == 1 ? "selesai" : "belum selesai", + dateStart: moment(v.dateStart).format("DD-MM-YYYY"), + dateEnd: moment(v.dateEnd).format("DD-MM-YYYY"), + createdAt: moment(v.createdAt).format("DD-MM-YYYY HH:mm"), + })) + const dataFix = _.orderBy(formatData, 'createdAt', 'asc') + allData = dataFix + + } else if (kategori == "file") { + const dataFile = await prisma.projectFile.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + orderBy: { + createdAt: 'asc' + }, + select: { + id: true, + name: true, + extension: true, + idStorage: true + } + }) + + allData = dataFile + + } else if (kategori == "member") { + const dataMember = await prisma.projectMember.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + select: { + id: true, + idUser: true, + User: { + select: { + name: true, + email: true, + img: true, + Position: { + select: { + name: true + } + } + } + }, + } + }) + + const fix = dataMember.map((v: any) => ({ + ..._.omit(v, ["User"]), + name: v.User.name, + email: v.User.email, + img: v.User.img, + position: v.User.Position.name + })) + + allData = fix + } else if (kategori == "link") { + const dataLink = await prisma.projectLink.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + orderBy: { + createdAt: 'asc' + } + }) + allData = dataLink + } + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan kegiatan", data: allData }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/ai/project/route.ts b/src/app/api/ai/project/route.ts new file mode 100644 index 0000000..7db00f3 --- /dev/null +++ b/src/app/api/ai/project/route.ts @@ -0,0 +1,107 @@ +import { prisma } from "@/module/_global"; +import _, { ceil } from "lodash"; +import { NextResponse } from "next/server"; + + +// GET ALL DATA PROJECT +export async function GET(request: Request) { + try { + const { searchParams } = new URL(request.url); + const idVillage = searchParams.get('desa'); + const name = searchParams.get('search'); + const status = searchParams.get('status'); + const idGroup = searchParams.get("group"); + const page = searchParams.get('page'); + const get = searchParams.get('get'); + + let getFix = 10; + if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) { + getFix = 10; + } else { + getFix = Number(get); + } + + const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix; + + + + + let kondisi: any = { + isActive: true, + idVillage: String(idVillage), + title: { + contains: (name == undefined || name == "null") ? "" : name, + mode: "insensitive" + }, + } + + if (status != "null" && status != undefined && status != "") { + kondisi = { + ...kondisi, + status: status == "segera" ? 0 : status == "dikerjakan" ? 1 : status == "selesai" ? 2 : status == "batal" ? 3 : 0 + } + } + + + if (idGroup != "null" && idGroup != undefined && idGroup != "") { + kondisi = { + ...kondisi, + idGroup: String(idGroup) + } + } + + + const data = await prisma.project.findMany({ + skip: dataSkip, + take: getFix, + where: kondisi, + select: { + id: true, + idGroup: true, + title: true, + desc: true, + status: true, + ProjectMember: { + where: { + isActive: true + }, + select: { + idUser: true + } + }, + ProjectTask: { + where: { + isActive: true + }, + select: { + title: true, + status: true + } + }, + Group: { + select: { + name: true + } + } + }, + orderBy: { + createdAt: 'desc' + } + }) + + const omitData = data.map((v: any) => ({ + ..._.omit(v, ["ProjectMember", "ProjectTask", "status", "Group"]), + group: v.Group.name, + status: v.status == 0 ? "segera" : v.status == 1 ? "dikerjakan" : v.status == 2 ? "selesai" : v.status == 3 ? "batal" : "", + progress: ceil((v.ProjectTask.filter((i: any) => i.status == 1).length * 100) / v.ProjectTask.length), + member: v.ProjectMember.length + })) + + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan kegiatan", data: omitData }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} \ No newline at end of file From bbe016c03dba79238d00ac6a95203b814ce87da2 Mon Sep 17 00:00:00 2001 From: amal Date: Fri, 19 Sep 2025 16:47:52 +0800 Subject: [PATCH 5/6] upd: api ai Deskripsi: - list task - detail task No Issues --- src/app/api/ai/project/route.ts | 2 +- src/app/api/ai/task/[id]/route.ts | 180 ++++++++++++++++++++++++++++++ src/app/api/ai/task/route.ts | 104 +++++++++++++++++ 3 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 src/app/api/ai/task/[id]/route.ts create mode 100644 src/app/api/ai/task/route.ts diff --git a/src/app/api/ai/project/route.ts b/src/app/api/ai/project/route.ts index 7db00f3..7715ee5 100644 --- a/src/app/api/ai/project/route.ts +++ b/src/app/api/ai/project/route.ts @@ -92,7 +92,7 @@ export async function GET(request: Request) { const omitData = data.map((v: any) => ({ ..._.omit(v, ["ProjectMember", "ProjectTask", "status", "Group"]), group: v.Group.name, - status: v.status == 0 ? "segera" : v.status == 1 ? "dikerjakan" : v.status == 2 ? "selesai" : v.status == 3 ? "batal" : "", + status: v.status == 1 ? "dikerjakan" : v.status == 2 ? "selesai" : v.status == 3 ? "batal" : "segera", progress: ceil((v.ProjectTask.filter((i: any) => i.status == 1).length * 100) / v.ProjectTask.length), member: v.ProjectMember.length })) diff --git a/src/app/api/ai/task/[id]/route.ts b/src/app/api/ai/task/[id]/route.ts new file mode 100644 index 0000000..75b3261 --- /dev/null +++ b/src/app/api/ai/task/[id]/route.ts @@ -0,0 +1,180 @@ +import { prisma } from "@/module/_global"; +import _ from "lodash"; +import moment from "moment"; +import "moment/locale/id"; +import { NextResponse } from "next/server"; + + +// GET DETAIL TASK DIVISI / GET ONE +export async function GET(request: Request, context: { params: { id: string } }) { + try { + let allData + const { id } = context.params; + const { searchParams } = new URL(request.url); + const kategori = searchParams.get("cat"); + + const data = await prisma.divisionProject.findUnique({ + where: { + id: String(id), + }, + select: { + id: true, + idDivision: true, + title: true, + status: true, + desc: true, + reason: true, + report: true, + isActive: true, + Division: { + select: { + name: true + } + } + } + }); + + if (!data) { + return NextResponse.json({ success: false, message: "Gagal mendapatkan kegiatan, data tidak ditemukan", }, { status: 404 }); + } + + if (kategori == "data") { + const dataProgress = await prisma.divisionProjectTask.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + orderBy: { + updatedAt: 'desc' + } + }) + + const semua = dataProgress.length + const selesai = _.filter(dataProgress, { status: 1 }).length + const progress = Math.ceil((selesai / semua) * 100) + + + allData = { + id: data.id, + idDivision: data.idDivision, + division: data.Division.name, + title: data.title, + status: data.status == 3 ? "batal" : data.status == 2 ? "selesai" : data.status == 1 ? "dikerjakan" : "segera", + desc: data.desc, + reason: data.reason, + report: data.report, + isActive: data.isActive, + progress: progress, + } + } else if (kategori == "task") { + const dataProgress = await prisma.divisionProjectTask.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + select: { + id: true, + title: true, + status: true, + dateStart: true, + dateEnd: true, + }, + orderBy: { + createdAt: 'asc' + } + }) + + const fix = dataProgress.map((v: any) => ({ + ..._.omit(v, ["dateStart", "dateEnd", "status"]), + status: v.status == 1 ? "selesai" : "belum selesai", + dateStart: moment(v.dateStart).format("DD-MM-YYYY"), + dateEnd: moment(v.dateEnd).format("DD-MM-YYYY"), + })) + + allData = fix + + } else if (kategori == "file") { + const dataFile = await prisma.divisionProjectFile.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + select: { + id: true, + ContainerFileDivision: { + select: { + id: true, + name: true, + extension: true, + idStorage: true + } + } + } + }) + + const fix = dataFile.map((v: any) => ({ + ..._.omit(v, ["ContainerFileDivision"]), + nameInStorage: v.ContainerFileDivision.id, + name: v.ContainerFileDivision.name, + extension: v.ContainerFileDivision.extension, + idStorage: v.ContainerFileDivision.idStorage, + })) + + allData = fix + + } else if (kategori == "member") { + const dataMember = await prisma.divisionProjectMember.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + select: { + id: true, + idUser: true, + User: { + select: { + name: true, + email: true, + img: true, + Position: { + select: { + name: true + } + } + } + } + } + }) + + + const fix = dataMember.map((v: any) => ({ + ..._.omit(v, ["User"]), + name: v.User.name, + email: v.User.email, + img: v.User.img, + position: v.User.Position.name + })) + + allData = fix + } else if (kategori == "link") { + const dataLink = await prisma.divisionProjectLink.findMany({ + where: { + isActive: true, + idProject: String(id) + }, + orderBy: { + createdAt: 'asc' + } + }) + + allData = dataLink + } + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan tugas divisi", data: allData }, { status: 200 }); + + } + catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mendapatkan tugas divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/ai/task/route.ts b/src/app/api/ai/task/route.ts new file mode 100644 index 0000000..3fd53dc --- /dev/null +++ b/src/app/api/ai/task/route.ts @@ -0,0 +1,104 @@ +import { prisma } from "@/module/_global"; +import _, { ceil } from "lodash"; +import { NextResponse } from "next/server"; + + +// GET ALL DATA TUGAS DIVISI +export async function GET(request: Request) { + try { + const { searchParams } = new URL(request.url); + const villageId = searchParams.get('desa'); + const division = searchParams.get('division'); + const search = searchParams.get('search'); + const status = searchParams.get('status'); + const page = searchParams.get('page'); + const get = searchParams.get('get'); + + let getFix = 10; + if (get == null || get == undefined || get == "" || _.isNaN(Number(get))) { + getFix = 10; + } else { + getFix = Number(get); + } + + const dataSkip = page == null || page == undefined ? 0 : Number(page) * getFix - getFix; + + let kondisi: any = { + isActive: true, + Division: { + idVillage: String(villageId) + }, + title: { + contains: (search == undefined || search == "null") ? "" : search, + mode: "insensitive" + } + } + + if (status != "null" && status != undefined && status != "" && status != null) { + kondisi = { + ...kondisi, + status: status == "segera" ? 0 : status == "dikerjakan" ? 1 : status == "selesai" ? 2 : status == "batal" ? 3 : 0 + } + } + + if (division != "null" && division != undefined && division != "" && division != null) { + kondisi = { + ...kondisi, + idDivision: String(division) + } + } + + + const data = await prisma.divisionProject.findMany({ + skip: dataSkip, + take: getFix, + where: kondisi, + select: { + id: true, + idDivision: true, + title: true, + desc: true, + status: true, + DivisionProjectTask: { + where: { + isActive: true + }, + select: { + title: true, + status: true + } + }, + DivisionProjectMember: { + where: { + isActive: true + }, + select: { + idUser: true + } + }, + Division: { + select: { + name: true + } + } + }, + orderBy: { + createdAt: "desc" + } + }); + + const formatData = data.map((v: any) => ({ + ..._.omit(v, ["DivisionProjectTask", "DivisionProjectMember", "status", "Division"]), + division: v.Division.name, + status: v.status == 1 ? "dikerjakan" : v.status == 2 ? "selesai" : v.status == 3 ? "batal" : "segera", + progress: ceil((v.DivisionProjectTask.filter((i: any) => i.status == 1).length * 100) / v.DivisionProjectTask.length), + member: v.DivisionProjectMember.length, + })) + + return NextResponse.json({ success: true, message: "Berhasil mendapatkan divisi", data: formatData }, { status: 200 }); + + } catch (error) { + console.error(error); + return NextResponse.json({ success: false, message: "Gagal mendapatkan divisi, coba lagi nanti (error: 500)", reason: (error as Error).message, }, { status: 500 }); + } +} \ No newline at end of file From 09d1088face7c25abcdf61c898c6071a0d123ce1 Mon Sep 17 00:00:00 2001 From: amal Date: Fri, 19 Sep 2025 16:48:22 +0800 Subject: [PATCH 6/6] upd: swagger watcher --- darmasaba-api-ai.yml | 1444 +++++++++++++++++++++++++----------------- 1 file changed, 849 insertions(+), 595 deletions(-) diff --git a/darmasaba-api-ai.yml b/darmasaba-api-ai.yml index 7c83eae..43ca383 100644 --- a/darmasaba-api-ai.yml +++ b/darmasaba-api-ai.yml @@ -1,7 +1,7 @@ openapi: 3.0.3 info: title: API AI Desa+ - description: API untuk AI Desa+ + description: API untuk sistem manajemen AI Desa+ version: 1.0.0 contact: name: API Support @@ -19,42 +19,35 @@ components: bearerFormat: JWT schemas: - # Common Schemas - User: - type: object - properties: - id: - type: string - name: - type: string - phone: - type: string - # Tambahkan properties lain sesuai kebutuhan - required: - - id - - Error: - type: object - properties: - message: - type: string - status: - type: integer - BaseResponse: type: object + required: + - success + - message properties: success: type: boolean message: type: string - - - + meta: + type: object + properties: + total: + type: integer + page: + type: integer + perPage: + type: integer # Banner BannerBase: type: object + required: + - id + - idVillage + - title + - image + - isActive properties: id: type: string @@ -76,31 +69,32 @@ components: format: date-time BannerListResponse: - type: object - properties: - success: - type: boolean - message: - type: string - data: - type: array - items: - $ref: '#/components/schemas/BannerBase' + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/BannerBase' BannerDetailResponse: - type: object - properties: - success: - type: boolean - message: - type: string - data: - $ref: '#/components/schemas/BannerBase' - + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + $ref: '#/components/schemas/BannerBase' # Announcement AnnouncementBase: type: object + required: + - id + - idVillage + - title + - desc + - isActive properties: id: type: string @@ -123,6 +117,9 @@ components: AnnouncementMember: type: object + required: + - idGroup + - idDivision properties: idGroup: type: string @@ -134,42 +131,42 @@ components: type: string AnnouncementListResponse: - type: object - properties: - success: - type: boolean - message: - type: string - data: - type: array - items: - $ref: '#/components/schemas/AnnouncementBase' - - AnnouncementDetailResponse: - type: object - properties: - success: - type: boolean - message: - type: string - data: - type: object + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object properties: - id: - type: string - title: - type: string - desc: - type: string - member: + data: type: array items: - $ref: '#/components/schemas/AnnouncementMember' + $ref: '#/components/schemas/AnnouncementBase' + AnnouncementDetailResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + properties: + id: + type: string + title: + type: string + desc: + type: string + member: + type: array + items: + $ref: '#/components/schemas/AnnouncementMember' # Calendar CalendarBase: type: object + required: + - id + - dateStart + - title + - isActive properties: id: type: string @@ -194,6 +191,11 @@ components: CalendarMember: type: object + required: + - id + - idUser + - name + - email properties: id: type: string @@ -208,58 +210,58 @@ components: nullable: true CalendarListResponse: - type: object - properties: - success: - type: boolean - message: - type: string - data: - type: array - items: - $ref: '#/components/schemas/CalendarBase' - - CalendarDetailResponse: - type: object - properties: - success: - type: boolean - message: - type: string - data: - type: object + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object properties: - id: - type: string - timeStart: - type: string - dateStart: - type: string - format: date-time - timeEnd: - type: string - createdAt: - type: string - format: date-time - title: - type: string - desc: - type: string - linkMeet: - type: string - repeatEventTyper: - type: string - repeatValue: - type: integer - member: + data: type: array items: - $ref: '#/components/schemas/CalendarMember' + $ref: '#/components/schemas/CalendarBase' + CalendarDetailResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + properties: + id: + type: string + timeStart: + type: string + dateStart: + type: string + format: date-time + timeEnd: + type: string + createdAt: + type: string + format: date-time + title: + type: string + desc: + type: string + linkMeet: + type: string + repeatEventType: + type: string + repeatValue: + type: integer + member: + type: array + items: + $ref: '#/components/schemas/CalendarMember' # Discussion DiscussionBase: type: object + required: + - id + - desc + - idDivision + - status properties: id: type: string @@ -276,9 +278,14 @@ components: type: integer status: type: string + enum: [open, close] DiscussionComment: type: object + required: + - id + - comment + - username properties: id: type: string @@ -291,53 +298,50 @@ components: type: string userimg: type: string + nullable: true DiscussionListResponse: - type: object - properties: - success: - type: boolean - message: - type: string - data: - type: array - items: - $ref: '#/components/schemas/DiscussionBase' - - DiscussionDetailResponse: - type: object - properties: - success: - type: boolean - message: - type: string - data: - type: object + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object properties: - id: - type: string - idDivision: - type: string - division: - type: string - isActive: - type: boolean - desc: - type: string - status: - type: string - createdAt: - type: string - format: date-time - createdBy: - type: string - komentar: + data: type: array items: - $ref: '#/components/schemas/DiscussionComment' + $ref: '#/components/schemas/DiscussionBase' + DiscussionDetailResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + properties: + id: + type: string + idDivision: + type: string + division: + type: string + isActive: + type: boolean + desc: + type: string + status: + type: string + enum: [open, close] + createdAt: + type: string + format: date-time + createdBy: + type: string + komentar: + type: array + items: + $ref: '#/components/schemas/DiscussionComment' - # Discussion General + # Discussion General DiskusiUmumListResponse: allOf: - $ref: '#/components/schemas/BaseResponse' @@ -347,6 +351,11 @@ components: type: array items: type: object + required: + - id + - title + - desc + - status properties: id: type: string @@ -361,6 +370,7 @@ components: type: integer status: type: string + enum: [open, close] group: type: string @@ -371,6 +381,11 @@ components: properties: data: type: object + required: + - id + - title + - desc + - status properties: id: type: string @@ -386,6 +401,7 @@ components: type: string status: type: string + enum: [open, close] createdAt: type: string format: date-time @@ -399,6 +415,9 @@ components: type: array items: type: object + required: + - idUser + - name properties: idUser: type: string @@ -417,6 +436,11 @@ components: type: array items: type: object + required: + - id + - comment + - idUser + - username properties: id: type: string @@ -433,9 +457,7 @@ components: type: string nullable: true - - - # Division (mirip Project, disederhanakan) + # Division DivisiListResponse: allOf: - $ref: '#/components/schemas/BaseResponse' @@ -445,6 +467,9 @@ components: type: array items: type: object + required: + - id + - name properties: id: type: string @@ -466,6 +491,10 @@ components: properties: data: type: object + required: + - id + - name + - isActive properties: id: type: string @@ -491,6 +520,10 @@ components: type: array items: type: object + required: + - id + - idUser + - name properties: id: type: string @@ -504,28 +537,92 @@ components: type: string nullable: true - - - - # Group - Group: + # Document + DocumentItem: type: object + required: + - id + - category + - name + - path properties: id: type: string + category: + type: string + enum: [FILE, FOLDER] name: type: string - user: + extension: + type: string + idStorage: + type: string + nullable: true + path: + type: string + createdBy: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + share: + type: boolean + + DocumentListResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/DocumentItem' + + # Group + GroupItem: + type: object + required: + - id + - idVillage + - name + - isActive + properties: + id: + type: string + idVillage: + type: string + name: type: string isActive: type: boolean + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + GroupListResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/GroupItem' + + # Position + PositionItem: + type: object required: - id - name - - # Position - Position: - type: object + - idGroup + - isActive properties: id: type: string @@ -533,109 +630,336 @@ components: type: string idGroup: type: string - user: + group: type: string isActive: type: boolean - required: - - id - - name + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + + PositionListResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/PositionItem' # Project - Project: - type: object - properties: - id: - type: string - name: - type: string - user: - type: string - status: - type: integer - member: - type: array - items: - $ref: '#/components/schemas/User' - required: - - id - - name + BaseResponseProjectList: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + type: object + required: + - id + - idGroup + - title + - status + properties: + id: + type: string + idGroup: + type: string + title: + type: string + desc: + type: string + nullable: true + group: + type: string + status: + type: string + enum: [segera, dikerjakan, selesai, batal] + progress: + type: integer + member: + type: integer - # Task (mirip Project) - Task: - type: object - properties: - id: - type: string - title: - type: string - user: - type: string - status: - type: integer - idDivision: - type: string - required: - - id - - title + BaseResponseProjectDetail: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + required: + - id + - idVillage + - idGroup + - title + - status + - isActive + properties: + id: + type: string + idVillage: + type: string + idGroup: + type: string + group: + type: string + title: + type: string + status: + type: string + enum: [segera, dikerjakan, selesai, batal] + desc: + type: string + nullable: true + reason: + type: string + nullable: true + report: + type: string + nullable: true + isActive: + type: boolean + progress: + type: integer - # Document - - # Notification - NotificationReadBody: - type: object - properties: - user: - type: string - id: - type: string - required: - - user - - id - - # Generic Response - ApiResponse: - type: object - properties: - data: - type: object - success: - type: boolean - required: - - data + BaseResponseTaskList: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + type: object + required: + - id + - idDivision + - title + - status + properties: + id: + type: string + idDivision: + type: string + title: + type: string + desc: + type: string + nullable: true + division: + type: string + status: + type: string + enum: [segera, dikerjakan, selesai, batal] + progress: + type: integer + member: + type: integer + BaseResponseTaskDetail: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + required: + - id + - idDivision + - title + - status + - isActive + properties: + id: + type: string + idDivision: + type: string + division: + type: string + title: + type: string + status: + type: string + desc: + type: string + nullable: true + reason: + type: string + nullable: true + report: + type: string + nullable: true + isActive: + type: boolean + progress: + type: integer + BaseResponseSubTaskList: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + type: object + required: + - id + - title + - status + properties: + id: + type: string + title: + type: string + status: + type: string + enum: [belum selesai, selesai] + dateStart: + type: string + format: date-time + dateEnd: + type: string + format: date-time + BaseResponseMemberList: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + type: object + required: + - id + - idUser + - name + - email + properties: + id: + type: string + idUser: + type: string + name: + type: string + email: + type: string + img: + type: string + nullable: true + position: + type: string + BaseResponseFileList: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + type: object + required: + - id + - name + - path + properties: + id: + type: string + name: + type: string + extension: + type: string + idStorage: + type: string + nullable: true + path: + type: string + createdBy: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time + share: + type: boolean + BaseResponseLinkList: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + type: object + required: + - id + - idProject + - link + - isActive + properties: + id: + type: string + idProject: + type: string + link: + type: string + isActive: + type: boolean + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time paths: # Announcement - /announcement: + /announcement: get: tags: - Announcement - summary: Get announcements + summary: Get list of announcements + description: Retrieves a paginated list of announcements filtered by village parameters: - name: desa in: query required: true + description: Village ID schema: type: string - - name: searh + - name: search in: query + description: Search term for announcement title or description schema: type: string - name: page in: query + description: Page number for pagination schema: type: integer + minimum: 1 + default: 1 - name: get in: query + description: Number of items per page schema: type: integer + minimum: 1 + default: 10 - name: active in: query + description: Filter by active status schema: type: boolean responses: @@ -646,15 +970,17 @@ paths: schema: $ref: '#/components/schemas/AnnouncementListResponse' - /announcement/{id}: + /announcement/{id}: get: tags: - Announcement - summary: Get one announcement + summary: Get announcement details + description: Retrieves details of a specific announcement parameters: - name: id in: path required: true + description: Announcement ID schema: type: string responses: @@ -665,33 +991,42 @@ paths: schema: $ref: '#/components/schemas/AnnouncementDetailResponse' - # Banner - /banner: + /banner: get: tags: - Banner - summary: Get banners + summary: Get list of banners + description: Retrieves a paginated list of banners filtered by village parameters: - name: desa in: query required: true + description: Village ID + schema: + type: string + - name: search + in: query + description: Search term for banner title schema: type: string - name: page in: query + description: Page number for pagination schema: type: integer + minimum: 1 + default: 1 - name: get in: query + description: Number of items per page schema: type: integer - - name: search - in: query - schema: - type: string + minimum: 1 + default: 10 - name: active in: query + description: Filter by active status schema: type: boolean responses: @@ -701,16 +1036,18 @@ paths: application/json: schema: $ref: '#/components/schemas/BannerListResponse' - - /banner/{id}: + + /banner/{id}: get: tags: - Banner - summary: Get one banner + summary: Get banner details + description: Retrieves details of a specific banner parameters: - name: id in: path required: true + description: Banner ID schema: type: string responses: @@ -721,61 +1058,74 @@ paths: schema: $ref: '#/components/schemas/BannerDetailResponse' - # Calendar - /calendar: + /calendar: get: tags: - Calendar - summary: Get calendar by date and division + summary: Get calendar events + description: Retrieves a paginated list of calendar events filtered by village, date, and division parameters: - name: desa in: query required: true + description: Village ID schema: type: string - name: date in: query + description: Filter by event date schema: type: string + format: date - name: division in: query + description: Filter by division ID schema: type: string - name: active in: query + description: Filter by active status schema: type: boolean - name: search in: query + description: Search term for event title or description schema: type: string - name: page in: query + description: Page number for pagination schema: type: integer + minimum: 1 + default: 1 - name: get in: query + description: Number of items per page schema: type: integer + minimum: 1 + default: 10 responses: '200': - description: Calendar events + description: List of calendar events content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/CalendarListResponse' - /calendar/{id}: + $ref: '#/components/schemas/CalendarListResponse' + + /calendar/{id}: get: tags: - Calendar - summary: Get one calendar event + summary: Get calendar event details + description: Retrieves details of a specific calendar event parameters: - name: id in: path required: true + description: Event ID schema: type: string responses: @@ -786,63 +1136,74 @@ paths: schema: $ref: '#/components/schemas/CalendarDetailResponse' - # Discussion - /discussion: + /discussion: get: tags: - Discussion - summary: Get discussions division + summary: Get division discussions + description: Retrieves a paginated list of discussions filtered by village and division parameters: - name: desa in: query required: true + description: Village ID schema: type: string - name: division in: query + description: Filter by division ID schema: type: string - name: status in: query + description: Filter by discussion status schema: type: string enum: [open, close] - name: active in: query + description: Filter by active status schema: type: boolean - name: search in: query + description: Search term for discussion description schema: type: string - name: page in: query + description: Page number for pagination schema: type: integer + minimum: 1 + default: 1 - name: get in: query + description: Number of items per page schema: type: integer + minimum: 1 + default: 10 responses: '200': description: List of discussions content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/DiscussionListResponse' + $ref: '#/components/schemas/DiscussionListResponse' - /discussion/{id}: + /discussion/{id}: get: tags: - Discussion - summary: Get one discussion division + summary: Get division discussion details + description: Retrieves details of a specific division discussion parameters: - name: id in: path required: true + description: Discussion ID schema: type: string responses: @@ -853,72 +1214,85 @@ paths: schema: $ref: '#/components/schemas/DiscussionDetailResponse' - # Discussion General - /discussion-general: + /discussion-general: get: tags: - DiscussionGeneral - summary: Get discussion general + summary: Get general discussions + description: Retrieves a paginated list of general discussions filtered by village and group parameters: - name: desa in: query required: true + description: Village ID schema: type: string - name: group in: query + description: Filter by group ID schema: type: string - name: search in: query + description: Search term for discussion title or description schema: type: string - name: status in: query + description: Filter by discussion status schema: type: string enum: [open, close] - name: active in: query + description: Filter by active status schema: type: boolean - name: page in: query + description: Page number for pagination schema: type: integer + minimum: 1 + default: 1 - name: get in: query + description: Number of items per page schema: type: integer + minimum: 1 + default: 10 responses: '200': - description: List of discussions + description: List of general discussions content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/DiskusiUmumListResponse' + $ref: '#/components/schemas/DiskusiUmumListResponse' - /discussion-general/{id}: + /discussion-general/{id}: get: tags: - DiscussionGeneral - summary: Get one discussion general + summary: Get general discussion details + description: Retrieves details of a specific general discussion, including members or comments based on category parameters: - name: id in: path required: true + description: Discussion ID schema: type: string - name: desa in: query required: true + description: Village ID schema: type: string - name: cat in: query + description: Category of data to retrieve schema: type: string enum: [detail, member, comment] @@ -933,63 +1307,74 @@ paths: - $ref: '#/components/schemas/DiskusiUmumMemberResponse' - $ref: '#/components/schemas/DiskusiUmumCommentResponse' - # Division - /division: + /division: get: tags: - Division summary: Get divisions + description: Retrieves a paginated list of divisions filtered by village and group parameters: - name: desa in: query required: true + description: Village ID schema: type: string - name: active in: query + description: Filter by active status schema: type: boolean - name: group in: query + description: Filter by group ID schema: type: string - name: search in: query + description: Search term for division name or description schema: type: string - name: page in: query + description: Page number for pagination schema: type: integer + minimum: 1 + default: 1 - name: get in: query + description: Number of items per page schema: type: integer + minimum: 1 + default: 10 responses: '200': description: List of divisions content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/DivisiListResponse' - - /division/{id}: + $ref: '#/components/schemas/DivisiListResponse' + + /division/{id}: get: tags: - Division - summary: Get one division detail + summary: Get division details + description: Retrieves details of a specific division parameters: - name: id in: path required: true + description: Division ID schema: type: string - name: desa in: query required: true + description: Village ID schema: type: string responses: @@ -1000,483 +1385,352 @@ paths: schema: $ref: '#/components/schemas/DivisiDetailResponse' - - # Home Data - /home: + # Document + /document: get: tags: - - Home - summary: Get home data by category + - Document + summary: Get documents + description: Retrieves a paginated list of documents and folders filtered by village and division parameters: - - name: user + - name: desa in: query required: true + description: Village ID schema: type: string - - name: cat + - name: division in: query - required: true + description: Filter by division ID schema: type: string - enum: [kegiatan, division, progress, dokumen, event, discussion, header, check-late-project] - responses: - '200': - description: Home data - content: - application/json: - schema: - $ref: '#/components/schemas/ApiResponse' - - /home/search: - get: - tags: - - Home - summary: Search home - parameters: - - name: search + - name: path in: query - required: true - schema: - type: string - - name: user - in: query - required: true - schema: - type: string - responses: - '200': - description: Search results - content: - application/json: - schema: - type: array - items: - type: object - - /home/notification: - get: - tags: - - Notification - summary: Get notifications - parameters: - - name: user - in: query - required: true - schema: - type: string - - name: page - in: query - schema: - type: integer - responses: - '200': - description: List of notifications - content: - application/json: - schema: - type: array - items: - type: object - - # Group - /group: - get: - tags: - - Group - summary: Get groups - parameters: - - name: user - in: query - required: true + description: Filter by document path schema: type: string - name: active in: query - required: true + description: Filter by active status schema: - type: string + type: boolean - name: search in: query - required: true + description: Search term for document name schema: type: string + - name: page + in: query + description: Page number for pagination + schema: + type: integer + minimum: 1 + default: 1 + - name: get + in: query + description: Number of items per page + schema: + type: integer + minimum: 1 + default: 10 + responses: + '200': + description: List of documents and folders + content: + application/json: + schema: + $ref: '#/components/schemas/DocumentListResponse' + + # Group + /group: + get: + tags: + - Group + summary: Get groups + description: Retrieves a paginated list of groups filtered by village + parameters: + - name: desa + in: query + required: true + description: Village ID + schema: + type: string + - name: active + in: query + description: Filter by active status + schema: + type: boolean + - name: search + in: query + description: Search term for group name + schema: + type: string + - name: page + in: query + description: Page number for pagination + schema: + type: integer + minimum: 1 + default: 1 + - name: get + in: query + description: Number of items per page + schema: + type: integer + minimum: 1 + default: 10 responses: '200': description: List of groups content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/Group' + $ref: '#/components/schemas/GroupListResponse' # Position - /position: + /position: get: tags: - Position summary: Get positions + description: Retrieves a paginated list of positions filtered by village and group parameters: - - name: user - in: query - required: true - schema: - type: string - - name: active + - name: desa in: query required: true + description: Village ID schema: type: string - name: group in: query + description: Filter by group ID schema: type: string - name: search in: query - required: true + description: Search term for position name schema: type: string + - name: active + in: query + description: Filter by active status + schema: + type: boolean + - name: page + in: query + description: Page number for pagination + schema: + type: integer + minimum: 1 + default: 1 + - name: get + in: query + description: Number of items per page + schema: + type: integer + minimum: 1 + default: 10 responses: '200': description: List of positions content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/Position' - - # User - /user: - get: - tags: - - User - summary: Get users - parameters: - - name: user - in: query - required: true - schema: - type: string - - name: active - in: query - required: true - schema: - type: string - - name: group - in: query - schema: - type: string - - name: search - in: query - required: true - schema: - type: string - - name: page - in: query - schema: - type: integer - responses: - '200': - description: List of users - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/User' - - /user/{id}: - get: - tags: - - User - summary: Get profile - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - '200': - description: User profile - content: - application/json: - schema: - $ref: '#/components/schemas/User' + $ref: '#/components/schemas/PositionListResponse' # Project - /project: + /project: get: tags: - Project summary: Get projects + description: Retrieves a paginated list of projects filtered by village, group, and status parameters: - - name: user + - name: desa in: query required: true + description: Village ID schema: type: string - name: status in: query - required: true + description: Filter by project status schema: type: string + enum: [segera, dikerjakan, selesai, batal] - name: group in: query + description: Filter by group ID schema: type: string - name: search in: query - required: true - schema: - type: string - - name: cat - in: query + description: Search term for project title or description schema: type: string - name: page in: query + description: Page number for pagination schema: type: integer + minimum: 1 + default: 1 + - name: get + in: query + description: Number of items per page + schema: + type: integer + minimum: 1 + default: 10 responses: '200': description: List of projects content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/Project' + $ref: '#/components/schemas/BaseResponseProjectList' - /project/{id}: + /project/{id}: get: tags: - Project - summary: Get one project + summary: Get project details + description: Retrieves details of a specific project based on category parameters: - name: id in: path required: true - schema: - type: string - - name: user - in: query - required: true + description: Project ID schema: type: string - name: cat in: query required: true + description: Category of project data to retrieve schema: type: string - enum: [data, progress, task, file, member, link] + enum: [data, task, file, member, link] responses: '200': description: Project details content: application/json: schema: - $ref: '#/components/schemas/Project' + oneOf: + - $ref: '#/components/schemas/BaseResponseProjectDetail' + - $ref: '#/components/schemas/BaseResponseTaskList' + - $ref: '#/components/schemas/BaseResponseMemberList' + - $ref: '#/components/schemas/BaseResponseFileList' + - $ref: '#/components/schemas/BaseResponseLinkList' # Task - /task: + /task: get: tags: - Task summary: Get tasks + description: Retrieves a paginated list of tasks filtered by village, division, and status parameters: - - name: user - in: query - required: true - schema: - type: string - - name: status + - name: desa in: query required: true + description: Village ID schema: type: string - name: division in: query - required: true + description: Filter by division ID schema: type: string + - name: status + in: query + description: Filter by task status + schema: + type: string + enum: [segera, dikerjakan, selesai, batal] - name: search in: query - required: true + description: Search term for task title or description schema: type: string - name: page in: query + description: Page number for pagination schema: type: integer + minimum: 1 + default: 1 + - name: get + in: query + description: Number of items per page + schema: + type: integer + minimum: 1 + default: 10 responses: '200': description: List of tasks content: application/json: schema: - type: array - items: - $ref: '#/components/schemas/Task' + $ref: '#/components/schemas/BaseResponseTaskList' - /task/{id}: + /task/{id}: get: tags: - Task - summary: Get one task + summary: Get task details + description: Retrieves details of a specific task based on category parameters: - name: id in: path required: true - schema: - type: string - - name: user - in: query - required: true + description: Task ID schema: type: string - name: cat in: query required: true + description: Category of task data to retrieve schema: type: string - enum: [data, progress, task, file, member, link] + enum: [data, task, file, member, link] responses: '200': description: Task details content: application/json: schema: - $ref: '#/components/schemas/Task' - - /task/detail/{id}: - get: - tags: - - Task - summary: Get task tugas - parameters: - - name: id - in: path - required: true - schema: - type: string - - name: user - in: query - required: true - schema: - type: string - - name: cat - in: query - schema: - type: string - responses: - '200': - description: Tugas details - content: - application/json: - schema: - $ref: '#/components/schemas/ApiResponse' - - # Document - /document: - get: - tags: - - Document - summary: Get documents - parameters: - - name: user - in: query - required: true - schema: - type: string - - name: path - in: query - required: true - schema: - type: string - - name: division - in: query - required: true - schema: - type: string - - name: category - in: query - required: true - schema: - type: string - enum: [all, folder] - responses: - '200': - description: List of documents - content: - application/json: - schema: - type: array - items: - type: object - - /document/more: - get: - tags: - - Document - summary: Get document info - parameters: - - name: user - in: query - required: true - schema: - type: string - - name: item - in: query - required: true - schema: - type: string - - name: cat - in: query - required: true - schema: - type: string - enum: [share, lainnya] - responses: - '200': - description: Info - content: - application/json: - schema: - $ref: '#/components/schemas/ApiResponse' - + oneOf: + - $ref: '#/components/schemas/BaseResponseTaskDetail' + - $ref: '#/components/schemas/BaseResponseSubTaskList' + - $ref: '#/components/schemas/BaseResponseMemberList' + - $ref: '#/components/schemas/BaseResponseFileList' + - $ref: '#/components/schemas/BaseResponseLinkList' security: - bearerAuth: [] tags: - name: Announcement - description: Announcements + description: Operations related to announcements - name: Banner - description: Banner management + description: Operations related to banner management - name: Calendar - description: Calendar events + description: Operations related to calendar events - name: Discussion - description: Division discussions + description: Operations related to division discussions - name: DiscussionGeneral - description: General discussions + description: Operations related to general discussions - name: Division - description: Division management - - - name: Home - description: Home and search - - name: Group - description: Group management - - name: Position - description: Position management - - name: User - description: User management - - name: Project - description: Project management - - name: Task - description: Task management + description: Operations related to division management - name: Document - description: Document management - - name: Notification - description: Notifications + description: Operations related to document management + - name: Group + description: Operations related to group management + - name: Position + description: Operations related to position management + - name: Project + description: Operations related to project management + - name: Task + description: Operations related to task management \ No newline at end of file