diff --git a/apps/backend/src/drizzle/seed.ts b/apps/backend/src/drizzle/seed.ts index bb98014..9d35f19 100644 --- a/apps/backend/src/drizzle/seed.ts +++ b/apps/backend/src/drizzle/seed.ts @@ -4,6 +4,11 @@ import roleSeeder from "./seeds/rolesSeeder"; import userSeeder from "./seeds/userSeeder"; import aspectsSeeder from "./seeds/aspectsSeeder"; import subAspectsSeeder from "./seeds/subAspectsSeeder"; +import answersSeeder from "./seeds/answersSeeder"; +import assessmentsSeeder from "./seeds/assessmentsSeeder"; +import optionsSeeder from "./seeds/optionsSeeder"; +import questionSeeder from "./seeds/questionSeeder"; +import respondentSeeder from "./seeds/respondentsSeeder"; (async () => { console.time("Done seeding"); @@ -13,6 +18,11 @@ import subAspectsSeeder from "./seeds/subAspectsSeeder"; await userSeeder(); await aspectsSeeder(); await subAspectsSeeder(); + await answersSeeder(); + await assessmentsSeeder(); + await optionsSeeder(); + await questionSeeder(); + await respondentSeeder(); })().then(() => { console.log("\n"); console.timeEnd("Done seeding"); diff --git a/apps/backend/src/drizzle/seeds/answersSeeder.ts b/apps/backend/src/drizzle/seeds/answersSeeder.ts new file mode 100644 index 0000000..7f1fb61 --- /dev/null +++ b/apps/backend/src/drizzle/seeds/answersSeeder.ts @@ -0,0 +1,62 @@ +import { createId } from "@paralleldrive/cuid2"; +import db from ".."; +import { answers } from "../schema/answers"; +import { options } from "../schema/options"; +import { assessments } from "../schema/assessments"; + +type answers = { + id: string; + optionId: string; + assessmentId: string | null; + isFlagged: boolean; + filename: string; + validationInformation: string; + createdAt: Date; + updatedAt: Date; +}; + +const answersSeeder = async () => { + const optionsData = await db.select().from(options); + const assessmentData = await db.select().from(assessments); + + const answersData: answers[] = []; + + optionsData.forEach(option => { + // assessmentData.forEach(assessment => { + answersData.push({ + id: createId(), + optionId: option.id, + assessmentId: null, + isFlagged: false, + filename: "answer.pdf", + validationInformation: "Sudah teruji dengan baik", + createdAt: new Date(), + updatedAt: new Date(), + }); + // }); + }); + + console.log("Seeding answers..."); + + for (let submitAnswers of answersData) { + try { + const insertedAnswers = ( + await db + .insert(answers) + .values(submitAnswers) + .onConflictDoNothing() + .returning() + )[0]; + + if (insertedAnswers) { + console.log(`Answers created`); + } else { + console.log(`Answers already exists`); + } + } catch (error) { + console.error(`Error inserting answers :`, error); + } + } +}; + +export default answersSeeder; \ No newline at end of file diff --git a/apps/backend/src/drizzle/seeds/assessmentsSeeder.ts b/apps/backend/src/drizzle/seeds/assessmentsSeeder.ts new file mode 100644 index 0000000..7daf68b --- /dev/null +++ b/apps/backend/src/drizzle/seeds/assessmentsSeeder.ts @@ -0,0 +1,103 @@ +import { createId } from "@paralleldrive/cuid2"; +import db from ".."; +import { assessments } from "../schema/assessments"; +import { respondents } from "../schema/respondents"; +import { users } from "../schema/users"; + +type AssessmentData = { + id: string; + status: "menunggu konfirmasi" | "diterima" | "ditolak" | "selesai"; + reviewedAt: Date; + reviewedBy: string; + validatedBy: string; + validatedAt: Date; + createdAt: Date, + respondentId: string; +}; + +const assessmentsSeeder = async () => { + const respondentsData = await db.select().from(respondents); + + const assessmentsData: AssessmentData[] = []; + + respondentsData.forEach((respondent) => { + assessmentsData.push({ + id: createId(), + status: "diterima", + reviewedAt: new Date(), + reviewedBy: "Reviewer B", + validatedBy: "Reviewer A", + validatedAt: new Date(), + createdAt: new Date(), + respondentId: respondent.id, + + }); + + assessmentsData.push({ + id: createId(), + status: "ditolak", + reviewedAt: new Date(), + reviewedBy: "Reviewer C", + validatedBy: "Reviewer D", + validatedAt: new Date(), + createdAt: new Date(), + respondentId: respondent.id, + }); + + assessmentsData.push({ + id: createId(), + status: "menunggu konfirmasi", + reviewedAt: new Date(), + reviewedBy: "Reviewer W", + validatedBy: "Reviewer S", + validatedAt: new Date(), + createdAt: new Date(), + respondentId: respondent.id, + }); + + assessmentsData.push({ + id: createId(), + status: "selesai", + reviewedAt: new Date(), + reviewedBy: "Reviewer F", + validatedBy: "Reviewer G", + validatedAt: new Date(), + createdAt: new Date(), + respondentId: respondent.id, + }); + assessmentsData.push({ + id: createId(), + status: "selesai", + reviewedAt: new Date(), + reviewedBy: "Reviewer I", + validatedBy: "Reviewer L", + validatedAt: new Date(), + createdAt: new Date(), + respondentId: respondent.id, + }); + }); + + console.log("Seeding assessments..."); + + for (let assessment of assessmentsData) { + try { + const insertedAssessment = ( + await db + .insert(assessments) + .values(assessment) + .onConflictDoNothing() + .returning() + )[0]; + + if (insertedAssessment) { + console.log(`Assessment for respondent ${assessment.respondentId} created`); + } else { + console.log(`Assessment for respondent ${assessment.respondentId} already exists`); + } + } catch (error) { + console.error(`Error inserting assessment for respondent ${assessment.respondentId}:, error`); + } + } +}; + +export default assessmentsSeeder; \ No newline at end of file diff --git a/apps/backend/src/drizzle/seeds/optionsSeeder.ts b/apps/backend/src/drizzle/seeds/optionsSeeder.ts new file mode 100644 index 0000000..e2d03c4 --- /dev/null +++ b/apps/backend/src/drizzle/seeds/optionsSeeder.ts @@ -0,0 +1,148 @@ +import { createId } from "@paralleldrive/cuid2"; +import db from ".."; +import { eq, and } from "drizzle-orm"; +import { options } from "../schema/options"; +import { questions } from "../schema/questions"; + +const optionsSeeder = async () => { + + const optionsData: (typeof options.$inferInsert & { question: string})[] = [ + { + text: "Ya", + score: 5, + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + question: "Apakah organisasi Anda membuat program pemahaman kesadaran keamanan informasi untuk semua karyawan secara berkala (setidaknya setiap tahun sekali) dalam rangka memastikan mereka memahami serta menunjukkan behavior dan skill yang diperlukan untuk memastikan keamanan informasi di organisasi? Jika ada, apakah program kesadaran keamanan organisasi dilakukan secara berkelanjutan?", + }, + { + text: "Tidak", + score: 1, + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + question: "Apakah organisasi Anda membuat program pemahaman kesadaran keamanan informasi untuk semua karyawan secara berkala (setidaknya setiap tahun sekali) dalam rangka memastikan mereka memahami serta menunjukkan behavior dan skill yang diperlukan untuk memastikan keamanan informasi di organisasi? Jika ada, apakah program kesadaran keamanan organisasi dilakukan secara berkelanjutan?", + }, + { + text: "Ya", + score: 5, + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + question: "Apakah organisasi Anda memastikan bahwa terdapat program kesadaran keamanan informasi diperbarui secara berkala untuk mnyesuaikan terhadap teknologi terbaru, standar, dan persyaratan bisnis serta mengatasi adanya ancaman?", + }, + { + text: "Tidak", + score: 1, + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + question: "Apakah organisasi Anda memastikan bahwa terdapat program kesadaran keamanan informasi diperbarui secara berkala untuk mnyesuaikan terhadap teknologi terbaru, standar, dan persyaratan bisnis serta mengatasi adanya ancaman?", + }, + { + text: "Ya", + score: 5, + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + question: "Apakah organisasi Anda memiliki kebijakan mengharuskan penerapan perlindungan data pribadi? Dan apakah direviu secara berkala?", + }, + { + text: "Tidak", + score: 1, + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + question: "Apakah organisasi Anda memiliki kebijakan mengharuskan penerapan perlindungan data pribadi? Dan apakah direviu secara berkala?", + }, + { + text: "Ya", + score: 5, + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + question: "Apakah pemeriksaan background dilakukan untuk semua karyawan baru?", + }, + { + text: "Tidak", + score: 1, + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + question: "Apakah pemeriksaan background dilakukan untuk semua karyawan baru?", + }, + { + text: "Ya", + score: 5, + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + question: "Dalam pengembangan software organisasi Anda, apakah menggunakan algoritma enkripsi dan direviu secara berkala?", + }, + { + text: "Tidak", + score: 1, + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + question: "Dalam pengembangan software organisasi Anda, apakah menggunakan algoritma enkripsi dan direviu secara berkala?", + }, + ]; + + console.log("Seeding options..."); + + const memoizedQuestionIds: Map = new Map(); + + for (let option of optionsData) { + // Check if sub aspect ID is already memoized + if (!memoizedQuestionIds.has(option.question)) { + const questionData = ( + await db + .select({ id: questions.id }) + .from(questions) + .where(eq(questions.question, option.question)) + )[0]; + + if (!questionData) { + throw new Error(`Question ${questions.question} does not exist in the database`); + } + + memoizedQuestionIds.set(option.question, questionData.id); + } + + const questionId = memoizedQuestionIds.get(option.question)!; + + // Check if the question already exists + const existingOption = await db + .select() + .from(options) + .where(and(eq(options.text as any, option.text as any), eq(options.questionId, questionId))) + .limit(1); + + if (existingOption.length === 0) { + // If the questions does not exist, insert it + const insertedOption = ( + await db + .insert(options) + .values({ + questionId: questionId, + text: option.text, + score: option.score, + createdAt: option.createdAt, + updatedAt: option.updatedAt, + deletedAt: option.deletedAt, + }) + .onConflictDoNothing() + .returning() + )[0]; + + if (insertedOption) { + console.log(`Options ${option.text} created and linked to question ${option.question}`); + } + } else { + console.log(`Options ${option.text} already exists`); + } + } +}; + +export default optionsSeeder; \ No newline at end of file diff --git a/apps/backend/src/drizzle/seeds/questionSeeder.ts b/apps/backend/src/drizzle/seeds/questionSeeder.ts new file mode 100644 index 0000000..ab91f6d --- /dev/null +++ b/apps/backend/src/drizzle/seeds/questionSeeder.ts @@ -0,0 +1,213 @@ +import { subAspects } from "../schema/subAspects"; +import db from ".."; +import { eq, and } from "drizzle-orm"; +import { questions } from "../schema/questions"; + +const questionSeeder = async () => { + const questionsData: (typeof questions.$inferInsert & { subAspectName: string})[] = [ + { + question: "Apakah organisasi Anda membuat program pemahaman kesadaran keamanan informasi untuk semua karyawan secara berkala (setidaknya setiap tahun sekali) dalam rangka memastikan mereka memahami serta menunjukkan behavior dan skill yang diperlukan untuk memastikan keamanan informasi di organisasi? Jika ada, apakah program kesadaran keamanan organisasi dilakukan secara berkelanjutan?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda memastikan bahwa terdapat program kesadaran keamanan informasi diperbarui secara berkala untuk mnyesuaikan terhadap teknologi terbaru, standar, dan persyaratan bisnis serta mengatasi adanya ancaman?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah semua karyawan Anda mengetahui dan menerapkan kebijakan keamanan informasi di lingkungan kerja Anda?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah setiap karyawan baru di organisai Anda mendapatkan pengarahan mengenai keamanan informasi?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah semua karyawan Anda memberikan kontribusi terhadap efektivitas sistem manajemen keamanan informasi?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda melakukan gap analisis untuk memahami skill dan behavior yang tidak dimiliki oleh karyawan, dan menggunakan informasi tersebut untuk membuat roadmap terkait baseline pendidikan dan pelatihan terkait keamanan informasi?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda melakukan pelatihan keamanan informasi secara terjadwal untuk semua karyawan?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda memberikan pelatihan untuk pegawai tentang pentingnya penggunaan secure authentication? Contohnya seperti autentikasi login ke email organisasi, aplikasi kritikal organisasi, akses jaringan organisasi, dll.", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda memberikan pelatihan untuk karyawan tentang cara mengidentifikasi berbagai bentuk serangan social engineering, seperti phishing, scam phone, dan impersonation call?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda memberikan pelatihan untuk karyawan tentang cara mengidentifikasi dan menyimpan, mengirim, mengarsipkan, dan memusnahkan informasi sensitif dengan benar?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda memberikan pelatihan untuk karyawan terkait kesadaran tentang penyebab kebocoran data secara tidak sengaja, seperti kehilangan perangkat seluler karyawan atau ketidaksengajaan mengirim email ke orang yang salah?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah karyawan yang menangani data sensitif stakeholder / klien / konsumen / pelanggan dilatih tentang cara melindungi data tersebut, pembatasan penggunaan, dan mendokumentasikan dari proses yang harus karyawan ikuti?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda melatih staf secara khusus tentang kewajiban menjaga data privasi, termasuk hukuman terkait pengungkapan data yang salah?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda melakukan manajemen kerentanan siber dan mitigasi terhadap kerentanan?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda melakukan simulasi phishing setidaknya setiap tahun?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Dalam pengembangan software/aplikasi di organisasi, apakah personel yang terlibat dalam pengembangan software/aplikasi telah mendapatkan pelatihan dalam membuat secure code yang baik?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda memberitahukan kepada stakeholder / klien / konsumen / pelanggan Anda tentang teknik atau kerentanan siber yang berkembang saat ini yang dapat digunakan dalam peningkatan risiko fraud/penipuan?", + needFile: false, + subAspectName: "Kesadaran" + }, + { + question: "Apakah organisasi Anda memiliki kebijakan mengharuskan penerapan perlindungan data pribadi? Dan apakah direviu secara berkala?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah pemeriksaan background dilakukan untuk semua karyawan baru?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Dalam pengembangan software organisasi Anda, apakah menggunakan algoritma enkripsi dan direviu secara berkala?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah organisasi Anda menggunakan tool vulnerability scanning secara mandiri, yang mana hasil vulnerability assessment digunakan sebagai titik awal dalam melakukan penetrating testing?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah di organisasi Anda menggunakan akun khusus selain akun admin untuk melakukan vulnerability scanning?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah setiap akun pengguna atau sistem yang digunakan dalam melakukan penetrating testing dikontrol dan dipantau untuk memastikan bahwa akun tersebut hanya digunakan untuk tujuan yang sah, dan dihapus atau dikembalikan ke fungsi normal setelah pengujian selesai dilakukan?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah organisasi Anda melakukan reviu security risk assessment? Dan apakah dilakukan secara berkala?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah organisasi Anda melakukan reviu security risk treatment? Dan apakah dilakukan secara berkelanjutan?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah organisasi Anda melakukan internal audit keamanan informasi secara berkala?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah organisasi Anda mereviu izin akses dari akun pengguna setidaknya setiap tiga bulan?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah ada dokumentasi/diagram yang menggambarkan semua aliran data di seluruh sistem dan jaringan dan apakah dilakukan pembaruan?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah organisasi Anda telah menerapkan dan mendokumentasikan standar konfigurasi (port, protokol, service) untuk semua sistem, seperti operating system, software/aplikasi, dan lain-lain?", + needFile: false, + subAspectName: "Audit" + }, + { + question: "Apakah organisasi Anda memastikan sistem manajemen keamanan informasi dapat mencapai hasil yang diharapkan?", + needFile: false, + subAspectName: "Kontrol" + }, + ]; + + console.log("Seeding questions..."); + + const memoizedSubAspectIds: Map = new Map(); + + for (let question of questionsData) { + // Check if sub aspect ID is already memoized + if (!memoizedSubAspectIds.has(question.subAspectName)) { + const subAspect = ( + await db + .select({ id: subAspects.id }) + .from(subAspects) + .where(eq(subAspects.name, question.subAspectName)) + )[0]; + + if (!subAspect) { + throw new Error(`Sub Aspect ${question.subAspectName} does not exist in the database`); + } + + memoizedSubAspectIds.set(question.subAspectName, subAspect.id); + } + + const subAspectId = memoizedSubAspectIds.get(question.subAspectName)!; + + // Check if the question already exists + const existingQuestion = await db + .select() + .from(questions) + .where(and(eq(questions.question as any, question.question as any), eq(questions.subAspectId, subAspectId))) + .limit(1); + + if (existingQuestion.length === 0) { + // If the questions does not exist, insert it + const insertedQuestion = ( + await db + .insert(questions) + .values({ + question: question.question, + needFile: question.needFile, + subAspectId: subAspectId + }) + .onConflictDoNothing() + .returning() + )[0]; + + if (insertedQuestion) { + console.log(`Question ${question.question} created and linked to sub aspect ${question.subAspectName}`); + } + } else { + console.log(`Question ${question.question} already exists`); + } + } +}; + +export default questionSeeder; diff --git a/apps/backend/src/drizzle/seeds/respondentsSeeder.ts b/apps/backend/src/drizzle/seeds/respondentsSeeder.ts new file mode 100644 index 0000000..f2769d3 --- /dev/null +++ b/apps/backend/src/drizzle/seeds/respondentsSeeder.ts @@ -0,0 +1,110 @@ +import db from ".."; +import { eq, and } from "drizzle-orm"; +import { users } from "../schema/users"; +import { respondents } from "../schema/respondents"; + +const respondentSeeder = async () => { + const respondentsData: (typeof respondents.$inferInsert & { userName: string })[] = [ + { + userName: "Respondent User 2", + companyName: "Company C", + position: "Employee", + workExperience: "4 years", + address: "Address D", + phoneNumber: "1234567890123", + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + }, + { + userName: "Respondent User 3", + companyName: "Company DD", + position: "Manager Account", + workExperience: "6 years", + address: "Address HRT", + phoneNumber: "1234567890123", + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + }, + { + userName: "Respondent User 4", + companyName: "Company FS", + position: "Developer", + workExperience: "8 years", + address: "Address HFD", + phoneNumber: "1234567890123", + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + }, + { + userName: "Respondent User 5", + companyName: "Company DA", + position: "Start", + workExperience: "3 years", + address: "Address JWO", + phoneNumber: "1234567890123", + createdAt: new Date(), + updatedAt: new Date(), + deletedAt: null, + }, +]; + + console.log("Seeding users and respondents..."); + + const memoizedUserIds: Map = new Map(); + + for (let respondent of respondentsData) { + if (!memoizedUserIds.has(respondent.userName)) { + const user = ( + await db + .select({ id: users.id }) + .from(users) + .where(eq(users.name, respondent.userName)) + )[0]; + + if (!user) { + throw new Error(`User ${respondent.userName} does not exist in the database`); + } + + memoizedUserIds.set(respondent.userName, user.id); + } + + const UserId = memoizedUserIds.get(respondent.userName)!; + + const existingRespondent = await db + .select() + .from(respondents) + .where(and(eq(respondents.companyName, respondent.userName), eq(respondents.userId, UserId))) + .limit(1); + + if (existingRespondent.length === 0) { + const insertedRespondent = ( + await db + .insert(respondents) + .values({ + companyName: respondent.companyName, + position: respondent.position, + workExperience: respondent.workExperience, + address: respondent.address, + phoneNumber: respondent.phoneNumber, + createdAt: respondent.createdAt, + updatedAt: respondent.updatedAt, + deletedAt: respondent.deletedAt, + userId: UserId, + }) + .onConflictDoNothing() + .returning() + )[0]; + + if (insertedRespondent) { + console.log(`Respondent ${respondent.companyName} created and linked to respondent ${respondent.userName}`); + } + } else { + console.log(`Respondent ${respondent.companyName} already exists`); + } + } +}; + +export default respondentSeeder; \ No newline at end of file