commit 1cb2056c2c4f9510c18aa41a2b97c8538871846e Author: marvin-lucky Date: Fri Jul 25 18:00:13 2025 +0700 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84c048a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/build/ diff --git a/.gradle/8.6/checksums/checksums.lock b/.gradle/8.6/checksums/checksums.lock new file mode 100644 index 0000000..6032138 Binary files /dev/null and b/.gradle/8.6/checksums/checksums.lock differ diff --git a/.gradle/8.6/checksums/md5-checksums.bin b/.gradle/8.6/checksums/md5-checksums.bin new file mode 100644 index 0000000..60a62d1 Binary files /dev/null and b/.gradle/8.6/checksums/md5-checksums.bin differ diff --git a/.gradle/8.6/checksums/sha1-checksums.bin b/.gradle/8.6/checksums/sha1-checksums.bin new file mode 100644 index 0000000..00b3075 Binary files /dev/null and b/.gradle/8.6/checksums/sha1-checksums.bin differ diff --git a/.gradle/8.6/dependencies-accessors/gc.properties b/.gradle/8.6/dependencies-accessors/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/8.6/executionHistory/executionHistory.bin b/.gradle/8.6/executionHistory/executionHistory.bin new file mode 100644 index 0000000..a92e582 Binary files /dev/null and b/.gradle/8.6/executionHistory/executionHistory.bin differ diff --git a/.gradle/8.6/executionHistory/executionHistory.lock b/.gradle/8.6/executionHistory/executionHistory.lock new file mode 100644 index 0000000..1a646ae Binary files /dev/null and b/.gradle/8.6/executionHistory/executionHistory.lock differ diff --git a/.gradle/8.6/fileChanges/last-build.bin b/.gradle/8.6/fileChanges/last-build.bin new file mode 100644 index 0000000..f76dd23 Binary files /dev/null and b/.gradle/8.6/fileChanges/last-build.bin differ diff --git a/.gradle/8.6/fileHashes/fileHashes.bin b/.gradle/8.6/fileHashes/fileHashes.bin new file mode 100644 index 0000000..2472b0d Binary files /dev/null and b/.gradle/8.6/fileHashes/fileHashes.bin differ diff --git a/.gradle/8.6/fileHashes/fileHashes.lock b/.gradle/8.6/fileHashes/fileHashes.lock new file mode 100644 index 0000000..7dd093d Binary files /dev/null and b/.gradle/8.6/fileHashes/fileHashes.lock differ diff --git a/.gradle/8.6/fileHashes/resourceHashesCache.bin b/.gradle/8.6/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000..2150e21 Binary files /dev/null and b/.gradle/8.6/fileHashes/resourceHashesCache.bin differ diff --git a/.gradle/8.6/gc.properties b/.gradle/8.6/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000..818820a Binary files /dev/null and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..6e470ca --- /dev/null +++ b/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Thu Mar 06 11:58:08 ICT 2025 +gradle.version=8.6 diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000..545ff47 Binary files /dev/null and b/.gradle/buildOutputCleanup/outputFiles.bin differ diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe new file mode 100644 index 0000000..485efc3 Binary files /dev/null and b/.gradle/file-system.probe differ diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..82a9851 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +tte-auth-service \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..a73c751 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..7d3b3e8 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,17 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..8d752e6 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..3efc67a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/tte-auth-service.main.iml b/.idea/modules/tte-auth-service.main.iml new file mode 100644 index 0000000..afc1871 --- /dev/null +++ b/.idea/modules/tte-auth-service.main.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/tte-auth-service.test.iml b/.idea/modules/tte-auth-service.test.iml new file mode 100644 index 0000000..db191b3 --- /dev/null +++ b/.idea/modules/tte-auth-service.test.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/tte-auth-service-v2.iml b/.idea/tte-auth-service-v2.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/tte-auth-service-v2.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..35eb33d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,33 @@ +FROM gradle:8-jdk17 as build +WORKDIR /mm-auth-service +COPY build.gradle build.gradle +COPY settings.gradle settings.gradle +COPY src src +COPY conf conf +COPY sql sql +RUN gradle shadowJar + +FROM eclipse-temurin:17-jdk +# Set Timezone +ENV TZ=Asia/Jakarta +RUN apt-get update && \ + apt-get install -y tzdata && \ + ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ + echo $TZ > /etc/timezone && \ + apt-get clean \ + +WORKDIR /mm-auth-service +COPY --from=build /mm-auth-service/build/libs/mm-auth-service-1.0.0-all.jar app.jar +COPY conf conf +COPY sql sql + +RUN mkdir -p /mm-auth-service/tmp +RUN chmod -R 777 /mm-auth-service/tmp + +EXPOSE 8080 + +ENV JAVA_OPTS="-Xms256m -Xmx2048m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UseStringDeduplication -Djava.security.egd=file:/dev/./urandom" + +CMD java $JAVA_OPTS -jar app.jar + +#CMD ["java", "-jar", "app.jar"] diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..e21022a --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,288 @@ +// Refactored Jenkinsfile for tte-auth-app +// Standardized to match the latest CI/CD template. + +import groovy.transform.Field +import groovy.json.JsonOutput +import java.text.SimpleDateFormat + +// A field to accumulate log messages for the final notification. +@Field +String pipelineLog = '' + +/** + * Appends a formatted message to the pipeline log for inclusion in the final notification. + * @param message The string message to log. + */ +def appendLog(String message) { + echo "[LOG] ${message}" + pipelineLog += "\n${message.trim()}" +} + +/** + * Sends a rich, formatted notification to a Discord webhook using embeds. + * @param params A map of parameters including status, jobName, buildUrl, etc. + */ +def sendDiscordNotification(Map params) { + // Parameter validation + ['status', 'jobName', 'buildNumber', 'buildUrl', 'webhookCredentialId'].each { key -> + if (!params[key]) { + echo "⚠️ sendDiscordNotification: Missing required parameter '${key}'" + return + } + } + + def colorValue, statusEmoji + def statusText = params.status.toUpperCase() + def embedTitle + + // Determine color and emoji based on build status + switch (statusText) { + case 'SUCCESS': colorValue = 0x28A745; statusEmoji = "✅"; embedTitle = "${statusEmoji} Build Successful: ${params.jobName.split('/').last()}"; break + case 'FAILURE': colorValue = 0xDC3545; statusEmoji = "❌"; embedTitle = "${statusEmoji} Build Failed: ${params.jobName.split('/').last()}"; break + case 'UNSTABLE': colorValue = 0xFFC107; statusEmoji = "⚠️"; embedTitle = "${statusEmoji} Build Unstable: ${params.jobName.split('/').last()}"; break + case 'ABORTED': colorValue = 0x6C757D; statusEmoji = "🚫"; embedTitle = "${statusEmoji} Build Aborted: ${params.jobName.split('/').last()}"; break + case 'APPROVAL_REQUEST': colorValue = 0x007BFF; statusEmoji = "🔔"; embedTitle = "${statusEmoji} Approval Required: ${params.jobName.split('/').last()}"; break + default: colorValue = 0x17A2B8; statusEmoji = "ℹ️"; embedTitle = "${statusEmoji} Build Notification (${statusText}): ${params.jobName.split('/').last()}"; break + } + + // Special highlighting for the production branch + if (params.branchName == 'main') { + if (!['FAILURE', 'ABORTED'].contains(statusText.toUpperCase())) { + colorValue = 0xFFD700 // Gold color for production + } + embedTitle = "❗ PRODUCTION: ${embedTitle}" + } + + // Build the main description text + def descriptionLines = [] + if (params.customMessage) { + descriptionLines.add(params.customMessage.stripIndent().trim()) + descriptionLines.add("") + } + descriptionLines.add("**Project:** `${params.jobName.replaceAll("/", " / ")}`") + if (params.branchName) { + descriptionLines.add("**Branch:** `${params.branchName}`") + } + descriptionLines.add("**Build:** [#${params.buildNumber}](${params.buildUrl}display/redirect) - **${statusText.toUpperCase()}**") + if (params.nodeName) { + descriptionLines.add("**Node:** `${params.nodeName}`") + } + if (params.triggeredBy) { + descriptionLines.add("**Triggered by:** ${params.triggeredBy}") + } + + // Add commit details + def commitDetails = "" + if (params.processedCommits && !params.processedCommits.isEmpty()) { + def commitMessages = params.processedCommits.collect { c -> " - `${c.commitId}`: ${c.message} (_${c.author}_)" } + commitDetails = "\n\n📜 **Commits:**\n" + commitMessages.join('\n') + } + descriptionLines.add(commitDetails) + def description = descriptionLines.join('\n').take(4000) + + // Footer with timestamp + def footerTimeZone = TimeZone.getTimeZone(params.footerTimeZone ?: 'UTC') + def footerTimestamp = new Date(params.buildTimestamp ?: System.currentTimeMillis()).format("yyyy-MM-dd HH:mm:ss z", footerTimeZone) + + // Construct the final embed payload + def embed = [ + title: embedTitle.take(250), + description: description, + color: colorValue, + timestamp: new Date(params.buildTimestamp ?: System.currentTimeMillis()).format("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone('UTC')), + url: "${params.buildUrl}display/redirect", + footer: [ text: "Jenkins Build #${params.buildNumber} • ${footerTimestamp}", icon_url: params.footerIconUrl ?: params.avatarUrl ] + ] + + if (params.customFields) { embed.fields = params.customFields } + + def payloadMap = [embeds: [embed]] + if (params.username) { payloadMap.username = params.username.take(80) } + if (params.avatarUrl) { payloadMap.avatar_url = params.avatarUrl } + + def jsonPayload = groovy.json.JsonOutput.toJson(payloadMap) + + withCredentials([string(credentialsId: params.webhookCredentialId, variable: 'DISCORD_WEBHOOK_URL')]) { + try { + httpRequest(url: DISCORD_WEBHOOK_URL, httpMode: 'POST', contentType: 'APPLICATION_JSON', requestBody: jsonPayload, quiet: true, timeout: 20, validResponseCodes: '200:204') + echo "Discord notification sent successfully for status: ${statusText}." + } catch (Exception e) { + echo "⚠️ Error sending Discord notification: ${e.getMessage()}" + } + } +} + + +pipeline { + agent any + + environment { + // --- Configuration for the auth application --- + OKD_PROJECT = 'tte-applications-project' + BUILD_NAME = 'tte-auth-app' + DEPLOYMENT = 'tte-auth-app' + + OKD_PROJECT_DEV = 'tte-dev-applications-project' + BUILD_NAME_DEV = 'tte-dev-auth-apps' + DEPLOYMENT_DEV = 'tte-dev-auth-apps' + + // Notification settings + DISCORD_WEBHOOK_CREDENTIAL_ID = 'discord-webhook-auth' + DISCORD_BOT_USERNAME = "Jenkins CI" + DISCORD_AVATAR_URL = "https://www.jenkins.io/images/logos/jenkins/jenkins.png" + FOOTER_TIMEZONE = "Asia/Jakarta" + } + + options { + timestamps() + timeout(time: 1, unit: 'HOURS') + buildDiscarder(logRotator(numToKeepStr: '10')) + } + + stages { + stage('Build App for Development') { + when { branch 'dev' } + steps { + script { + appendLog("🚀 **Building App for Development** (`${env.BUILD_NAME_DEV}`)...") + try { + withCredentials([file(credentialsId: 'kubeconfig-file', variable: 'KUBECONFIG_PATH')]) { + sh """ + export KUBECONFIG="\${KUBECONFIG_PATH}" + oc start-build "${BUILD_NAME_DEV}" --follow --wait=true -n "${OKD_PROJECT_DEV}" + """ + } + appendLog("✅ **Development App Build** completed successfully.") + } catch (Exception e) { + currentBuild.result = 'FAILURE' + appendLog("❌ **Development App Build FAILED**.") + error("OpenShift build for Development failed: ${e.getMessage()}") + } + } + } + } + + stage('Build App for Production') { + when { branch 'main' } + steps { + script { + appendLog("🚀 **Building App for Production** (`${env.BUILD_NAME}`)...") + try { + withCredentials([file(credentialsId: 'kubeconfig-file', variable: 'KUBECONFIG_PATH')]) { + sh """ + export KUBECONFIG="\${KUBECONFIG_PATH}" + oc start-build "${BUILD_NAME}" --follow --wait=true -n "${OKD_PROJECT}" + """ + } + appendLog("✅ **Production App Build** completed successfully.") + } catch (Exception e) { + currentBuild.result = 'FAILURE' + appendLog("❌ **Production App Build FAILED**.") + error("OpenShift build for Production failed: ${e.getMessage()}") + } + } + } + } + + stage('Deploy to Development') { + when { + branch 'dev' + expression { currentBuild.resultIsBetterOrEqualTo('SUCCESS') } + } + steps { + script { + appendLog("🚚 **Deploy to Development** starting for `${env.DEPLOYMENT_DEV}`...") + try { + withCredentials([file(credentialsId: 'kubeconfig-file', variable: 'KUBECONFIG_PATH')]) { + sh """ + export KUBECONFIG="\${KUBECONFIG_PATH}" + oc rollout restart deployment/"${DEPLOYMENT_DEV}" -n "${OKD_PROJECT_DEV}" + oc rollout status deployment/"${DEPLOYMENT_DEV}" --watch -n "${OKD_PROJECT_DEV}" + """ + } + appendLog("✅ **Deploy to Development** succeeded.") + } catch (Exception e) { + currentBuild.result = 'FAILURE' + appendLog("❌ **Deploy to Development FAILED**.") + error("Deployment to Development failed: ${e.getMessage()}") + } + } + } + } + + stage('Deploy to Production') { + when { + branch 'main' + expression { currentBuild.resultIsBetterOrEqualTo('SUCCESS') } + } + steps { + script { + appendLog("🚀 **Deploy to Production** starting for `${env.DEPLOYMENT}`...") + try { + withCredentials([file(credentialsId: 'kubeconfig-file', variable: 'KUBECONFIG_PATH')]) { + sh """ + export KUBECONFIG="\${KUBECONFIG_PATH}" + oc rollout restart deployment/"${DEPLOYMENT}" -n "${OKD_PROJECT}" + oc rollout status deployment/"${DEPLOYMENT}" --watch -n "${OKD_PROJECT}" + """ + } + appendLog("✅ **Deploy to Production** succeeded.") + } catch (Exception e) { + currentBuild.result = 'FAILURE' + appendLog("❌ **Deploy to Production FAILED**.") + error("Deployment to Production failed: ${e.getMessage()}") + } + } + } + } + } + + post { + always { + script { + def finalStatus = currentBuild.currentResult ?: 'UNKNOWN' + + def processedCommitsList = [] + try { + for (changeLogSet in currentBuild.changeSets) { + for (entry in changeLogSet.items) { + processedCommitsList.add([ + commitId: entry.commitId?.take(7) ?: "N/A", + message: (entry.msg?.split('\n')[0] ?: "No commit message").take(80), + author: entry.author?.displayName ?: "Unknown" + ]) + } + } + } catch (e) { echo "Could not get changeset: ${e.getMessage()}" } + + def customFieldsList = [] + if (pipelineLog) { + customFieldsList.add([ + name: "📋 Log Highlights", + value: "```\n${pipelineLog.trim().take(1000)}\n```", + inline: false + ]) + } + + def triggeredBy = "Unknown" + try { triggeredBy = currentBuild.rawBuild.getCauses().collect { it.getShortDescription() }.join(", ") } catch (e) { /* ignore */ } + + sendDiscordNotification([ + status: finalStatus, + jobName: env.JOB_NAME, + buildNumber: env.BUILD_NUMBER, + buildUrl: env.BUILD_URL, + webhookCredentialId: env.DISCORD_WEBHOOK_CREDENTIAL_ID, + branchName: env.BRANCH_NAME ?: "N/A", + nodeName: env.NODE_NAME ?: 'N/A', + processedCommits: processedCommitsList, + triggeredBy: triggeredBy, + username: "${env.DISCORD_BOT_USERNAME} (${env.JOB_NAME.split('/').last()})", + avatarUrl: env.DISCORD_AVATAR_URL, + footerTimeZone: env.FOOTER_TIMEZONE, + buildTimestamp: currentBuild.startTimeInMillis + ]) + } + } + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ada3aca --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# tte-auth-service + +Welcome to tte-auth-service!! + +## running + + ./gradlew joobyRun + +## building + + ./gradlew build + +## docker + + docker build . -t tte-auth-service + docker run -p 8080:8080 -it tte-auth-service diff --git a/bin/default/META-INF/services/io.jooby.MvcFactory b/bin/default/META-INF/services/io.jooby.MvcFactory new file mode 100644 index 0000000..e7dc84f --- /dev/null +++ b/bin/default/META-INF/services/io.jooby.MvcFactory @@ -0,0 +1,9 @@ +id.go.polri.tte.controllers.UserInitialController_ +id.go.polri.tte.controllers.BsreLogController_ +id.go.polri.tte.controllers.UserRoleController_ +id.go.polri.tte.controllers.EsignController_ +id.go.polri.tte.controllers.UserController_ +id.go.polri.tte.controllers.RoleController_ +id.go.polri.tte.controllers.UserSignatureController_ +id.go.polri.tte.controllers.SippController_ + diff --git a/bin/default/id/go/polri/tte/controllers/BsreLogController_.class b/bin/default/id/go/polri/tte/controllers/BsreLogController_.class new file mode 100644 index 0000000..36077ae Binary files /dev/null and b/bin/default/id/go/polri/tte/controllers/BsreLogController_.class differ diff --git a/bin/default/id/go/polri/tte/controllers/EsignController_.class b/bin/default/id/go/polri/tte/controllers/EsignController_.class new file mode 100644 index 0000000..3a2c829 Binary files /dev/null and b/bin/default/id/go/polri/tte/controllers/EsignController_.class differ diff --git a/bin/default/id/go/polri/tte/controllers/RoleController_.class b/bin/default/id/go/polri/tte/controllers/RoleController_.class new file mode 100644 index 0000000..743a075 Binary files /dev/null and b/bin/default/id/go/polri/tte/controllers/RoleController_.class differ diff --git a/bin/default/id/go/polri/tte/controllers/SippController_.class b/bin/default/id/go/polri/tte/controllers/SippController_.class new file mode 100644 index 0000000..477401b Binary files /dev/null and b/bin/default/id/go/polri/tte/controllers/SippController_.class differ diff --git a/bin/default/id/go/polri/tte/controllers/UserController_.class b/bin/default/id/go/polri/tte/controllers/UserController_.class new file mode 100644 index 0000000..bd9c52b Binary files /dev/null and b/bin/default/id/go/polri/tte/controllers/UserController_.class differ diff --git a/bin/default/id/go/polri/tte/controllers/UserInitialController_.class b/bin/default/id/go/polri/tte/controllers/UserInitialController_.class new file mode 100644 index 0000000..aa437e2 Binary files /dev/null and b/bin/default/id/go/polri/tte/controllers/UserInitialController_.class differ diff --git a/bin/default/id/go/polri/tte/controllers/UserRoleController_.class b/bin/default/id/go/polri/tte/controllers/UserRoleController_.class new file mode 100644 index 0000000..8232eac Binary files /dev/null and b/bin/default/id/go/polri/tte/controllers/UserRoleController_.class differ diff --git a/bin/default/id/go/polri/tte/controllers/UserSignatureController_.class b/bin/default/id/go/polri/tte/controllers/UserSignatureController_.class new file mode 100644 index 0000000..bb1e843 Binary files /dev/null and b/bin/default/id/go/polri/tte/controllers/UserSignatureController_.class differ diff --git a/bin/generated-sources/annotations/id/go/polri/tte/controllers/BsreLogController_.java b/bin/generated-sources/annotations/id/go/polri/tte/controllers/BsreLogController_.java new file mode 100644 index 0000000..6d1290f --- /dev/null +++ b/bin/generated-sources/annotations/id/go/polri/tte/controllers/BsreLogController_.java @@ -0,0 +1,81 @@ +package id.go.polri.tte.controllers; + +@io.jooby.annotation.Generated(BsreLogController.class) +public class BsreLogController_ implements io.jooby.MvcExtension, io.jooby.MvcFactory { + protected final java.util.function.Function factory; + + public BsreLogController_() { + this(BsreLogController.class); + } + + public BsreLogController_(Class type) { + this(ctx -> ctx.require(type)); + } + + public BsreLogController_(BsreLogController instance) { + this(ctx -> instance); + } + + public BsreLogController_(java.util.function.Supplier provider) { + this(ctx -> provider.get()); + } + + public BsreLogController_(java.util.function.Function factory) { + this.factory = factory; + } + + public void install(io.jooby.Jooby app) throws Exception { + /** See {@link BsreLogController#findAll(io.jooby.Context) */ + app.get("/api/v2/bsre-log", this::findAll) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.BsreLogController.class, "findAll", id.go.polri.tte.responses.BsreLogListResponse.class, io.jooby.Context.class)); + + /** See {@link BsreLogController#findById(String, io.jooby.Context) */ + app.get("/api/v2/bsre-log/{id}", this::findById) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.BsreLogController.class, "findById", id.go.polri.tte.responses.BsreLogSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link BsreLogController#insert(io.jooby.Context) */ + app.post("/api/v2/bsre-log", this::insert) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.BsreLogController.class, "insert", id.go.polri.tte.responses.BsreLogSingleResponse.class, io.jooby.Context.class)); + + /** See {@link BsreLogController#update(String, io.jooby.Context) */ + app.put("/api/v2/bsre-log/{id}", this::update) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.BsreLogController.class, "update", id.go.polri.tte.responses.BsreLogSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link BsreLogController#delete(String) */ + app.delete("/api/v2/bsre-log/{id}", this::delete) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.BsreLogController.class, "delete", id.go.polri.tte.responses.BasicResponse.class, java.lang.String.class)); + } + + public id.go.polri.tte.responses.BsreLogListResponse findAll(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findAll(ctx); + } + + public id.go.polri.tte.responses.BsreLogSingleResponse findById(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findById(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.BsreLogSingleResponse insert(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.insert(ctx); + } + + public id.go.polri.tte.responses.BsreLogSingleResponse update(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.update(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.BasicResponse delete(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.delete(ctx.path("id").valueOrNull()); + } + + public boolean supports(Class type) { + return type == BsreLogController.class; + } + + public io.jooby.Extension create(java.util.function.Supplier provider) { + return new BsreLogController_(provider); + } +} diff --git a/bin/generated-sources/annotations/id/go/polri/tte/controllers/EsignController_.java b/bin/generated-sources/annotations/id/go/polri/tte/controllers/EsignController_.java new file mode 100644 index 0000000..7c0c737 --- /dev/null +++ b/bin/generated-sources/annotations/id/go/polri/tte/controllers/EsignController_.java @@ -0,0 +1,63 @@ +package id.go.polri.tte.controllers; + +@io.jooby.annotation.Generated(EsignController.class) +public class EsignController_ implements io.jooby.MvcExtension, io.jooby.MvcFactory { + protected final java.util.function.Function factory; + + public EsignController_() { + this(EsignController.class); + } + + public EsignController_(Class type) { + this(ctx -> ctx.require(type)); + } + + public EsignController_(EsignController instance) { + this(ctx -> instance); + } + + public EsignController_(java.util.function.Supplier provider) { + this(ctx -> provider.get()); + } + + public EsignController_(java.util.function.Function factory) { + this.factory = factory; + } + + public void install(io.jooby.Jooby app) throws Exception { + /** See {@link EsignController#status(io.jooby.Context) */ + app.get("/api/v2/auth-service/esign/status", this::status) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.EsignController.class, "status", id.go.polri.tte.responses.StatusResponse.class, io.jooby.Context.class)); + + /** See {@link EsignController#registrasi(io.jooby.Context) */ + app.post("/api/v2/auth-service/esign/registrasi", this::registrasi) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.EsignController.class, "registrasi", id.go.polri.tte.responses.BasicResponse.class, io.jooby.Context.class)); + + /** See {@link EsignController#uploadKeystore(io.jooby.Context) */ + app.post("/api/v2/auth-service/esign/upload-keystore", this::uploadKeystore) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.EsignController.class, "uploadKeystore", id.go.polri.tte.responses.BasicResponse.class, io.jooby.Context.class)); + } + + public id.go.polri.tte.responses.StatusResponse status(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.status(ctx); + } + + public id.go.polri.tte.responses.BasicResponse registrasi(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.registrasi(ctx); + } + + public id.go.polri.tte.responses.BasicResponse uploadKeystore(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.uploadKeystore(ctx); + } + + public boolean supports(Class type) { + return type == EsignController.class; + } + + public io.jooby.Extension create(java.util.function.Supplier provider) { + return new EsignController_(provider); + } +} diff --git a/bin/generated-sources/annotations/id/go/polri/tte/controllers/RoleController_.java b/bin/generated-sources/annotations/id/go/polri/tte/controllers/RoleController_.java new file mode 100644 index 0000000..59a045a --- /dev/null +++ b/bin/generated-sources/annotations/id/go/polri/tte/controllers/RoleController_.java @@ -0,0 +1,81 @@ +package id.go.polri.tte.controllers; + +@io.jooby.annotation.Generated(RoleController.class) +public class RoleController_ implements io.jooby.MvcExtension, io.jooby.MvcFactory { + protected final java.util.function.Function factory; + + public RoleController_() { + this(RoleController.class); + } + + public RoleController_(Class type) { + this(ctx -> ctx.require(type)); + } + + public RoleController_(RoleController instance) { + this(ctx -> instance); + } + + public RoleController_(java.util.function.Supplier provider) { + this(ctx -> provider.get()); + } + + public RoleController_(java.util.function.Function factory) { + this.factory = factory; + } + + public void install(io.jooby.Jooby app) throws Exception { + /** See {@link RoleController#findAll(io.jooby.Context) */ + app.get("/api/v2/role", this::findAll) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.RoleController.class, "findAll", id.go.polri.tte.responses.RoleListResponse.class, io.jooby.Context.class)); + + /** See {@link RoleController#findById(String, io.jooby.Context) */ + app.get("/api/v2/role/{id}", this::findById) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.RoleController.class, "findById", id.go.polri.tte.responses.RoleSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link RoleController#insert(io.jooby.Context) */ + app.post("/api/v2/role", this::insert) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.RoleController.class, "insert", id.go.polri.tte.responses.RoleSingleResponse.class, io.jooby.Context.class)); + + /** See {@link RoleController#update(String, io.jooby.Context) */ + app.put("/api/v2/role/{id}", this::update) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.RoleController.class, "update", id.go.polri.tte.responses.RoleSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link RoleController#delete(String) */ + app.delete("/api/v2/role/{id}", this::delete) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.RoleController.class, "delete", id.go.polri.tte.responses.BasicResponse.class, java.lang.String.class)); + } + + public id.go.polri.tte.responses.RoleListResponse findAll(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findAll(ctx); + } + + public id.go.polri.tte.responses.RoleSingleResponse findById(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findById(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.RoleSingleResponse insert(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.insert(ctx); + } + + public id.go.polri.tte.responses.RoleSingleResponse update(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.update(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.BasicResponse delete(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.delete(ctx.path("id").valueOrNull()); + } + + public boolean supports(Class type) { + return type == RoleController.class; + } + + public io.jooby.Extension create(java.util.function.Supplier provider) { + return new RoleController_(provider); + } +} diff --git a/bin/generated-sources/annotations/id/go/polri/tte/controllers/SippController_.java b/bin/generated-sources/annotations/id/go/polri/tte/controllers/SippController_.java new file mode 100644 index 0000000..ff1e00d --- /dev/null +++ b/bin/generated-sources/annotations/id/go/polri/tte/controllers/SippController_.java @@ -0,0 +1,41 @@ +package id.go.polri.tte.controllers; + +@io.jooby.annotation.Generated(SippController.class) +public class SippController_ implements io.jooby.MvcExtension, io.jooby.MvcFactory { + protected final java.util.function.Function factory; + + public SippController_() { + this(new SippController()); + } + + public SippController_(SippController instance) { + this(ctx -> instance); + } + + public SippController_(java.util.function.Supplier provider) { + this(ctx -> provider.get()); + } + + public SippController_(java.util.function.Function factory) { + this.factory = factory; + } + + public void install(io.jooby.Jooby app) throws Exception { + /** See {@link SippController#find(io.jooby.Context) */ + app.get("/api/v2/sipp", this::find) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.SippController.class, "find", id.go.polri.tte.responses.BasicResponse.class, io.jooby.Context.class)); + } + + public id.go.polri.tte.responses.BasicResponse find(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.find(ctx); + } + + public boolean supports(Class type) { + return type == SippController.class; + } + + public io.jooby.Extension create(java.util.function.Supplier provider) { + return new SippController_(provider); + } +} diff --git a/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserController_.java b/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserController_.java new file mode 100644 index 0000000..eeca373 --- /dev/null +++ b/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserController_.java @@ -0,0 +1,99 @@ +package id.go.polri.tte.controllers; + +@io.jooby.annotation.Generated(UserController.class) +public class UserController_ implements io.jooby.MvcExtension, io.jooby.MvcFactory { + protected final java.util.function.Function factory; + + public UserController_() { + this(UserController.class); + } + + public UserController_(Class type) { + this(ctx -> ctx.require(type)); + } + + public UserController_(UserController instance) { + this(ctx -> instance); + } + + public UserController_(java.util.function.Supplier provider) { + this(ctx -> provider.get()); + } + + public UserController_(java.util.function.Function factory) { + this.factory = factory; + } + + public void install(io.jooby.Jooby app) throws Exception { + /** See {@link UserController#findAll(io.jooby.Context) */ + app.get("/api/v2/user", this::findAll) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserController.class, "findAll", id.go.polri.tte.responses.UserListResponse.class, io.jooby.Context.class)); + + /** See {@link UserController#findById(String, io.jooby.Context) */ + app.get("/api/v2/user/{id}", this::findById) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserController.class, "findById", id.go.polri.tte.responses.UserSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link UserController#insert(io.jooby.Context) */ + app.post("/api/v2/user", this::insert) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserController.class, "insert", id.go.polri.tte.responses.UserSingleResponse.class, io.jooby.Context.class)); + + /** See {@link UserController#update(String, io.jooby.Context) */ + app.put("/api/v2/user/{id}", this::update) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserController.class, "update", id.go.polri.tte.responses.UserSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link UserController#delete(String) */ + app.delete("/api/v2/user/{id}", this::delete) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserController.class, "delete", id.go.polri.tte.responses.BasicResponse.class, java.lang.String.class)); + + /** See {@link UserController#resetPassword(io.jooby.Context) */ + app.post("/api/v2/user/reset-password", this::resetPassword) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserController.class, "resetPassword", id.go.polri.tte.responses.BasicResponse.class, io.jooby.Context.class)); + + /** See {@link UserController#verify(io.jooby.Context) */ + app.post("/api/v2/user/verify", this::verify) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserController.class, "verify", id.go.polri.tte.responses.LoginResponse.class, io.jooby.Context.class)); + } + + public id.go.polri.tte.responses.UserListResponse findAll(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findAll(ctx); + } + + public id.go.polri.tte.responses.UserSingleResponse findById(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findById(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.UserSingleResponse insert(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.insert(ctx); + } + + public id.go.polri.tte.responses.UserSingleResponse update(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.update(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.BasicResponse delete(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.delete(ctx.path("id").valueOrNull()); + } + + public id.go.polri.tte.responses.BasicResponse resetPassword(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.resetPassword(ctx); + } + + public id.go.polri.tte.responses.LoginResponse verify(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.verify(ctx); + } + + public boolean supports(Class type) { + return type == UserController.class; + } + + public io.jooby.Extension create(java.util.function.Supplier provider) { + return new UserController_(provider); + } +} diff --git a/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserInitialController_.java b/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserInitialController_.java new file mode 100644 index 0000000..f1b3ad6 --- /dev/null +++ b/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserInitialController_.java @@ -0,0 +1,81 @@ +package id.go.polri.tte.controllers; + +@io.jooby.annotation.Generated(UserInitialController.class) +public class UserInitialController_ implements io.jooby.MvcExtension, io.jooby.MvcFactory { + protected final java.util.function.Function factory; + + public UserInitialController_() { + this(UserInitialController.class); + } + + public UserInitialController_(Class type) { + this(ctx -> ctx.require(type)); + } + + public UserInitialController_(UserInitialController instance) { + this(ctx -> instance); + } + + public UserInitialController_(java.util.function.Supplier provider) { + this(ctx -> provider.get()); + } + + public UserInitialController_(java.util.function.Function factory) { + this.factory = factory; + } + + public void install(io.jooby.Jooby app) throws Exception { + /** See {@link UserInitialController#findAll(io.jooby.Context) */ + app.get("/api/v2/user-initial", this::findAll) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserInitialController.class, "findAll", id.go.polri.tte.responses.UserInitialListResponse.class, io.jooby.Context.class)); + + /** See {@link UserInitialController#findById(String, io.jooby.Context) */ + app.get("/api/v2/user-initial/{id}", this::findById) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserInitialController.class, "findById", id.go.polri.tte.responses.UserInitialSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link UserInitialController#insert(io.jooby.Context) */ + app.post("/api/v2/user-initial", this::insert) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserInitialController.class, "insert", id.go.polri.tte.responses.UserInitialSingleResponse.class, io.jooby.Context.class)); + + /** See {@link UserInitialController#update(String, io.jooby.Context) */ + app.put("/api/v2/user-initial/{id}", this::update) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserInitialController.class, "update", id.go.polri.tte.responses.UserInitialSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link UserInitialController#delete(String) */ + app.delete("/api/v2/user-initial/{id}", this::delete) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserInitialController.class, "delete", id.go.polri.tte.responses.BasicResponse.class, java.lang.String.class)); + } + + public id.go.polri.tte.responses.UserInitialListResponse findAll(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findAll(ctx); + } + + public id.go.polri.tte.responses.UserInitialSingleResponse findById(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findById(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.UserInitialSingleResponse insert(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.insert(ctx); + } + + public id.go.polri.tte.responses.UserInitialSingleResponse update(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.update(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.BasicResponse delete(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.delete(ctx.path("id").valueOrNull()); + } + + public boolean supports(Class type) { + return type == UserInitialController.class; + } + + public io.jooby.Extension create(java.util.function.Supplier provider) { + return new UserInitialController_(provider); + } +} diff --git a/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserRoleController_.java b/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserRoleController_.java new file mode 100644 index 0000000..427bd1d --- /dev/null +++ b/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserRoleController_.java @@ -0,0 +1,81 @@ +package id.go.polri.tte.controllers; + +@io.jooby.annotation.Generated(UserRoleController.class) +public class UserRoleController_ implements io.jooby.MvcExtension, io.jooby.MvcFactory { + protected final java.util.function.Function factory; + + public UserRoleController_() { + this(UserRoleController.class); + } + + public UserRoleController_(Class type) { + this(ctx -> ctx.require(type)); + } + + public UserRoleController_(UserRoleController instance) { + this(ctx -> instance); + } + + public UserRoleController_(java.util.function.Supplier provider) { + this(ctx -> provider.get()); + } + + public UserRoleController_(java.util.function.Function factory) { + this.factory = factory; + } + + public void install(io.jooby.Jooby app) throws Exception { + /** See {@link UserRoleController#findAll(io.jooby.Context) */ + app.get("/api/v2/user-role", this::findAll) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserRoleController.class, "findAll", id.go.polri.tte.responses.UserRoleListResponse.class, io.jooby.Context.class)); + + /** See {@link UserRoleController#findById(String, io.jooby.Context) */ + app.get("/api/v2/user-role/{id}", this::findById) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserRoleController.class, "findById", id.go.polri.tte.responses.UserRoleSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link UserRoleController#insert(io.jooby.Context) */ + app.post("/api/v2/user-role", this::insert) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserRoleController.class, "insert", id.go.polri.tte.responses.UserRoleSingleResponse.class, io.jooby.Context.class)); + + /** See {@link UserRoleController#update(String, io.jooby.Context) */ + app.put("/api/v2/user-role/{id}", this::update) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserRoleController.class, "update", id.go.polri.tte.responses.UserRoleSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link UserRoleController#delete(String) */ + app.delete("/api/v2/user-role/{id}", this::delete) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserRoleController.class, "delete", id.go.polri.tte.responses.BasicResponse.class, java.lang.String.class)); + } + + public id.go.polri.tte.responses.UserRoleListResponse findAll(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findAll(ctx); + } + + public id.go.polri.tte.responses.UserRoleSingleResponse findById(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findById(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.UserRoleSingleResponse insert(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.insert(ctx); + } + + public id.go.polri.tte.responses.UserRoleSingleResponse update(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.update(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.BasicResponse delete(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.delete(ctx.path("id").valueOrNull()); + } + + public boolean supports(Class type) { + return type == UserRoleController.class; + } + + public io.jooby.Extension create(java.util.function.Supplier provider) { + return new UserRoleController_(provider); + } +} diff --git a/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserSignatureController_.java b/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserSignatureController_.java new file mode 100644 index 0000000..c559067 --- /dev/null +++ b/bin/generated-sources/annotations/id/go/polri/tte/controllers/UserSignatureController_.java @@ -0,0 +1,81 @@ +package id.go.polri.tte.controllers; + +@io.jooby.annotation.Generated(UserSignatureController.class) +public class UserSignatureController_ implements io.jooby.MvcExtension, io.jooby.MvcFactory { + protected final java.util.function.Function factory; + + public UserSignatureController_() { + this(UserSignatureController.class); + } + + public UserSignatureController_(Class type) { + this(ctx -> ctx.require(type)); + } + + public UserSignatureController_(UserSignatureController instance) { + this(ctx -> instance); + } + + public UserSignatureController_(java.util.function.Supplier provider) { + this(ctx -> provider.get()); + } + + public UserSignatureController_(java.util.function.Function factory) { + this.factory = factory; + } + + public void install(io.jooby.Jooby app) throws Exception { + /** See {@link UserSignatureController#findAll(io.jooby.Context) */ + app.get("/api/v2/user-signature", this::findAll) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserSignatureController.class, "findAll", id.go.polri.tte.responses.UserSignatureListResponse.class, io.jooby.Context.class)); + + /** See {@link UserSignatureController#findById(String, io.jooby.Context) */ + app.get("/api/v2/user-signature/{id}", this::findById) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserSignatureController.class, "findById", id.go.polri.tte.responses.UserSignatureSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link UserSignatureController#insert(io.jooby.Context) */ + app.post("/api/v2/user-signature", this::insert) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserSignatureController.class, "insert", id.go.polri.tte.responses.UserSignatureSingleResponse.class, io.jooby.Context.class)); + + /** See {@link UserSignatureController#update(String, io.jooby.Context) */ + app.put("/api/v2/user-signature/{id}", this::update) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserSignatureController.class, "update", id.go.polri.tte.responses.UserSignatureSingleResponse.class, java.lang.String.class, io.jooby.Context.class)); + + /** See {@link UserSignatureController#delete(String) */ + app.delete("/api/v2/user-signature/{id}", this::delete) + .setMvcMethod(new io.jooby.Route.MvcMethod(id.go.polri.tte.controllers.UserSignatureController.class, "delete", id.go.polri.tte.responses.BasicResponse.class, java.lang.String.class)); + } + + public id.go.polri.tte.responses.UserSignatureListResponse findAll(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findAll(ctx); + } + + public id.go.polri.tte.responses.UserSignatureSingleResponse findById(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.findById(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.UserSignatureSingleResponse insert(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.insert(ctx); + } + + public id.go.polri.tte.responses.UserSignatureSingleResponse update(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.update(ctx.path("id").valueOrNull(), ctx); + } + + public id.go.polri.tte.responses.BasicResponse delete(io.jooby.Context ctx) { + var c = this.factory.apply(ctx); + return c.delete(ctx.path("id").valueOrNull()); + } + + public boolean supports(Class type) { + return type == UserSignatureController.class; + } + + public io.jooby.Extension create(java.util.function.Supplier provider) { + return new UserSignatureController_(provider); + } +} diff --git a/bin/main/id/go/polri/tte/app/App.class b/bin/main/id/go/polri/tte/app/App.class new file mode 100644 index 0000000..f2c3416 Binary files /dev/null and b/bin/main/id/go/polri/tte/app/App.class differ diff --git a/bin/main/id/go/polri/tte/controllers/BsreLogController.class b/bin/main/id/go/polri/tte/controllers/BsreLogController.class new file mode 100644 index 0000000..55a629b Binary files /dev/null and b/bin/main/id/go/polri/tte/controllers/BsreLogController.class differ diff --git a/bin/main/id/go/polri/tte/controllers/EsignController.class b/bin/main/id/go/polri/tte/controllers/EsignController.class new file mode 100644 index 0000000..4047447 Binary files /dev/null and b/bin/main/id/go/polri/tte/controllers/EsignController.class differ diff --git a/bin/main/id/go/polri/tte/controllers/RoleController.class b/bin/main/id/go/polri/tte/controllers/RoleController.class new file mode 100644 index 0000000..f0291cd Binary files /dev/null and b/bin/main/id/go/polri/tte/controllers/RoleController.class differ diff --git a/bin/main/id/go/polri/tte/controllers/SippController.class b/bin/main/id/go/polri/tte/controllers/SippController.class new file mode 100644 index 0000000..29c5894 Binary files /dev/null and b/bin/main/id/go/polri/tte/controllers/SippController.class differ diff --git a/bin/main/id/go/polri/tte/controllers/UserController.class b/bin/main/id/go/polri/tte/controllers/UserController.class new file mode 100644 index 0000000..f868e42 Binary files /dev/null and b/bin/main/id/go/polri/tte/controllers/UserController.class differ diff --git a/bin/main/id/go/polri/tte/controllers/UserInitialController.class b/bin/main/id/go/polri/tte/controllers/UserInitialController.class new file mode 100644 index 0000000..36e5c4b Binary files /dev/null and b/bin/main/id/go/polri/tte/controllers/UserInitialController.class differ diff --git a/bin/main/id/go/polri/tte/controllers/UserRoleController.class b/bin/main/id/go/polri/tte/controllers/UserRoleController.class new file mode 100644 index 0000000..4d7fefe Binary files /dev/null and b/bin/main/id/go/polri/tte/controllers/UserRoleController.class differ diff --git a/bin/main/id/go/polri/tte/controllers/UserSignatureController.class b/bin/main/id/go/polri/tte/controllers/UserSignatureController.class new file mode 100644 index 0000000..83ca3c0 Binary files /dev/null and b/bin/main/id/go/polri/tte/controllers/UserSignatureController.class differ diff --git a/bin/main/id/go/polri/tte/dto/UserAddRoleDto.class b/bin/main/id/go/polri/tte/dto/UserAddRoleDto.class new file mode 100644 index 0000000..c62d81b Binary files /dev/null and b/bin/main/id/go/polri/tte/dto/UserAddRoleDto.class differ diff --git a/bin/main/id/go/polri/tte/dto/UserVerifyDto.class b/bin/main/id/go/polri/tte/dto/UserVerifyDto.class new file mode 100644 index 0000000..e720812 Binary files /dev/null and b/bin/main/id/go/polri/tte/dto/UserVerifyDto.class differ diff --git a/bin/main/id/go/polri/tte/models/BsreLog$Mapper.class b/bin/main/id/go/polri/tte/models/BsreLog$Mapper.class new file mode 100644 index 0000000..d8efd77 Binary files /dev/null and b/bin/main/id/go/polri/tte/models/BsreLog$Mapper.class differ diff --git a/bin/main/id/go/polri/tte/models/BsreLog.class b/bin/main/id/go/polri/tte/models/BsreLog.class new file mode 100644 index 0000000..67a2d5e Binary files /dev/null and b/bin/main/id/go/polri/tte/models/BsreLog.class differ diff --git a/bin/main/id/go/polri/tte/models/OneTimePassword$Mapper.class b/bin/main/id/go/polri/tte/models/OneTimePassword$Mapper.class new file mode 100644 index 0000000..dd25760 Binary files /dev/null and b/bin/main/id/go/polri/tte/models/OneTimePassword$Mapper.class differ diff --git a/bin/main/id/go/polri/tte/models/OneTimePassword.class b/bin/main/id/go/polri/tte/models/OneTimePassword.class new file mode 100644 index 0000000..dd0cfe2 Binary files /dev/null and b/bin/main/id/go/polri/tte/models/OneTimePassword.class differ diff --git a/bin/main/id/go/polri/tte/models/Role$Mapper.class b/bin/main/id/go/polri/tte/models/Role$Mapper.class new file mode 100644 index 0000000..10750cc Binary files /dev/null and b/bin/main/id/go/polri/tte/models/Role$Mapper.class differ diff --git a/bin/main/id/go/polri/tte/models/Role.class b/bin/main/id/go/polri/tte/models/Role.class new file mode 100644 index 0000000..84fc28c Binary files /dev/null and b/bin/main/id/go/polri/tte/models/Role.class differ diff --git a/bin/main/id/go/polri/tte/models/User$Mapper.class b/bin/main/id/go/polri/tte/models/User$Mapper.class new file mode 100644 index 0000000..55f187f Binary files /dev/null and b/bin/main/id/go/polri/tte/models/User$Mapper.class differ diff --git a/bin/main/id/go/polri/tte/models/User.class b/bin/main/id/go/polri/tte/models/User.class new file mode 100644 index 0000000..67e7b05 Binary files /dev/null and b/bin/main/id/go/polri/tte/models/User.class differ diff --git a/bin/main/id/go/polri/tte/models/UserInitial$Mapper.class b/bin/main/id/go/polri/tte/models/UserInitial$Mapper.class new file mode 100644 index 0000000..6f615e8 Binary files /dev/null and b/bin/main/id/go/polri/tte/models/UserInitial$Mapper.class differ diff --git a/bin/main/id/go/polri/tte/models/UserInitial.class b/bin/main/id/go/polri/tte/models/UserInitial.class new file mode 100644 index 0000000..c01cd87 Binary files /dev/null and b/bin/main/id/go/polri/tte/models/UserInitial.class differ diff --git a/bin/main/id/go/polri/tte/models/UserRole$Mapper.class b/bin/main/id/go/polri/tte/models/UserRole$Mapper.class new file mode 100644 index 0000000..aa76e3d Binary files /dev/null and b/bin/main/id/go/polri/tte/models/UserRole$Mapper.class differ diff --git a/bin/main/id/go/polri/tte/models/UserRole.class b/bin/main/id/go/polri/tte/models/UserRole.class new file mode 100644 index 0000000..8aacf26 Binary files /dev/null and b/bin/main/id/go/polri/tte/models/UserRole.class differ diff --git a/bin/main/id/go/polri/tte/models/UserSignature$Mapper.class b/bin/main/id/go/polri/tte/models/UserSignature$Mapper.class new file mode 100644 index 0000000..b425939 Binary files /dev/null and b/bin/main/id/go/polri/tte/models/UserSignature$Mapper.class differ diff --git a/bin/main/id/go/polri/tte/models/UserSignature.class b/bin/main/id/go/polri/tte/models/UserSignature.class new file mode 100644 index 0000000..9c2bf4b Binary files /dev/null and b/bin/main/id/go/polri/tte/models/UserSignature.class differ diff --git a/bin/main/id/go/polri/tte/repositories/api/EsignRepository.class b/bin/main/id/go/polri/tte/repositories/api/EsignRepository.class new file mode 100644 index 0000000..eeaaa31 Binary files /dev/null and b/bin/main/id/go/polri/tte/repositories/api/EsignRepository.class differ diff --git a/bin/main/id/go/polri/tte/repositories/jdbi/BsreLogRepository.class b/bin/main/id/go/polri/tte/repositories/jdbi/BsreLogRepository.class new file mode 100644 index 0000000..30d6416 Binary files /dev/null and b/bin/main/id/go/polri/tte/repositories/jdbi/BsreLogRepository.class differ diff --git a/bin/main/id/go/polri/tte/repositories/jdbi/OneTimePasswordRepository.class b/bin/main/id/go/polri/tte/repositories/jdbi/OneTimePasswordRepository.class new file mode 100644 index 0000000..e55dbba Binary files /dev/null and b/bin/main/id/go/polri/tte/repositories/jdbi/OneTimePasswordRepository.class differ diff --git a/bin/main/id/go/polri/tte/repositories/jdbi/RoleRepository.class b/bin/main/id/go/polri/tte/repositories/jdbi/RoleRepository.class new file mode 100644 index 0000000..a6e73e7 Binary files /dev/null and b/bin/main/id/go/polri/tte/repositories/jdbi/RoleRepository.class differ diff --git a/bin/main/id/go/polri/tte/repositories/jdbi/UserInitialRepository.class b/bin/main/id/go/polri/tte/repositories/jdbi/UserInitialRepository.class new file mode 100644 index 0000000..295f484 Binary files /dev/null and b/bin/main/id/go/polri/tte/repositories/jdbi/UserInitialRepository.class differ diff --git a/bin/main/id/go/polri/tte/repositories/jdbi/UserRepository.class b/bin/main/id/go/polri/tte/repositories/jdbi/UserRepository.class new file mode 100644 index 0000000..76a064f Binary files /dev/null and b/bin/main/id/go/polri/tte/repositories/jdbi/UserRepository.class differ diff --git a/bin/main/id/go/polri/tte/repositories/jdbi/UserRoleRepository.class b/bin/main/id/go/polri/tte/repositories/jdbi/UserRoleRepository.class new file mode 100644 index 0000000..a17c85d Binary files /dev/null and b/bin/main/id/go/polri/tte/repositories/jdbi/UserRoleRepository.class differ diff --git a/bin/main/id/go/polri/tte/repositories/jdbi/UserSignatureRepository.class b/bin/main/id/go/polri/tte/repositories/jdbi/UserSignatureRepository.class new file mode 100644 index 0000000..cf67c63 Binary files /dev/null and b/bin/main/id/go/polri/tte/repositories/jdbi/UserSignatureRepository.class differ diff --git a/bin/main/id/go/polri/tte/responses/BasicResponse$BasicResponseBuilder.class b/bin/main/id/go/polri/tte/responses/BasicResponse$BasicResponseBuilder.class new file mode 100644 index 0000000..25e714b Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/BasicResponse$BasicResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/BasicResponse$BasicResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/BasicResponse$BasicResponseBuilderImpl.class new file mode 100644 index 0000000..bf63767 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/BasicResponse$BasicResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/BasicResponse.class b/bin/main/id/go/polri/tte/responses/BasicResponse.class new file mode 100644 index 0000000..fe613e8 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/BasicResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/BsreLogListResponse$BsreLogListResponseBuilder.class b/bin/main/id/go/polri/tte/responses/BsreLogListResponse$BsreLogListResponseBuilder.class new file mode 100644 index 0000000..32165b8 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/BsreLogListResponse$BsreLogListResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/BsreLogListResponse$BsreLogListResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/BsreLogListResponse$BsreLogListResponseBuilderImpl.class new file mode 100644 index 0000000..72d97a2 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/BsreLogListResponse$BsreLogListResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/BsreLogListResponse.class b/bin/main/id/go/polri/tte/responses/BsreLogListResponse.class new file mode 100644 index 0000000..ebf3238 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/BsreLogListResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/BsreLogSingleResponse$BsreLogSingleResponseBuilder.class b/bin/main/id/go/polri/tte/responses/BsreLogSingleResponse$BsreLogSingleResponseBuilder.class new file mode 100644 index 0000000..41891df Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/BsreLogSingleResponse$BsreLogSingleResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/BsreLogSingleResponse$BsreLogSingleResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/BsreLogSingleResponse$BsreLogSingleResponseBuilderImpl.class new file mode 100644 index 0000000..d67068b Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/BsreLogSingleResponse$BsreLogSingleResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/BsreLogSingleResponse.class b/bin/main/id/go/polri/tte/responses/BsreLogSingleResponse.class new file mode 100644 index 0000000..9ab080f Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/BsreLogSingleResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseBuilder.class b/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseBuilder.class new file mode 100644 index 0000000..0e508b1 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseBuilderImpl.class new file mode 100644 index 0000000..9521057 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseData$LoginResponseDataBuilder.class b/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseData$LoginResponseDataBuilder.class new file mode 100644 index 0000000..fb4fca1 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseData$LoginResponseDataBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseData.class b/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseData.class new file mode 100644 index 0000000..5fc7d99 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/LoginResponse$LoginResponseData.class differ diff --git a/bin/main/id/go/polri/tte/responses/LoginResponse.class b/bin/main/id/go/polri/tte/responses/LoginResponse.class new file mode 100644 index 0000000..9af6807 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/LoginResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/OneTimePasswordListResponse$OneTimePasswordListResponseBuilder.class b/bin/main/id/go/polri/tte/responses/OneTimePasswordListResponse$OneTimePasswordListResponseBuilder.class new file mode 100644 index 0000000..64a126f Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/OneTimePasswordListResponse$OneTimePasswordListResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/OneTimePasswordListResponse$OneTimePasswordListResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/OneTimePasswordListResponse$OneTimePasswordListResponseBuilderImpl.class new file mode 100644 index 0000000..d8926f5 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/OneTimePasswordListResponse$OneTimePasswordListResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/OneTimePasswordListResponse.class b/bin/main/id/go/polri/tte/responses/OneTimePasswordListResponse.class new file mode 100644 index 0000000..3687432 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/OneTimePasswordListResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/OneTimePasswordSingleResponse$OneTimePasswordSingleResponseBuilder.class b/bin/main/id/go/polri/tte/responses/OneTimePasswordSingleResponse$OneTimePasswordSingleResponseBuilder.class new file mode 100644 index 0000000..b2f7677 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/OneTimePasswordSingleResponse$OneTimePasswordSingleResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/OneTimePasswordSingleResponse$OneTimePasswordSingleResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/OneTimePasswordSingleResponse$OneTimePasswordSingleResponseBuilderImpl.class new file mode 100644 index 0000000..5809578 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/OneTimePasswordSingleResponse$OneTimePasswordSingleResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/OneTimePasswordSingleResponse.class b/bin/main/id/go/polri/tte/responses/OneTimePasswordSingleResponse.class new file mode 100644 index 0000000..60c0cce Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/OneTimePasswordSingleResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/RoleListResponse$RoleListResponseBuilder.class b/bin/main/id/go/polri/tte/responses/RoleListResponse$RoleListResponseBuilder.class new file mode 100644 index 0000000..a9a9eb8 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/RoleListResponse$RoleListResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/RoleListResponse$RoleListResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/RoleListResponse$RoleListResponseBuilderImpl.class new file mode 100644 index 0000000..b5e63b4 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/RoleListResponse$RoleListResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/RoleListResponse.class b/bin/main/id/go/polri/tte/responses/RoleListResponse.class new file mode 100644 index 0000000..34fc1d5 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/RoleListResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/RoleSingleResponse$RoleSingleResponseBuilder.class b/bin/main/id/go/polri/tte/responses/RoleSingleResponse$RoleSingleResponseBuilder.class new file mode 100644 index 0000000..3eedfea Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/RoleSingleResponse$RoleSingleResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/RoleSingleResponse$RoleSingleResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/RoleSingleResponse$RoleSingleResponseBuilderImpl.class new file mode 100644 index 0000000..f0f1a0c Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/RoleSingleResponse$RoleSingleResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/RoleSingleResponse.class b/bin/main/id/go/polri/tte/responses/RoleSingleResponse.class new file mode 100644 index 0000000..b5f812b Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/RoleSingleResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/StatusResponse$StatusResponseBuilder.class b/bin/main/id/go/polri/tte/responses/StatusResponse$StatusResponseBuilder.class new file mode 100644 index 0000000..8e2f970 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/StatusResponse$StatusResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/StatusResponse.class b/bin/main/id/go/polri/tte/responses/StatusResponse.class new file mode 100644 index 0000000..c26f6a6 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/StatusResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserInitialListResponse$UserInitialListResponseBuilder.class b/bin/main/id/go/polri/tte/responses/UserInitialListResponse$UserInitialListResponseBuilder.class new file mode 100644 index 0000000..a6654aa Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserInitialListResponse$UserInitialListResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserInitialListResponse$UserInitialListResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/UserInitialListResponse$UserInitialListResponseBuilderImpl.class new file mode 100644 index 0000000..12c8d2d Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserInitialListResponse$UserInitialListResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserInitialListResponse.class b/bin/main/id/go/polri/tte/responses/UserInitialListResponse.class new file mode 100644 index 0000000..a863716 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserInitialListResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserInitialSingleResponse$UserInitialSingleResponseBuilder.class b/bin/main/id/go/polri/tte/responses/UserInitialSingleResponse$UserInitialSingleResponseBuilder.class new file mode 100644 index 0000000..96cf6aa Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserInitialSingleResponse$UserInitialSingleResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserInitialSingleResponse$UserInitialSingleResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/UserInitialSingleResponse$UserInitialSingleResponseBuilderImpl.class new file mode 100644 index 0000000..15d1b8c Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserInitialSingleResponse$UserInitialSingleResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserInitialSingleResponse.class b/bin/main/id/go/polri/tte/responses/UserInitialSingleResponse.class new file mode 100644 index 0000000..157be48 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserInitialSingleResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserListResponse$UserListResponseBuilder.class b/bin/main/id/go/polri/tte/responses/UserListResponse$UserListResponseBuilder.class new file mode 100644 index 0000000..9c4ad3a Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserListResponse$UserListResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserListResponse$UserListResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/UserListResponse$UserListResponseBuilderImpl.class new file mode 100644 index 0000000..e2f7069 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserListResponse$UserListResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserListResponse.class b/bin/main/id/go/polri/tte/responses/UserListResponse.class new file mode 100644 index 0000000..8ed479b Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserListResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserRoleListResponse$UserRoleListResponseBuilder.class b/bin/main/id/go/polri/tte/responses/UserRoleListResponse$UserRoleListResponseBuilder.class new file mode 100644 index 0000000..7be0142 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserRoleListResponse$UserRoleListResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserRoleListResponse$UserRoleListResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/UserRoleListResponse$UserRoleListResponseBuilderImpl.class new file mode 100644 index 0000000..e488214 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserRoleListResponse$UserRoleListResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserRoleListResponse.class b/bin/main/id/go/polri/tte/responses/UserRoleListResponse.class new file mode 100644 index 0000000..1ee7ca4 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserRoleListResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserRoleSingleResponse$UserRoleSingleResponseBuilder.class b/bin/main/id/go/polri/tte/responses/UserRoleSingleResponse$UserRoleSingleResponseBuilder.class new file mode 100644 index 0000000..bf61a0e Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserRoleSingleResponse$UserRoleSingleResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserRoleSingleResponse$UserRoleSingleResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/UserRoleSingleResponse$UserRoleSingleResponseBuilderImpl.class new file mode 100644 index 0000000..0e4afec Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserRoleSingleResponse$UserRoleSingleResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserRoleSingleResponse.class b/bin/main/id/go/polri/tte/responses/UserRoleSingleResponse.class new file mode 100644 index 0000000..a081749 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserRoleSingleResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserSignatureListResponse$UserSignatureListResponseBuilder.class b/bin/main/id/go/polri/tte/responses/UserSignatureListResponse$UserSignatureListResponseBuilder.class new file mode 100644 index 0000000..b4b1af7 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserSignatureListResponse$UserSignatureListResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserSignatureListResponse$UserSignatureListResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/UserSignatureListResponse$UserSignatureListResponseBuilderImpl.class new file mode 100644 index 0000000..2b1d256 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserSignatureListResponse$UserSignatureListResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserSignatureListResponse.class b/bin/main/id/go/polri/tte/responses/UserSignatureListResponse.class new file mode 100644 index 0000000..ca26313 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserSignatureListResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserSignatureSingleResponse$UserSignatureSingleResponseBuilder.class b/bin/main/id/go/polri/tte/responses/UserSignatureSingleResponse$UserSignatureSingleResponseBuilder.class new file mode 100644 index 0000000..cfe17f3 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserSignatureSingleResponse$UserSignatureSingleResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserSignatureSingleResponse$UserSignatureSingleResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/UserSignatureSingleResponse$UserSignatureSingleResponseBuilderImpl.class new file mode 100644 index 0000000..8ccf3bd Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserSignatureSingleResponse$UserSignatureSingleResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserSignatureSingleResponse.class b/bin/main/id/go/polri/tte/responses/UserSignatureSingleResponse.class new file mode 100644 index 0000000..1c2d200 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserSignatureSingleResponse.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserSingleResponse$UserSingleResponseBuilder.class b/bin/main/id/go/polri/tte/responses/UserSingleResponse$UserSingleResponseBuilder.class new file mode 100644 index 0000000..93e4b9d Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserSingleResponse$UserSingleResponseBuilder.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserSingleResponse$UserSingleResponseBuilderImpl.class b/bin/main/id/go/polri/tte/responses/UserSingleResponse$UserSingleResponseBuilderImpl.class new file mode 100644 index 0000000..f9bfa4b Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserSingleResponse$UserSingleResponseBuilderImpl.class differ diff --git a/bin/main/id/go/polri/tte/responses/UserSingleResponse.class b/bin/main/id/go/polri/tte/responses/UserSingleResponse.class new file mode 100644 index 0000000..fda1408 Binary files /dev/null and b/bin/main/id/go/polri/tte/responses/UserSingleResponse.class differ diff --git a/bin/test/app/IntegrationTest.class b/bin/test/app/IntegrationTest.class new file mode 100644 index 0000000..506e535 Binary files /dev/null and b/bin/test/app/IntegrationTest.class differ diff --git a/bin/test/app/UnitTest.class b/bin/test/app/UnitTest.class new file mode 100644 index 0000000..abb6817 Binary files /dev/null and b/bin/test/app/UnitTest.class differ diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..966de14 --- /dev/null +++ b/build.gradle @@ -0,0 +1,100 @@ +buildscript { + ext { + joobyVersion = "3.6.1" + } +} + +plugins { + id "application" + id "io.jooby.run" version "${joobyVersion}" + id "io.spring.dependency-management" version "1.1.0" + id "com.google.osdetector" version "1.7.3" + id "com.github.johnrengelman.shadow" version "8.1.1" + id "io.freefair.lombok" version "8.6" +} + +group "id.go.polri" +version "1.0.0" +mainClassName = "id.go.polri.tte.app.App" +sourceCompatibility = 17 + +repositories { + mavenLocal() + mavenCentral() +} + +dependencyManagement { + imports { + mavenBom "io.jooby:jooby-bom:$joobyVersion" + } +} + +dependencies { + annotationProcessor "io.jooby:jooby-apt:$joobyVersion" + implementation "io.jooby:jooby-undertow" + implementation "io.jooby:jooby-logback" + implementation "io.jooby:jooby-hikari" + implementation "io.jooby:jooby-flyway" + implementation "io.jooby:jooby-jdbi" + implementation "io.jooby:jooby-jackson" + implementation "io.jooby:jooby-guice" + implementation "io.jooby:jooby-metrics" + implementation "io.jooby:jooby-pac4j" + implementation "io.jooby:jooby-quartz" + implementation 'org.quartz-scheduler:quartz:2.3.2' + implementation 'com.auth0:java-jwt:4.4.0' + implementation 'org.postgresql:postgresql:42.7.5' + + implementation "at.favre.lib:bcrypt:0.10.2" + implementation 'org.pac4j:pac4j-jwt:6.1.0' + + implementation "org.jdbi:jdbi3-core:3.45.2" + implementation "org.jdbi:jdbi3-sqlobject:3.45.2" + implementation 'antlr:stringtemplate:2.3b6' + + implementation 'org.asynchttpclient:async-http-client:3.0.1' + + implementation 'jakarta.validation:jakarta.validation-api:3.0.2' + implementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final' + + implementation 'at.favre.lib:bcrypt:0.10.2' + implementation 'com.sun.mail:jakarta.mail:2.0.1' + + testImplementation "org.junit.jupiter:junit-jupiter-api:5.10.2" + testImplementation "org.junit.jupiter:junit-jupiter-engine:5.10.2" + testImplementation "io.jooby:jooby-test" + testImplementation "com.squareup.okhttp3:okhttp:4.12.0" + + implementation 'software.amazon.awssdk:s3:2.31.20' + + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' + implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' + implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' + implementation 'com.google.guava:guava:32.1.2-jre' +} + +test { + useJUnitPlatform() +} + +/** Java debug information: */ +tasks.withType(JavaCompile).configureEach { + options.compilerArgs += [ + '-parameters', + '-Ajooby.incremental=true', + '-Ajooby.services=true', + '-Ajooby.debug=false' + ] + options.debug = true +} + +shadowJar { + mergeServiceFiles() +} + +joobyRun { + mainClass = "id.go.polri.tte.app.App" + restartExtensions = ["conf", "properties", "class"] + compileExtensions = ["java"] + port = 8080 +} diff --git a/conf/application.conf b/conf/application.conf new file mode 100644 index 0000000..58e0cb2 --- /dev/null +++ b/conf/application.conf @@ -0,0 +1,29 @@ +# Application configuration file. See https://github.com/typesafehub/config/blob/master/HOCON.md for more details +db.url = "jdbc:postgresql://172.27.168.4:5432/mm_auth" +db.user = postgres +db.password = "postgres" +hikari.maximumPoolSize = 5 +flyway.cleanDisabled = false +flyway.run = migrate +flyway.locations = "filesystem:./sql" +#flyway.baselineOnMigrate = true +jwt.salt = "MMPolri2025Test" +email { + protocol = "smtp" + username = "tte@polri.go.id" + password = "02EaK6&xDh9o" + host = "mail.polri.go.id" + port = 465 + encryption = "ssl" + from_address = "tte@polri.go.id" + from_name = "Mail Management Polri" +} +sipp.baseUrl = "https://api.polri.go.id/sippv1" +sipp.auth = "Basic dHRlcG9scmk6VFQzUDBsciE=" +sipp.cid = "d0332d4d5939ce77-e0ac9eed-81e7e4ee" + +OTP_API_BASE_URL="https://api-otp.polri.go.id/api/v1/whatsapp-public/send/text" +OTP_API_TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IjIiLCJzdWIiOjgsIm90aGVyIjoiYTE2MTA5NDg1ODYwYTEyYTFlMmRjMzZhYTIyYjI0MzE5IiwidHlwZSI6InB1YmxpYy10b2tlbiIsImlzU3VwZXJBZG1pbiI6ZmFsc2UsImlhdCI6MTc0MjA0NzUxOX0.P7h-DBngyTEfbI7JUZ-Z2IGa9aK9CpUaZrvirnkmutLjWXgkQtXkNZwl9pT7MhNFnq_BF2BkA-0M4clVsv440xwCp4aKFrBeYT6P504szuP8xwDGFYJy71oP-_chn8JsxLRhHmJISlRBxSVx9t_G9crPu3DW9AVa-I1lHP-LL36yqX5pNv3XwzBV58lMxeOkREEqiycGtPieDVWm2_K0HYjb2x1fmmz2rJ_13Hcr7HcfH_gV9oiVy3dzHxOb7Ub6GqKfJdurW1VJTMwX-YKRZwLFWSI8Z0Mez04OcrmNgZkT1ndEz_KuNtBOw-KbvNuUz2lRAm8yFyyiKY_Hm-w5Xw" + +jwt.secret="54cd0917f4ed313dbb1ae10e606a3b58b37c8e9ee918cddea2d8617eae64ad811a93be2be0cc53484220edab30d971aea152e800e3d65f4fd504adb58d2c7349" +jwt.expiration=28800 diff --git a/conf/logback.xml b/conf/logback.xml new file mode 100644 index 0000000..bdb1e0b --- /dev/null +++ b/conf/logback.xml @@ -0,0 +1,12 @@ + + + + + [%d{ISO8601}]-[%thread] %-5level %logger - %msg%n + + + + + + + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..f82ff05 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +services: + app: + build: . + ports: + - "8080:8080" + volumes: + - ./logs:/logs + +volumes: + mm-auth-files: \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..4f7956b --- /dev/null +++ b/gradle.properties @@ -0,0 +1,3 @@ +javaVersion=17 + +systemProp.joobyVersion=3.6.1 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..1948b90 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..11fce01 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..83ba0ec --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'tte-auth-service-v2' diff --git a/sql/V10__add_status_account_to_users.sql b/sql/V10__add_status_account_to_users.sql new file mode 100644 index 0000000..17bf93f --- /dev/null +++ b/sql/V10__add_status_account_to_users.sql @@ -0,0 +1 @@ +ALTER TABLE users ADD COLUMN status_account VARCHAR(20) DEFAULT 'active' \ No newline at end of file diff --git a/sql/V11__Update_application_table.sql b/sql/V11__Update_application_table.sql new file mode 100644 index 0000000..fc3bac0 --- /dev/null +++ b/sql/V11__Update_application_table.sql @@ -0,0 +1 @@ +ALTER TABLE users ADD "application_id_threescale" char(36); \ No newline at end of file diff --git a/sql/V12__Alter_application_table.sql b/sql/V12__Alter_application_table.sql new file mode 100644 index 0000000..f49dfde --- /dev/null +++ b/sql/V12__Alter_application_table.sql @@ -0,0 +1,3 @@ +ALTER TABLE users DROP COLUMN "application_id_threescale"; + +ALTER TABLE applications ADD "application_id_threescale" char(36); \ No newline at end of file diff --git a/sql/V13__Alter_application_table_change_type_data.sql b/sql/V13__Alter_application_table_change_type_data.sql new file mode 100644 index 0000000..27d13b9 --- /dev/null +++ b/sql/V13__Alter_application_table_change_type_data.sql @@ -0,0 +1,2 @@ +ALTER TABLE applications +ALTER COLUMN application_id_threescale TYPE varchar(36); \ No newline at end of file diff --git a/sql/V14__Create_Usage_Table.sql b/sql/V14__Create_Usage_Table.sql new file mode 100644 index 0000000..d9acd38 --- /dev/null +++ b/sql/V14__Create_Usage_Table.sql @@ -0,0 +1,13 @@ +ALTER TABLE applications DROP COLUMN "application_id_threescale"; + +CREATE TABLE usage_users ( + id UUID PRIMARY KEY, + user_id UUID NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE usage_organizations ( + id UUID PRIMARY KEY, + "org_name" varchar(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/sql/V15__Alter_table_otp.sql b/sql/V15__Alter_table_otp.sql new file mode 100644 index 0000000..fe41270 --- /dev/null +++ b/sql/V15__Alter_table_otp.sql @@ -0,0 +1 @@ +ALTER TABLE one_time_passwords ADD CONSTRAINT uniq_user_id_active UNIQUE (user_id, used_at); diff --git a/sql/V1__Init.sql b/sql/V1__Init.sql new file mode 100644 index 0000000..9ee41c6 --- /dev/null +++ b/sql/V1__Init.sql @@ -0,0 +1,81 @@ +create table "bsre_logs" ( + "id" char(36) not null primary key, + "nik" varchar(255) not null, + "nrp" varchar(255) not null, + "message" varchar(255) not null, + "created_at" timestamp, + "updated_at" timestamp +); +comment on table "bsre_logs" is 'null'; + +create table "roles" ( + "id" char(36) not null primary key, + "name" varchar(255) not null, + "created_at" timestamp, + "updated_at" timestamp +); +comment on table "roles" is 'null'; + +create table "users" ( + "id" char(36) not null primary key, + "name" varchar(255) not null, + "email" varchar(255) not null, + "phone" varchar(255) not null, + "email_verified_at" timestamp, + "phone_verified_at" timestamp, + "password" varchar(255) not null, + "nrp" varchar(255), + "nik" varchar(255), + "response_status" varchar(255), + "pangkat" varchar(255), + "nama_tanpa_gelar" varchar(255), + "jabatan" varchar(255), + "is_changed" int, + "satuan" text, + "pangkat_lengkap" varchar(255), + "satker" varchar(255), + "nama_aplikasi" varchar(255), + "device_token" varchar(255), + "created_at" timestamp, + "updated_at" timestamp +); +comment on table "users" is 'null'; + +create table "user_initials" ( + "id" char(36) not null primary key, + "user_id" char(36) not null, + "file" varchar(255) not null, + "created_at" timestamp, + "updated_at" timestamp +); +comment on table "user_initials" is 'null'; + +create table "user_roles" ( + "id" char(36) not null primary key, + "user_id" char(36) not null, + "role_id" char(36) not null, + "created_at" timestamp, + "updated_at" timestamp +); +comment on table "user_roles" is 'null'; + +create table "user_signatures" ( + "id" char(36) not null primary key, + "user_id" char(36) not null, + "file" varchar(255) not null, + "created_at" timestamp, + "updated_at" timestamp +); +comment on table "user_signatures" is 'null'; + +create table "one_time_passwords" ( + "id" char(36) not null primary key, + "user_id" char(36) not null, + "code" varchar(255) not null, + "expired_at" timestamp, + "used_at" timestamp, + "created_at" timestamp, + "updated_at" timestamp +); +comment on table "one_time_passwords" is 'null'; + diff --git a/sql/V2__Alter_table_users.sql b/sql/V2__Alter_table_users.sql new file mode 100644 index 0000000..6fdc47f --- /dev/null +++ b/sql/V2__Alter_table_users.sql @@ -0,0 +1 @@ +alter table users add satker varchar(255); \ No newline at end of file diff --git a/sql/V3__Update_users_table.sql b/sql/V3__Update_users_table.sql new file mode 100644 index 0000000..a877948 --- /dev/null +++ b/sql/V3__Update_users_table.sql @@ -0,0 +1,2 @@ +ALTER TABLE users ADD nama_aplikasi VARCHAR(255); +ALTER TABLE users RENAME COLUMN "isChanged" TO is_changed; \ No newline at end of file diff --git a/sql/V4__Add_column_nama_pendek_dengan_gelar.sql b/sql/V4__Add_column_nama_pendek_dengan_gelar.sql new file mode 100644 index 0000000..5f62c1c --- /dev/null +++ b/sql/V4__Add_column_nama_pendek_dengan_gelar.sql @@ -0,0 +1 @@ +ALTER TABLE users ADD nama_pendek_dengan_gelar VARCHAR(255); \ No newline at end of file diff --git a/sql/V5__Create_org_table.sql b/sql/V5__Create_org_table.sql new file mode 100644 index 0000000..0292b34 --- /dev/null +++ b/sql/V5__Create_org_table.sql @@ -0,0 +1,16 @@ +create table "organization" ( + "id" char(36) not null primary key, + "name" varchar(255) not null, + "created_at" timestamp, + "updated_at" timestamp +); +comment on table "organization" is 'null'; + +create table "applications" ( + "id" char(36) not null primary key, + "organization_id" char(36), + "name" varchar(255) not null, + "created_at" timestamp, + "updated_at" timestamp +); +comment on table "applications" is 'null'; \ No newline at end of file diff --git a/sql/V6__Create_org_mapping_table.sql b/sql/V6__Create_org_mapping_table.sql new file mode 100644 index 0000000..7587285 --- /dev/null +++ b/sql/V6__Create_org_mapping_table.sql @@ -0,0 +1,13 @@ +create table "organization_mappings" ( + "id" char(36) not null primary key, + "organization_id" char(36) not null, + "gateway_id" bigint not null +); +comment on table "organization_mappings" is 'null'; + +create table "application_mappings" ( + "id" char(36) not null primary key, + "application_id" char(36) not null, + "gateway_id" bigint not null +); +comment on table "application_mappings" is 'null'; \ No newline at end of file diff --git a/sql/V7__Create_analytics_table.sql b/sql/V7__Create_analytics_table.sql new file mode 100644 index 0000000..c6167f6 --- /dev/null +++ b/sql/V7__Create_analytics_table.sql @@ -0,0 +1,9 @@ +create table "application_analytics" +( + "id" char(36) not null primary key, + "application_id" char(36) not null, + "gateway_id" bigint not null, + "hit_date" date not null, + "value" integer not null +); +comment on table "application_analytics" is 'null'; \ No newline at end of file diff --git a/sql/V8__Create_user_logs_table.sql b/sql/V8__Create_user_logs_table.sql new file mode 100644 index 0000000..a56605f --- /dev/null +++ b/sql/V8__Create_user_logs_table.sql @@ -0,0 +1,7 @@ +create table "user_logs" +( + "id" char(36) not null primary key, + "user_id" char(36) not null, + "last_signin" timestamp not null +); +comment on table "user_logs" is 'null'; \ No newline at end of file diff --git a/sql/V9__Alter_table_user_logs.sql b/sql/V9__Alter_table_user_logs.sql new file mode 100644 index 0000000..4e90417 --- /dev/null +++ b/sql/V9__Alter_table_user_logs.sql @@ -0,0 +1,17 @@ +-- 1. Buat tabel baru dengan urutan kolom yang diinginkan +CREATE TABLE user_logs_new ( + id UUID PRIMARY KEY, + user_id UUID NOT NULL, + last_signin timestamp NOT NULL +); + +-- 2. Salin data dari tabel lama (yang sudah dikonversi ke UUID) +INSERT INTO user_logs_new (id, user_id, last_signin) +SELECT id::UUID, user_id::UUID, last_signin +FROM user_logs; + +-- 3. Hapus tabel lama +DROP TABLE user_logs; + +-- 4. Rename tabel baru ke nama asli +ALTER TABLE user_logs_new RENAME TO user_logs; \ No newline at end of file diff --git a/src/main/java/id/go/polri/tte/app/App.java b/src/main/java/id/go/polri/tte/app/App.java new file mode 100644 index 0000000..0dc5488 --- /dev/null +++ b/src/main/java/id/go/polri/tte/app/App.java @@ -0,0 +1,92 @@ +package id.go.polri.tte.app; + +import id.go.polri.tte.controllers.*; +import id.go.polri.tte.jobs.StatusBsreJob; +import id.go.polri.tte.module.*; +import id.go.polri.tte.repositories.jdbi.*; +import io.jooby.Jooby; +import io.jooby.Router; +import io.jooby.flyway.FlywayModule; +import io.jooby.guice.GuiceModule; +import io.jooby.handler.CorsHandler; +import io.jooby.hikari.HikariModule; +import io.jooby.jackson.JacksonModule; +import io.jooby.jdbi.JdbiModule; +import io.jooby.jdbi.TransactionalRequest; +import io.jooby.quartz.QuartzModule; +import io.jooby.undertow.UndertowServer; + +public class App extends Jooby { + + { + + error((ctx, cause, statusCode) -> { + Router router = ctx.getRouter(); + if (statusCode.value() == 404) { + router.getLog().error("found `{}` error", statusCode.value()); + } else { + router.getLog().error("found `{}` error", statusCode.value(), cause); + } + + ctx.setResponseCode(statusCode); + ctx.send("found `" + statusCode.value() + "` error"); + }); + use(new CorsHandler()); + use(new TransactionalRequest()); + + install(new UndertowServer()); + + install(new GuiceModule()); + install(new EsignModule()); + install(new EmailModule()); + install(new SippModule()); + install(new NotificationModule()); + install(new CephModule()); + install(new JwtModule()); + install(new JacksonModule()); + install(new HikariModule()); + install(new JdbiModule().sqlObjects(BsreLogRepository.class, + RoleRepository.class, + UserInitialRepository.class, + UserRoleRepository.class, + UserRepository.class, + UserSignatureRepository.class, + OneTimePasswordRepository.class, + ApplicationRepository.class, + OrganizationRepository.class, + ApplicationMappingRepository.class, + OrganizationMappingRepository.class, + ApplicationAnalyticsRepository.class, + UserLogsRepository.class, + UsageOrganizationRepository.class, + UsageUserRepository.class)); + install(new StatusBsreModule()); + + install(new FlywayModule()); + install(new ThreeScaleModule()); + install(new QuartzModule(StatusBsreJob.class)); + + mvc(EsignController.class); + mvc(BsreLogController.class); + mvc(RoleController.class); + mvc(UserInitialController.class); + mvc(UserRoleController.class); + mvc(UserController.class); + mvc(LoginController.class); + mvc(UserSignatureController.class); + mvc(SippController.class); + mvc(ApplicationController.class); + mvc(OrganizationController.class); + mvc(ApplicationMappingController.class); + mvc(OrganizationMappingController.class); + mvc(GatewayWebhookController.class); + mvc(ApplicationAnalyticsController.class); + + + } + + public static void main(final String[] args) { + runApp(args, App::new); + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/ApplicationAnalyticsController.java b/src/main/java/id/go/polri/tte/controllers/ApplicationAnalyticsController.java new file mode 100644 index 0000000..8556ed8 --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/ApplicationAnalyticsController.java @@ -0,0 +1,120 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.models.ApplicationAnalytics; +import id.go.polri.tte.repositories.jdbi.ApplicationAnalyticsRepository; +import id.go.polri.tte.responses.ApplicationAnalyticsListResponse; +import id.go.polri.tte.responses.ApplicationAnalyticsSingleResponse; +import id.go.polri.tte.responses.BasicResponse; +import io.jooby.Context; +import io.jooby.annotation.*; +import jakarta.inject.Inject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Path("/api/v2/auth-service/application-analytics") +public class ApplicationAnalyticsController { + private final ApplicationAnalyticsRepository repository; + + @Inject + public ApplicationAnalyticsController(ApplicationAnalyticsRepository repository) { + this.repository = repository; + } + + @GET("") + public ApplicationAnalyticsListResponse findAll(Context context) { + if (context.queryMap().containsKey("limit") && context.queryMap().containsKey("offset") + && context.queryMap().containsKey("orderBy") && context.queryMap().containsKey("direction")) { + List andConditions = new ArrayList<>(); + List orConditions = new ArrayList<>(); + int limit = context.query("limit").intValue(); + int offset = context.query("offset").intValue(); + for (Map.Entry entry : context.queryMap().entrySet()) { + if (!entry.getKey().equals("limit") && !entry.getKey().equals("offset") + && !entry.getKey().equals("orderBy") && !entry.getKey().equals("direction")) { + if (entry.getKey().endsWith("_id") || entry.getKey().equals("username")) { + andConditions.add(entry.getKey() + " = '" + entry.getValue() + "'"); + } else { + orConditions.add(entry.getKey() + " like '%" + entry.getValue() + "%'"); + } + } + } + if (!andConditions.isEmpty() || !orConditions.isEmpty()) { + List conditions = new ArrayList<>(); + if (!andConditions.isEmpty()) { + String andCondition = String.join(" and ", andConditions); + conditions.add(andCondition); + } + if (!orConditions.isEmpty()) { + String orCondition = "(" + String.join(" or ", orConditions) + ")"; + conditions.add(orCondition); + } + String condition = String.join(" and ", conditions); + List list = repository.findByCustomWhere(condition, limit, offset, context.query("orderBy").value(), context.query("direction").value()); + int recordsTotal = repository.count(); + int recordsFiltered = repository.countByCustomWhere(condition); + return ApplicationAnalyticsListResponse.builder().code(0).message("Success").data(list) + .recordsFiltered(recordsFiltered).recordsTotal(recordsTotal).build(); + } + } + + if (context.queryMap().containsKey("applicationId")) { + String applicationId = context.query("applicationId").value(); + List list = repository.findByApplicationId(applicationId); + return ApplicationAnalyticsListResponse.builder().code(0).message("Success").data(list).build(); + } + + if (context.queryMap().containsKey("gatewayId")) { + String gatewayId = context.query("gatewayId").value(); + List list = repository.findByGatewayId(gatewayId); + return ApplicationAnalyticsListResponse.builder().code(0).message("Success").data(list).build(); + } + + List list = repository.findAll(); + return ApplicationAnalyticsListResponse.builder().code(0).message("Success").data(list).build(); + } + + @GET("/{id}") + public ApplicationAnalyticsSingleResponse findById(@PathParam String id, Context context) { + ApplicationAnalytics item = repository.findById(id); + if (item == null) { + return ApplicationAnalyticsSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + return ApplicationAnalyticsSingleResponse.builder().code(0).message("Success").data(item).build(); + } + + @POST("") + public ApplicationAnalyticsSingleResponse insert(Context context) { + ApplicationAnalytics item = context.body(ApplicationAnalytics.class); + boolean result = repository.insert(item); + if (result) { + return ApplicationAnalyticsSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return ApplicationAnalyticsSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @PUT("/{id}") + public ApplicationAnalyticsSingleResponse update(@PathParam String id, Context context) { + ApplicationAnalytics item = context.body(ApplicationAnalytics.class); + boolean result = repository.update(item, id); + + if (result) { + return ApplicationAnalyticsSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return ApplicationAnalyticsSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @DELETE("/{id}") + public BasicResponse delete(@PathParam String id) { + boolean result = repository.delete(id); + if (result) { + return BasicResponse.builder().code(0).message("Success").build(); + } else { + return BasicResponse.builder().code(1).message("Failed").build(); + } + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/ApplicationController.java b/src/main/java/id/go/polri/tte/controllers/ApplicationController.java new file mode 100644 index 0000000..f596e0a --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/ApplicationController.java @@ -0,0 +1,115 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.models.Application; +import id.go.polri.tte.repositories.jdbi.ApplicationRepository; +import id.go.polri.tte.responses.ApplicationListResponse; +import id.go.polri.tte.responses.ApplicationSingleResponse; +import id.go.polri.tte.responses.BasicResponse; +import io.jooby.Context; +import io.jooby.annotation.*; +import jakarta.inject.Inject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Path("/api/v2/auth-service/applications") +public class ApplicationController { + private final ApplicationRepository repository; + + @Inject + public ApplicationController(ApplicationRepository repository) { + this.repository = repository; + } + + @GET("") + public ApplicationListResponse findAll(Context context) { + if (context.queryMap().containsKey("limit") && context.queryMap().containsKey("offset") + && context.queryMap().containsKey("orderBy") && context.queryMap().containsKey("direction")) { + List andConditions = new ArrayList<>(); + List orConditions = new ArrayList<>(); + int limit = context.query("limit").intValue(); + int offset = context.query("offset").intValue(); + for (Map.Entry entry : context.queryMap().entrySet()) { + if (!entry.getKey().equals("limit") && !entry.getKey().equals("offset") + && !entry.getKey().equals("orderBy") && !entry.getKey().equals("direction")) { + if (entry.getKey().endsWith("_id") || entry.getKey().equals("username")) { + andConditions.add(entry.getKey() + " = '" + entry.getValue() + "'"); + } else { + orConditions.add(entry.getKey() + " like '%" + entry.getValue() + "%'"); + } + } + } + if (!andConditions.isEmpty() || !orConditions.isEmpty()) { + List conditions = new ArrayList<>(); + if (!andConditions.isEmpty()) { + String andCondition = String.join(" and ", andConditions); + conditions.add(andCondition); + } + if (!orConditions.isEmpty()) { + String orCondition = "(" + String.join(" or ", orConditions) + ")"; + conditions.add(orCondition); + } + String condition = String.join(" and ", conditions); + List list = repository.findByCustomWhere(condition, limit, offset, context.query("orderBy").value(), context.query("direction").value()); + int recordsTotal = repository.count(); + int recordsFiltered = repository.countByCustomWhere(condition); + return ApplicationListResponse.builder().code(0).message("Success").data(list) + .recordsFiltered(recordsFiltered).recordsTotal(recordsTotal).build(); + } + } + + if (context.queryMap().containsKey("organizationId")) { + String organizationId = context.query("organizationId").value(); + List list = repository.findByOrganizationId(organizationId); + return ApplicationListResponse.builder().code(0).message("Success").data(list).build(); + } + + List list = repository.findAll(); + int recordsTotal = repository.count(); + return ApplicationListResponse.builder().code(0).message("Success").data(list).recordsTotal(recordsTotal).build(); + } + + @GET("/{id}") + public ApplicationSingleResponse findById(@PathParam String id, Context context) { + Application item = repository.findById(id); + if (item == null) { + return ApplicationSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + return ApplicationSingleResponse.builder().code(0).message("Success").data(item).build(); + } + + @POST("") + public ApplicationSingleResponse insert(Context context) { + Application item = context.body(Application.class); + boolean result = repository.insert(item); + if (result) { + return ApplicationSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return ApplicationSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @PUT("/{id}") + public ApplicationSingleResponse update(@PathParam String id, Context context) { + Application item = context.body(Application.class); + boolean result = repository.update(item, id); + + if (result) { + return ApplicationSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return ApplicationSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @DELETE("/{id}") + public BasicResponse delete(@PathParam String id) { + boolean result = repository.delete(id); + if (result) { + return BasicResponse.builder().code(0).message("Success").build(); + } else { + return BasicResponse.builder().code(1).message("Failed").build(); + } + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/ApplicationMappingController.java b/src/main/java/id/go/polri/tte/controllers/ApplicationMappingController.java new file mode 100644 index 0000000..7b1f194 --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/ApplicationMappingController.java @@ -0,0 +1,120 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.models.ApplicationMapping; +import id.go.polri.tte.repositories.jdbi.ApplicationMappingRepository; +import id.go.polri.tte.responses.ApplicationMappingListResponse; +import id.go.polri.tte.responses.ApplicationMappingSingleResponse; +import id.go.polri.tte.responses.BasicResponse; +import io.jooby.Context; +import io.jooby.annotation.*; +import jakarta.inject.Inject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Path("/api/v2/auth-service/application-mappings") +public class ApplicationMappingController { + private final ApplicationMappingRepository repository; + + @Inject + public ApplicationMappingController(ApplicationMappingRepository repository) { + this.repository = repository; + } + + @GET("") + public ApplicationMappingListResponse findAll(Context context) { + if (context.queryMap().containsKey("limit") && context.queryMap().containsKey("offset") + && context.queryMap().containsKey("orderBy") && context.queryMap().containsKey("direction")) { + List andConditions = new ArrayList<>(); + List orConditions = new ArrayList<>(); + int limit = context.query("limit").intValue(); + int offset = context.query("offset").intValue(); + for (Map.Entry entry : context.queryMap().entrySet()) { + if (!entry.getKey().equals("limit") && !entry.getKey().equals("offset") + && !entry.getKey().equals("orderBy") && !entry.getKey().equals("direction")) { + if (entry.getKey().endsWith("_id") || entry.getKey().equals("username")) { + andConditions.add(entry.getKey() + " = '" + entry.getValue() + "'"); + } else { + orConditions.add(entry.getKey() + " like '%" + entry.getValue() + "%'"); + } + } + } + if (!andConditions.isEmpty() || !orConditions.isEmpty()) { + List conditions = new ArrayList<>(); + if (!andConditions.isEmpty()) { + String andCondition = String.join(" and ", andConditions); + conditions.add(andCondition); + } + if (!orConditions.isEmpty()) { + String orCondition = "(" + String.join(" or ", orConditions) + ")"; + conditions.add(orCondition); + } + String condition = String.join(" and ", conditions); + List list = repository.findByCustomWhere(condition, limit, offset, context.query("orderBy").value(), context.query("direction").value()); + int recordsTotal = repository.count(); + int recordsFiltered = repository.countByCustomWhere(condition); + return ApplicationMappingListResponse.builder().code(0).message("Success").data(list) + .recordsFiltered(recordsFiltered).recordsTotal(recordsTotal).build(); + } + } + + if (context.queryMap().containsKey("applicationId")) { + String applicationId = context.query("applicationId").value(); + List list = repository.findByApplicationId(applicationId); + return ApplicationMappingListResponse.builder().code(0).message("Success").data(list).build(); + } + + if (context.queryMap().containsKey("gatewayId")) { + String gatewayId = context.query("gatewayId").value(); + List list = repository.findByGatewayId(gatewayId); + return ApplicationMappingListResponse.builder().code(0).message("Success").data(list).build(); + } + + List list = repository.findAll(); + return ApplicationMappingListResponse.builder().code(0).message("Success").data(list).build(); + } + + @GET("/{id}") + public ApplicationMappingSingleResponse findById(@PathParam String id, Context context) { + ApplicationMapping item = repository.findById(id); + if (item == null) { + return ApplicationMappingSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + return ApplicationMappingSingleResponse.builder().code(0).message("Success").data(item).build(); + } + + @POST("") + public ApplicationMappingSingleResponse insert(Context context) { + ApplicationMapping item = context.body(ApplicationMapping.class); + boolean result = repository.insert(item); + if (result) { + return ApplicationMappingSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return ApplicationMappingSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @PUT("/{id}") + public ApplicationMappingSingleResponse update(@PathParam String id, Context context) { + ApplicationMapping item = context.body(ApplicationMapping.class); + boolean result = repository.update(item, id); + + if (result) { + return ApplicationMappingSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return ApplicationMappingSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @DELETE("/{id}") + public BasicResponse delete(@PathParam String id) { + boolean result = repository.delete(id); + if (result) { + return BasicResponse.builder().code(0).message("Success").build(); + } else { + return BasicResponse.builder().code(1).message("Failed").build(); + } + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/BsreLogController.java b/src/main/java/id/go/polri/tte/controllers/BsreLogController.java new file mode 100644 index 0000000..e4a14c5 --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/BsreLogController.java @@ -0,0 +1,122 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.models.BsreLog; +import id.go.polri.tte.repositories.jdbi.BsreLogRepository; +import id.go.polri.tte.responses.BsreLogListResponse; +import id.go.polri.tte.responses.BsreLogSingleResponse; +import id.go.polri.tte.responses.BasicResponse; +import io.jooby.Context; +import io.jooby.annotation.*; +import jakarta.inject.Inject; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@Path("/api/v2/auth-service/bsre-log") +public class BsreLogController { + private final BsreLogRepository repository; + + @Inject + public BsreLogController(BsreLogRepository repository) { + this.repository = repository; + } + + @GET("") + public BsreLogListResponse findAll(Context context) { + if (context.queryMap().containsKey("limit") && context.queryMap().containsKey("offset") + && context.queryMap().containsKey("orderBy") && context.queryMap().containsKey("direction")) { + List andConditions = new ArrayList<>(); + List orConditions = new ArrayList<>(); + int limit = context.query("limit").intValue(); + int offset = context.query("offset").intValue(); + for (Map.Entry entry : context.queryMap().entrySet()) { + if (!entry.getKey().equals("limit") && !entry.getKey().equals("offset") + && !entry.getKey().equals("orderBy") && !entry.getKey().equals("direction")) { + if (entry.getKey().endsWith("_id") || entry.getKey().equals("username")) { + andConditions.add(entry.getKey() + " = '" + entry.getValue() + "'"); + } else { + orConditions.add(entry.getKey() + " like '%" + entry.getValue() + "%'"); + } + } + } + if (!andConditions.isEmpty() || !orConditions.isEmpty()) { + List conditions = new ArrayList<>(); + if (!andConditions.isEmpty()) { + String andCondition = String.join(" and ", andConditions); + conditions.add(andCondition); + } + if (!orConditions.isEmpty()) { + String orCondition = "(" + String.join(" or ", orConditions) + ")"; + conditions.add(orCondition); + } + String condition = String.join(" and ", conditions); + List list = repository.findByCustomWhere(condition, limit, offset, context.query("orderBy").value(), context.query("direction").value()); + int recordsTotal = repository.count(); + int recordsFiltered = repository.countByCustomWhere(condition); + return BsreLogListResponse.builder().code(0).message("Success").data(list) + .recordsFiltered(recordsFiltered).recordsTotal(recordsTotal).build(); + } + } + + List list = repository.findAll(); + int recordsTotal = repository.count(); + return BsreLogListResponse.builder().code(0).message("Success").data(list).recordsTotal(recordsTotal).build(); + } + + @GET("/{id}") + public BsreLogSingleResponse findById(@PathParam String id, Context context) { + BsreLog item = repository.findById(UUID.fromString(id)); + if (item == null) { + return BsreLogSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + return BsreLogSingleResponse.builder().code(0).message("Success").data(item).build(); + } + + @POST("") + public BsreLogSingleResponse insert(Context context) { + BsreLog item = context.body(BsreLog.class); + + item.setId(UUID.randomUUID()); + item.setCreatedAt(LocalDateTime.now()); + item.setUpdatedAt(LocalDateTime.now()); + + boolean result = repository.insert(item); + if (result) { + return BsreLogSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return BsreLogSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @PUT("/{id}") + public BsreLogSingleResponse update(@PathParam UUID id, Context context) { + BsreLog item = context.body(BsreLog.class); + BsreLog oldData = repository.findById(id); + + item.setId(oldData.getId()); + item.setCreatedAt(oldData.getCreatedAt()); + item.setUpdatedAt(LocalDateTime.now()); + + boolean result = repository.update(item, UUID.fromString(String.valueOf(id))); + + if (result) { + return BsreLogSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return BsreLogSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @DELETE("/{id}") + public BasicResponse delete(@PathParam String id) { + boolean result = repository.delete(UUID.fromString(id)); + if (result) { + return BasicResponse.builder().code(0).message("Success").build(); + } else { + return BasicResponse.builder().code(1).message("Failed").build(); + } + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/EsignController.java b/src/main/java/id/go/polri/tte/controllers/EsignController.java new file mode 100644 index 0000000..6cb3afd --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/EsignController.java @@ -0,0 +1,113 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.dto.RegistrasiEsignDto; +import id.go.polri.tte.models.User; +import id.go.polri.tte.repositories.api.EsignRepository; +import id.go.polri.tte.repositories.jdbi.UserRepository; +import id.go.polri.tte.responses.BasicResponse; +import id.go.polri.tte.responses.StatusResponse; +import id.go.polri.tte.responses.UserSingleResponse; +import id.go.polri.tte.services.StatusBsreService; +import io.jooby.Context; +import io.jooby.FileUpload; +import io.jooby.annotation.GET; +import io.jooby.annotation.POST; +import io.jooby.annotation.Path; +import jakarta.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@Slf4j +@Path("/api/v2/auth-service/esign") +public class EsignController { + private final UserRepository repository; + private final EsignRepository esignRepository; + private static final Logger logger = LoggerFactory.getLogger(StatusBsreService.class); + @Inject + public EsignController(UserRepository repository, EsignRepository esignRepository) { + this.repository = repository; + this.esignRepository = esignRepository; + + } + + @GET("/status") + public StatusResponse status(Context context) { + String nik = context.query("nik").value(); + User user = repository.findLatestByNik(nik); + if (user == null) { + String message = String.format("User dengan nik '%s' tidak ditemukan.", nik); + return StatusResponse.builder().status("error").statusCode(404).message(message).build(); + } + if (user.getResponseStatus() == null || user.getResponseStatus().isEmpty()) { + String message = String.format("User dengan nik '%s' belum melakukan pengkinian data.", nik); + return StatusResponse.builder().status("error").statusCode(404).message(message).build(); + } + return StatusResponse.builder().status("success").statusCode(200).message(user.getResponseStatus()).build(); + } + + @POST("/registrasi") + public UserSingleResponse registrasi(Context context) { + try { + RegistrasiEsignDto dto = new RegistrasiEsignDto(); + dto.setNama(context.form("nama").value()); + dto.setEmail(context.form("email").value()); + dto.setSuratRekomendasi(context.file("surat_rekomendasi")); + + // Kirim ke API eSign + String response = esignRepository.registrasi(dto); + + if (response.contains("\"error\"")) { + String errorMessage = response.replaceAll(".*\"error\"\\s*:\\s*\"([^\"]+)\".*", "$1"); + return UserSingleResponse.builder().code(1).message(errorMessage).data(null).build(); + } + Map mydata = new HashMap<>(); + mydata.put("nama", dto.getNama()); + mydata.put("email", dto.getEmail()); + mydata.put("suratRekomendasi", dto.getSuratRekomendasi().getFileName()); + + return UserSingleResponse.builder().code(0).message("Success").data(mydata).build(); + } catch (Exception e) { + return UserSingleResponse.builder().code(1).message("Failed: " + e.getMessage()).data(null).build(); + } + + } + + @POST("/upload-keystore") + public BasicResponse uploadKeystore(Context context) { + try { + String nik = context.form("nik").value(); + String passphrase = context.form("passphrase").value(); + FileUpload keystoreFile = context.file("keystore"); + + if (nik == null || passphrase == null || keystoreFile == null) { + return BasicResponse.builder().code(400).message("nik, passphrase, dan file keystore wajib diisi.").build(); + } + + String response = esignRepository.uploadKeystore(keystoreFile, passphrase, nik); + + System.out.println("Response API: " + response); + if (response.contains("\"error\"")) { + String errorMessage = response.replaceAll(".*\"message\"\\s*:\\s*\"([^\"]+)\".*", "$1"); + return BasicResponse.builder() + .code(400) + .message(errorMessage) + .build(); + } + + return BasicResponse.builder() + .code(200) + .message("Upload keystore berhasil.") + .build(); + + } catch (Exception e) { + return BasicResponse.builder().code(500).message("Terjadi kesalahan: " + e.getMessage()).build(); + } + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/GatewayWebhookController.java b/src/main/java/id/go/polri/tte/controllers/GatewayWebhookController.java new file mode 100644 index 0000000..524fbe5 --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/GatewayWebhookController.java @@ -0,0 +1,291 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.models.Application; +import id.go.polri.tte.models.ApplicationMapping; +import id.go.polri.tte.models.Organization; +import id.go.polri.tte.models.OrganizationMapping; +import id.go.polri.tte.repositories.jdbi.ApplicationMappingRepository; +import id.go.polri.tte.repositories.jdbi.ApplicationRepository; +import id.go.polri.tte.repositories.jdbi.OrganizationMappingRepository; +import id.go.polri.tte.repositories.jdbi.OrganizationRepository; +import id.go.polri.tte.responses.StatusResponse; +import io.jooby.Context; +import io.jooby.annotation.POST; +import io.jooby.annotation.Path; +import jakarta.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.io.StringReader; +import java.time.LocalDateTime; +import java.util.List; +import java.util.UUID; + +@Path("/api/v2/auth-service/gateway-webhook") +public class GatewayWebhookController { + private final ApplicationRepository applicationRepository; + private final OrganizationRepository organizationRepository; + private final ApplicationMappingRepository applicationMappingRepository; + private final OrganizationMappingRepository organizationMappingRepository; + + @Inject + public GatewayWebhookController(ApplicationRepository applicationRepository, + OrganizationRepository organizationRepository, + ApplicationMappingRepository applicationMappingRepository, + OrganizationMappingRepository organizationMappingRepository) { + this.applicationRepository = applicationRepository; + this.organizationRepository = organizationRepository; + this.applicationMappingRepository = applicationMappingRepository; + this.organizationMappingRepository = organizationMappingRepository; + } + + private static final Logger logger = LoggerFactory.getLogger(GatewayWebhookController.class); + + @POST("") + public StatusResponse index(Context context) { + logger.info("header {}", context.headerMap()); + logger.info("body {}", context.body().value()); + String body = context.body().value(); + String status = "success"; + String message = "Success"; + int statusCode = 200; + + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + InputSource inputSource = new InputSource(new StringReader(body)); + Document document = builder.parse(inputSource); + Element root = document.getDocumentElement(); + NodeList types = root.getElementsByTagName("type"); + NodeList actions = root.getElementsByTagName("action"); + NodeList objects = root.getElementsByTagName("object"); + if (types.getLength() > 0 && actions.getLength() > 0 && objects.getLength() > 0) { + Element type = (Element) types.item(0); + Element action = (Element) actions.item(0); + Element object = (Element) objects.item(0); + + String typeValue = type.getTextContent(); + String actionValue = action.getTextContent(); + NodeList objectNodes = object.getElementsByTagName(typeValue); + logger.info("MyTypeValue: {} action: {} objectNodes :{}", typeValue, actionValue,objectNodes); + if (objectNodes.getLength() > 0) { + Element objectChild = (Element) objectNodes.item(0); + if (typeValue.equals("application") && actionValue.equals("created") && object.hasChildNodes()) { + + NodeList idNodes = objectChild.getElementsByTagName("id"); + NodeList userAccountIdNodes = objectChild.getElementsByTagName("user_account_id"); + NodeList nameNodes = objectChild.getElementsByTagName("name"); + logger.info("MyObjectChild: {}", objectChild); + if (idNodes.getLength() > 0 && nameNodes.getLength() > 0) { + String id = idNodes.item(0).getTextContent().trim(); + String userAccountId = userAccountIdNodes.item(0).getTextContent().trim(); +// String name = nameNodes.item(0).getTextContent().trim(); + String name = null; + for (int i = 0; i < nameNodes.getLength(); i++) { + Node nameNode = nameNodes.item(i); + if (nameNode.getParentNode().equals(objectChild)) { + name = nameNode.getTextContent().trim(); + break; + } + } + long organizationGatewayId = Long.parseLong(userAccountId); + List organizationMappings = organizationMappingRepository.findByCustomWhere(String.format("gateway_id = '%s'", organizationGatewayId), 1, 0, "id", "desc"); + String organizationId = UUID.randomUUID().toString(); + if (organizationMappings.isEmpty()) { + Organization organization = new Organization(); + organization.setId(organizationId); + organization.setName("Default Organization"); + organization.setCreatedAt(LocalDateTime.now()); + organization.setUpdatedAt(LocalDateTime.now()); + organizationRepository.insert(organization); + + OrganizationMapping organizationMapping = new OrganizationMapping(); + organizationMapping.setId(UUID.randomUUID().toString()); + organizationMapping.setOrganizationId(organizationId); + organizationMapping.setGatewayId(organizationGatewayId); + organizationMappingRepository.insert(organizationMapping); + } else { + organizationId = organizationMappings.get(0).getOrganizationId(); + } + +// List applications = applicationRepository.findByCustomWhere(String.format("name = '%s'", name), 1, 0, "id", "desc"); + long gatewayId = Long.parseLong(id); + List applicationMappings = applicationMappingRepository.findByCustomWhere(String.format("gateway_id = '%s'", gatewayId), 1, 0, "id", "desc"); + String applicationId = UUID.randomUUID().toString(); + logger.info("MyApplication Data For Insert: {}", applicationMappings); + if (applicationMappings.isEmpty()) { + Application application = new Application(); + application.setId(applicationId); + application.setOrganizationId(organizationId); + application.setName(name); + application.setCreatedAt(LocalDateTime.now()); + application.setUpdatedAt(LocalDateTime.now()); + applicationRepository.insert(application); + logger.info("MyApplication Insert: {}", application); + + ApplicationMapping applicationMapping = new ApplicationMapping(); + applicationMapping.setId(UUID.randomUUID().toString()); + applicationMapping.setApplicationId(applicationId); + applicationMapping.setGatewayId(gatewayId); + applicationMappingRepository.insert(applicationMapping); + + } + } + } else if (typeValue.equals("application") && actionValue.equals("updated") && object.hasChildNodes()) { + + NodeList idNodes = objectChild.getElementsByTagName("id"); + NodeList nameNodes = objectChild.getElementsByTagName("name"); + logger.info("MyObjectChild: {}", objectChild); + if (idNodes.getLength() > 0 && nameNodes.getLength() > 0) { + String id = idNodes.item(0).getTextContent().trim(); + String name = null; + for (int i = 0; i < nameNodes.getLength(); i++) { + Node nameNode = nameNodes.item(i); + if (nameNode.getParentNode().equals(objectChild)) { + name = nameNode.getTextContent().trim(); + break; + } + } + + long gatewayId = Long.parseLong(id); + List applicationMapping = applicationMappingRepository.findByCustomWhere(String.format("gateway_id = '%s'", gatewayId), 1, 0, "id", "desc"); + List applications = applicationRepository.findByCustomWhere(String.format("id = '%s'", applicationMapping.get(0).getApplicationId()), 1, 0, "id", "desc"); + logger.info("MyApplication Data For Update: {}", applications); + if (!applications.isEmpty()) { + Application application = new Application(); + application.setId(applications.get(0).getId()); + application.setOrganizationId(applications.get(0).getOrganizationId()); + application.setName(name); + application.setCreatedAt(applications.get(0).getCreatedAt()); + application.setUpdatedAt(LocalDateTime.now()); + applicationRepository.update(application, applications.get(0).getId()); + logger.info("MyApplication Update: {}", application); + } + } + } else if (typeValue.equals("application") && actionValue.equals("deleted") && object.hasChildNodes()) { + NodeList idNodes = objectChild.getElementsByTagName("id"); + NodeList nameNodes = objectChild.getElementsByTagName("name"); + if (idNodes.getLength() > 0 && nameNodes.getLength() > 0) { + String id = idNodes.item(0).getTextContent().trim(); + + long gatewayId = Long.parseLong(id); + List applicationMapping = applicationMappingRepository.findByCustomWhere(String.format("gateway_id = '%s'", gatewayId), 1, 0, "id", "desc"); + List applications = applicationRepository.findByCustomWhere(String.format("id = '%s'", applicationMapping.get(0).getApplicationId()), 1, 0, "id", "desc"); + logger.info("MyApplication Data For Delete: {}", applications); + if (!applications.isEmpty()) { + applicationRepository.delete(applications.get(0).getId()); + logger.info("Deleted Application"); + } else { + logger.info("Failed Deleted Application "); + } + List applicationMappings = applicationMappingRepository.findByCustomWhere(String.format("application_id = '%s'", applications.get(0).getId()), 1, 0, "id", "desc"); + if (!applicationMappings.isEmpty()) { + applicationMappingRepository.delete(applicationMappings.get(0).getId()); + logger.info("Deleted App Mapping"); + } else { + logger.info("Failed Deleted App Mapping: "); + } + } + } else if (typeValue.equals("account") && actionValue.equals("created") && object.hasChildNodes()) { + NodeList idNodes = objectChild.getElementsByTagName("id"); + NodeList orgNameNodes = objectChild.getElementsByTagName("org_name"); + if (idNodes.getLength() > 0 && orgNameNodes.getLength() > 0) { + String id = idNodes.item(0).getTextContent().trim(); + String orgName = orgNameNodes.item(0).getTextContent().trim(); + + List organizations = organizationRepository.findByCustomWhere(String.format("name = '%s'", orgName), 1, 0, "id", "desc"); + String organizationId = UUID.randomUUID().toString(); + if (organizations.isEmpty()) { + Organization organization = new Organization(); + organization.setId(organizationId); + organization.setName(orgName); + organization.setCreatedAt(LocalDateTime.now()); + organization.setUpdatedAt(LocalDateTime.now()); + organizationRepository.insert(organization); + } else { + Organization organization = organizations.get(0); + organization.setName(orgName); + organization.setUpdatedAt(LocalDateTime.now()); + organizationId = organization.getId(); + organizationRepository.update(organization, organizationId); + } + long gatewayId = Long.parseLong(id); + List organizationMappings = organizationMappingRepository.findByCustomWhere(String.format("organization_id = '%s' and gateway_id = %d", organizationId, gatewayId), 1, 0, "id", "desc"); + if (organizationMappings.isEmpty()) { + OrganizationMapping organizationMapping = new OrganizationMapping(); + organizationMapping.setId(UUID.randomUUID().toString()); + organizationMapping.setOrganizationId(organizationId); + organizationMapping.setGatewayId(gatewayId); + organizationMappingRepository.insert(organizationMapping); + } + } + } else if (typeValue.equals("account") && actionValue.equals("updated") && object.hasChildNodes()) { + NodeList idNodes = objectChild.getElementsByTagName("id"); + NodeList orgNameNodes = objectChild.getElementsByTagName("org_name"); + if (idNodes.getLength() > 0 && orgNameNodes.getLength() > 0) { + String id = idNodes.item(0).getTextContent().trim(); + String orgName = orgNameNodes.item(0).getTextContent().trim(); + long gatewayId = Long.parseLong(id); + List organizationMappings = organizationMappingRepository.findByCustomWhere(String.format("gateway_id = %d", gatewayId), 1, 0, "id", "desc"); + String organizationId = organizationMappings.get(0).getOrganizationId(); + List organizations = organizationRepository.findByCustomWhere(String.format("id = '%s'",organizationId), 1, 0, "id", "desc"); + if (!organizations.isEmpty()) { + Organization organization = new Organization(); + organization.setId(organizationId); + organization.setName(orgName); + organization.setCreatedAt(organizations.get(0).getCreatedAt()); + organization.setUpdatedAt(LocalDateTime.now()); + organizationRepository.update(organization,organizationId); + } + } + } else if (typeValue.equals("account") && actionValue.equals("deleted") && object.hasChildNodes()) { + NodeList idNodes = objectChild.getElementsByTagName("id"); + NodeList orgNameNodes = objectChild.getElementsByTagName("org_name"); + if (idNodes.getLength() > 0 && orgNameNodes.getLength() > 0) { + String id = idNodes.item(0).getTextContent().trim(); + long gatewayId = Long.parseLong(id); + List organizationMappings = organizationMappingRepository.findByCustomWhere(String.format("gateway_id = %d", gatewayId), 1, 0, "id", "desc"); + String organizationId = organizationMappings.get(0).getOrganizationId(); + List organizations = organizationRepository.findByCustomWhere(String.format("id = '%s'",organizationId), 1, 0, "id", "desc"); + if (!organizations.isEmpty()) { + organizationRepository.delete(organizationId); + logger.info("Deleted Org Application"); + } else { + logger.info("Failed Deleted Org Application "); + } + if (!organizationMappings.isEmpty()) { + organizationMappingRepository.delete(organizationMappings.get(0).getId()); + logger.info("Deleted Org Mapping"); + } else { + logger.info("Failed Deleted Org Mapping: "); + } + } + } + } else { + logger.error("No {} object found in Event XML", typeValue); + statusCode = 500; + status = "error"; + message = String.format("No %s object found in Event XML", typeValue); + } + + } + } catch (ParserConfigurationException | IOException | SAXException e) { + statusCode = 500; + status = "error"; + message = "Failed to parse Event XML"; + logger.error("Error parsing Event XML: {}", e.getMessage()); + } + + return StatusResponse.builder().status(status).statusCode(statusCode).message(message).build(); + } +} diff --git a/src/main/java/id/go/polri/tte/controllers/LoginController.java b/src/main/java/id/go/polri/tte/controllers/LoginController.java new file mode 100644 index 0000000..deeecfb --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/LoginController.java @@ -0,0 +1,140 @@ +package id.go.polri.tte.controllers; + +import at.favre.lib.crypto.bcrypt.BCrypt; +import id.go.polri.tte.models.Role; +import id.go.polri.tte.models.UserRole; +import id.go.polri.tte.repositories.jdbi.RoleRepository; +import id.go.polri.tte.repositories.jdbi.UserLogsRepository; +import id.go.polri.tte.dto.LoginDto; +import id.go.polri.tte.models.User; +import id.go.polri.tte.models.UserLogs; +import id.go.polri.tte.repositories.jdbi.UserRepository; +import id.go.polri.tte.repositories.jdbi.UserRoleRepository; +import id.go.polri.tte.responses.BasicResponse; +import id.go.polri.tte.responses.LoginResponse; +import id.go.polri.tte.responses.LoginSingleResponse; +import id.go.polri.tte.utility.JwtUtil; +import io.jooby.annotation.POST; +import io.jooby.annotation.Path; +import jakarta.inject.Inject; + +import java.time.LocalDateTime; +import java.util.*; + +@Path("/api/v2/auth-service") +public class LoginController { + private final UserRepository userRepository; + private final UserRoleRepository userRoleRepository; + private final RoleRepository roleRepository; + private final UserLogsRepository userLogsRepository; + private final JwtUtil jwtUtil; + + @Inject + public LoginController(UserRepository userRepository, + UserRoleRepository userRoleRepository, + RoleRepository roleRepository, + UserLogsRepository userLogsRepository, + JwtUtil jwtUtil) { + this.userRepository = userRepository; + this.userRoleRepository = userRoleRepository; + this.roleRepository = roleRepository; + this.userLogsRepository = userLogsRepository; + this.jwtUtil = jwtUtil; + } + + @POST("/login") + public LoginSingleResponse authenticate(LoginDto loginDto) { + User user = userRepository.findLatestByEmail(loginDto.getEmail()); + if (user == null) { + return LoginSingleResponse.builder().code(1).message("Email salah.").build(); + } + + BCrypt.Result result = BCrypt.verifyer().verify(loginDto.getPassword().toCharArray(), user.getPassword()); + if (!result.verified) { + return LoginSingleResponse.builder().code(1).message("Password salah").build(); + } + + if (Objects.equals(user.getStatusAccount(), "suspended")) { + return LoginSingleResponse.builder() + .code(1) + .message("Status akun anda suspended.\nSilahkan reset password untuk mengaktifkan kembali akun anda") + .build(); + } + + LocalDateTime now = LocalDateTime.now(); + UserLogs user_log = new UserLogs(); + user_log.setId(UUID.randomUUID()); + user_log.setUserId(user.getId()); + user_log.setLastSignin(now); + boolean inserted = userLogsRepository.insert(user_log); + + LoginSingleResponse.LoginResponseSingleData data = LoginSingleResponse.LoginResponseSingleData.builder() + .id(user.getId()) + .isChanged(user.getIs_changed()) + .build(); + + if (inserted) { + return LoginSingleResponse.builder() + .code(0) + .message("success") + .user(data) + .build(); + } + + return LoginSingleResponse.builder() + .code(1) + .message("failure") + .build(); + } + + @POST("/login-internal") + public LoginResponse authenticateInternal(LoginDto loginDto) { + User user = userRepository.findLatestByEmail(loginDto.getEmail()); + if (user == null) { + return LoginResponse.builder().code(1).message("invalid email").build(); + } + + BCrypt.Result result = BCrypt.verifyer().verify(loginDto.getPassword().toCharArray(), user.getPassword()); + if (!result.verified) { + return LoginResponse.builder().code(2).message("invalid password").build(); + } + + LocalDateTime now = LocalDateTime.now(); + + UserLogs user_log = new UserLogs(); + user_log.setId(UUID.randomUUID()); + user_log.setUserId(user.getId()); + user_log.setLastSignin(now); + boolean inserted = userLogsRepository.insert(user_log); + if(inserted){ + List roles = new ArrayList<>(); + List userRoles = userRoleRepository.findByUserId(user.getId()); + for (UserRole userRole : userRoles) { + Role role = roleRepository.findById(userRole.getRoleId()); + roles.add(role.getName()); + } + + String token = jwtUtil.generateToken(String.valueOf(user.getId()), roles.toArray(new String[0])); + + LoginResponse.LoginResponseData data = LoginResponse.LoginResponseData.builder() + .roles(roles) + .user(user) + .build(); + + return LoginResponse.builder() + .code(0) + .message("success") + .token(token) + .data(data) + .build(); + } + return LoginResponse.builder() + .code(1) + .message("failure") + .token(null) + .data(null) + .build(); + + } +} + diff --git a/src/main/java/id/go/polri/tte/controllers/OrganizationController.java b/src/main/java/id/go/polri/tte/controllers/OrganizationController.java new file mode 100644 index 0000000..9bc0165 --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/OrganizationController.java @@ -0,0 +1,143 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.dto.TopOrganizationDTO; +import id.go.polri.tte.models.Organization; +import id.go.polri.tte.models.UsageOrganizations; +import id.go.polri.tte.repositories.jdbi.OrganizationRepository; +import id.go.polri.tte.repositories.jdbi.UsageOrganizationRepository; +import id.go.polri.tte.responses.*; +import io.jooby.Context; +import io.jooby.annotation.*; +import jakarta.inject.Inject; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@Path("/api/v2/auth-service/organizations") +public class OrganizationController { + private final OrganizationRepository repository; + private final UsageOrganizationRepository usageOrganizationRepository; + @Inject + public OrganizationController(OrganizationRepository repository, UsageOrganizationRepository usageOrganizationRepository) { + this.repository = repository; + this.usageOrganizationRepository = usageOrganizationRepository; + } + + @GET("") + public OrganizationListResponse findAll(Context context) { + if (context.queryMap().containsKey("limit") && context.queryMap().containsKey("offset") + && context.queryMap().containsKey("orderBy") && context.queryMap().containsKey("direction")) { + List andConditions = new ArrayList<>(); + List orConditions = new ArrayList<>(); + int limit = context.query("limit").intValue(); + int offset = context.query("offset").intValue(); + for (Map.Entry entry : context.queryMap().entrySet()) { + if (!entry.getKey().equals("limit") && !entry.getKey().equals("offset") + && !entry.getKey().equals("orderBy") && !entry.getKey().equals("direction")) { + if (entry.getKey().endsWith("_id") || entry.getKey().equals("username")) { + andConditions.add(entry.getKey() + " = '" + entry.getValue() + "'"); + } else { + orConditions.add(entry.getKey() + " like '%" + entry.getValue() + "%'"); + } + } + } + if (!andConditions.isEmpty() || !orConditions.isEmpty()) { + List conditions = new ArrayList<>(); + if (!andConditions.isEmpty()) { + String andCondition = String.join(" and ", andConditions); + conditions.add(andCondition); + } + if (!orConditions.isEmpty()) { + String orCondition = "(" + String.join(" or ", orConditions) + ")"; + conditions.add(orCondition); + } + String condition = String.join(" and ", conditions); + List list = repository.findByCustomWhere(condition, limit, offset, context.query("orderBy").value(), context.query("direction").value()); + int recordsTotal = repository.count(); + int recordsFiltered = repository.countByCustomWhere(condition); + return OrganizationListResponse.builder().code(0).message("Success").data(list) + .recordsFiltered(recordsFiltered).recordsTotal(recordsTotal).build(); + } + } + + List list = repository.findAll(); + return OrganizationListResponse.builder().code(0).message("Success").data(list).build(); + } + + @GET("/{id}") + public OrganizationSingleResponse findById(@PathParam String id, Context context) { + Organization item = repository.findById(id); + if (item == null) { + return OrganizationSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + return OrganizationSingleResponse.builder().code(0).message("Success").data(item).build(); + } + + @POST("") + public UsageOrganizationSingleResponse insert(Context context) { + UsageOrganizations item = context.body(UsageOrganizations.class); + item.setId(UUID.randomUUID()); + item.setOrgName(item.getOrgName()); + item.setCreatedAt(LocalDateTime.now()); + boolean result = usageOrganizationRepository.insert(item); + if (result) { + return UsageOrganizationSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return UsageOrganizationSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @PUT("/{id}") + public OrganizationSingleResponse update(@PathParam String id, Context context) { + Organization item = context.body(Organization.class); + boolean result = repository.update(item, id); + + if (result) { + return OrganizationSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return OrganizationSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @DELETE("/{id}") + public BasicResponse delete(@PathParam String id) { + boolean result = repository.delete(id); + if (result) { + return BasicResponse.builder().code(0).message("Success").build(); + } else { + return BasicResponse.builder().code(1).message("Failed").build(); + } + } + + @GET("/usages") + public Top10OrganizationListResponse findTop10(Context context) { + if (context.queryMap().containsKey("start_date") && context.queryMap().containsKey("end_date")) { + String startDateStr = context.query("start_date").value(); + String endDateStr = context.query("end_date").value(); + + // Parsing ke LocalDate + LocalDate startDate = LocalDate.parse(startDateStr); // format yyyy-MM-dd + LocalDate endDate = LocalDate.parse(endDateStr); + + List list = usageOrganizationRepository.findTop10OrganizationsByDate(startDate, endDate); + return Top10OrganizationListResponse.builder() + .code(0) + .message("Success") + .data(list) + .build(); + } + + List list = usageOrganizationRepository.findTop10Organizations(); + return Top10OrganizationListResponse.builder() + .code(0) + .message("Success") + .data(list) + .build(); + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/OrganizationMappingController.java b/src/main/java/id/go/polri/tte/controllers/OrganizationMappingController.java new file mode 100644 index 0000000..baab27d --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/OrganizationMappingController.java @@ -0,0 +1,120 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.models.OrganizationMapping; +import id.go.polri.tte.repositories.jdbi.OrganizationMappingRepository; +import id.go.polri.tte.responses.OrganizationMappingListResponse; +import id.go.polri.tte.responses.OrganizationMappingSingleResponse; +import id.go.polri.tte.responses.BasicResponse; +import io.jooby.Context; +import io.jooby.annotation.*; +import jakarta.inject.Inject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Path("/api/v2/auth-service/organization-mappings") +public class OrganizationMappingController { + private final OrganizationMappingRepository repository; + + @Inject + public OrganizationMappingController(OrganizationMappingRepository repository) { + this.repository = repository; + } + + @GET("") + public OrganizationMappingListResponse findAll(Context context) { + if (context.queryMap().containsKey("limit") && context.queryMap().containsKey("offset") + && context.queryMap().containsKey("orderBy") && context.queryMap().containsKey("direction")) { + List andConditions = new ArrayList<>(); + List orConditions = new ArrayList<>(); + int limit = context.query("limit").intValue(); + int offset = context.query("offset").intValue(); + for (Map.Entry entry : context.queryMap().entrySet()) { + if (!entry.getKey().equals("limit") && !entry.getKey().equals("offset") + && !entry.getKey().equals("orderBy") && !entry.getKey().equals("direction")) { + if (entry.getKey().endsWith("_id") || entry.getKey().equals("username")) { + andConditions.add(entry.getKey() + " = '" + entry.getValue() + "'"); + } else { + orConditions.add(entry.getKey() + " like '%" + entry.getValue() + "%'"); + } + } + } + if (!andConditions.isEmpty() || !orConditions.isEmpty()) { + List conditions = new ArrayList<>(); + if (!andConditions.isEmpty()) { + String andCondition = String.join(" and ", andConditions); + conditions.add(andCondition); + } + if (!orConditions.isEmpty()) { + String orCondition = "(" + String.join(" or ", orConditions) + ")"; + conditions.add(orCondition); + } + String condition = String.join(" and ", conditions); + List list = repository.findByCustomWhere(condition, limit, offset, context.query("orderBy").value(), context.query("direction").value()); + int recordsTotal = repository.count(); + int recordsFiltered = repository.countByCustomWhere(condition); + return OrganizationMappingListResponse.builder().code(0).message("Success").data(list) + .recordsFiltered(recordsFiltered).recordsTotal(recordsTotal).build(); + } + } + + if (context.queryMap().containsKey("organizationId")) { + String organizationId = context.query("organizationId").value(); + List list = repository.findByOrganizationId(organizationId); + return OrganizationMappingListResponse.builder().code(0).message("Success").data(list).build(); + } + + if (context.queryMap().containsKey("gatewayId")) { + String gatewayId = context.query("gatewayId").value(); + List list = repository.findByGatewayId(gatewayId); + return OrganizationMappingListResponse.builder().code(0).message("Success").data(list).build(); + } + + List list = repository.findAll(); + return OrganizationMappingListResponse.builder().code(0).message("Success").data(list).build(); + } + + @GET("/{id}") + public OrganizationMappingSingleResponse findById(@PathParam String id, Context context) { + OrganizationMapping item = repository.findById(id); + if (item == null) { + return OrganizationMappingSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + return OrganizationMappingSingleResponse.builder().code(0).message("Success").data(item).build(); + } + + @POST("") + public OrganizationMappingSingleResponse insert(Context context) { + OrganizationMapping item = context.body(OrganizationMapping.class); + boolean result = repository.insert(item); + if (result) { + return OrganizationMappingSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return OrganizationMappingSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @PUT("/{id}") + public OrganizationMappingSingleResponse update(@PathParam String id, Context context) { + OrganizationMapping item = context.body(OrganizationMapping.class); + boolean result = repository.update(item, id); + + if (result) { + return OrganizationMappingSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return OrganizationMappingSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @DELETE("/{id}") + public BasicResponse delete(@PathParam String id) { + boolean result = repository.delete(id); + if (result) { + return BasicResponse.builder().code(0).message("Success").build(); + } else { + return BasicResponse.builder().code(1).message("Failed").build(); + } + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/RoleController.java b/src/main/java/id/go/polri/tte/controllers/RoleController.java new file mode 100644 index 0000000..dc5dfc9 --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/RoleController.java @@ -0,0 +1,118 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.models.Role; +import id.go.polri.tte.repositories.jdbi.RoleRepository; +import id.go.polri.tte.responses.RoleListResponse; +import id.go.polri.tte.responses.RoleSingleResponse; +import id.go.polri.tte.responses.BasicResponse; +import io.jooby.Context; +import io.jooby.annotation.*; +import jakarta.inject.Inject; + +import java.time.LocalDateTime; +import java.util.UUID; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Path("/api/v2/auth-service/roles") +public class RoleController { + private final RoleRepository repository; + + @Inject + public RoleController(RoleRepository repository) { + this.repository = repository; + } + + @GET("") + public RoleListResponse findAll(Context context) { + if (context.queryMap().containsKey("limit") && context.queryMap().containsKey("offset") + && context.queryMap().containsKey("orderBy") && context.queryMap().containsKey("direction")) { + List andConditions = new ArrayList<>(); + List orConditions = new ArrayList<>(); + int limit = context.query("limit").intValue(); + int offset = context.query("offset").intValue(); + for (Map.Entry entry : context.queryMap().entrySet()) { + if (!entry.getKey().equals("limit") && !entry.getKey().equals("offset") + && !entry.getKey().equals("orderBy") && !entry.getKey().equals("direction")) { + if (entry.getKey().endsWith("_id") || entry.getKey().equals("username")) { + andConditions.add(entry.getKey() + " = '" + entry.getValue() + "'"); + } else { + orConditions.add(entry.getKey() + " like '%" + entry.getValue() + "%'"); + } + } + } + if (!andConditions.isEmpty() || !orConditions.isEmpty()) { + List conditions = new ArrayList<>(); + if (!andConditions.isEmpty()) { + String andCondition = String.join(" and ", andConditions); + conditions.add(andCondition); + } + if (!orConditions.isEmpty()) { + String orCondition = "(" + String.join(" or ", orConditions) + ")"; + conditions.add(orCondition); + } + String condition = String.join(" and ", conditions); + List list = repository.findByCustomWhere(condition, limit, offset, context.query("orderBy").value(), context.query("direction").value()); + int recordsTotal = repository.count(); + int recordsFiltered = repository.countByCustomWhere(condition); + return RoleListResponse.builder().code(0).message("Success").data(list) + .recordsFiltered(recordsFiltered).recordsTotal(recordsTotal).build(); + } + } + + List list = repository.findAll(); + return RoleListResponse.builder().code(0).message("Success").data(list).build(); + } + + @GET("/{id}") + public RoleSingleResponse findById(@PathParam String id, Context context) { + Role item = repository.findById(UUID.fromString(id)); + if (item == null) { + return RoleSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + return RoleSingleResponse.builder().code(0).message("Success").data(item).build(); + } + + @POST("") + public RoleSingleResponse insert(Context context) { + Role item = context.body(Role.class); + item.setId(UUID.randomUUID()); + item.setCreatedAt(LocalDateTime.now()); + item.setUpdatedAt(LocalDateTime.now()); + + boolean result = repository.insert(item); + if (result) { + return RoleSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return RoleSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @PUT("/{id}") + public RoleSingleResponse update(@PathParam UUID id, Context context) { + Role item = context.body(Role.class); + Role oldData = repository.findById(id); + item.setId(oldData.getId()); + item.setCreatedAt(oldData.getCreatedAt()); + item.setUpdatedAt(LocalDateTime.now()); + boolean result = repository.update(item, UUID.fromString(String.valueOf(id))); + + if (result) { + return RoleSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return RoleSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @DELETE("/{id}") + public BasicResponse delete(@PathParam String id) { + boolean result = repository.delete(UUID.fromString(id)); + if (result) { + return BasicResponse.builder().code(0).message("Success").build(); + } else { + return BasicResponse.builder().code(1).message("Failed").build(); + } + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/SippController.java b/src/main/java/id/go/polri/tte/controllers/SippController.java new file mode 100644 index 0000000..6f68f3f --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/SippController.java @@ -0,0 +1,100 @@ +package id.go.polri.tte.controllers; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import id.go.polri.tte.models.User; +import id.go.polri.tte.repositories.jdbi.UserRepository; +import id.go.polri.tte.responses.SippResponse; +import io.jooby.Context; +import io.jooby.annotation.GET; +import io.jooby.annotation.Path; +import id.go.polri.tte.repositories.api.SippRepository; +import jakarta.inject.Inject; +import com.fasterxml.jackson.databind.JsonNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Path("/api/v2/auth-service/sipp") +public class SippController { + private static final Logger logger = LoggerFactory.getLogger(SippController.class); + private final SippRepository repository; + private final UserRepository userRepository; + @Inject + public SippController(SippRepository repository,UserRepository userRepository) { + this.repository = repository; + this.userRepository = userRepository; + } + + @GET + public SippResponse find(Context context) { + String nrp = context.query("nrp").value(); + if (nrp.isEmpty()) { + return SippResponse.builder().code(1).message("NRP wajib diisi.").build(); + } + JsonNode result = repository.findByNrp(nrp); + User dataUser = userRepository.findByNrp(nrp); + logger.info("Raw response from SIPP API: {}", result.toString()); + ObjectNode mergedResult = result.deepCopy(); + + if (dataUser != null) { + mergedResult.put("handphone", dataUser.getPhone()); + mergedResult.put("nik", dataUser.getNik()); + mergedResult.put("email", dataUser.getEmail()); + } else { + logger.warn("User dengan NRP {} tidak ditemukan di database lokal.", nrp); + } + + // Tambahan: convert pangkat lengkap + JsonNode pangkatNode = result.get("pangkat"); + if (pangkatNode != null && !pangkatNode.isNull()) { + String pangkat = pangkatNode.asText(); + String pangkatLengkap = pangkatLengkap(pangkat); + mergedResult.put("pangkat_lengkap", pangkatLengkap); + } + + return SippResponse.builder() + .code(0) + .message("Response SIPP.") + .data(mergedResult) + .build(); + } + + private String pangkatLengkap(String pangkat) { + if (pangkat == null) return null; + + return switch (pangkat.toUpperCase()) { + case "AIPDA" -> "Ajun Inspektur Polisi Dua"; + case "AIPTU" -> "Ajun Inspektur Polisi Satu"; + case "AKBP" -> "Ajun Komisaris Besar Polisi"; + case "AKP" -> "Ajun Komisaris Polisi"; + case "BRIGJEN POL" -> "Brigadir Jenderal Polisi"; + case "BRIGPOL" -> "Brigadir Polisi"; + case "BRIPDA" -> "Brigadir Polisi Dua"; + case "BRIPTU" -> "Brigadir Polisi Satu"; + case "IPDA" -> "Inspektur Polisi Dua"; + case "IPTU" -> "Inspektur Polisi Satu"; + case "IRJEN POL" -> "Inspektur Jenderal Polisi"; + case "JENDERAL POL" -> "Jenderal Polisi"; + case "KOMBES POL" -> "Komisaris Besar Polisi"; + case "KOMJEN POL" -> "Komisaris Jenderal Polisi"; + case "KOMPOL" -> "Komisaris Polisi"; + case "PEMBINA UTAMA" -> "Pembina Utama"; + case "PEMMADYA" -> "Pembina Utama Madya"; + case "PEMBMUDA" -> "Pembina Utama Muda"; + case "PEMBINA I" -> "Pembina Tk. I"; + case "PEMBINA" -> "Pembina"; + case "PENATA I" -> "Penata Tk. I"; + case "PENATA" -> "Penata"; + case "PENDA I" -> "Penata Muda Tk. I"; + case "PENDA" -> "Penata Muda"; + case "PENGATUR I" -> "Pengatur Tk. I"; + case "PENGATUR" -> "Pengatur"; + case "PENGDA I" -> "Pengatur Muda Tk. I"; + case "PENGDA" -> "Pengatur Muda"; + case "JURU I" -> "Juru Tk. I"; + case "JURU" -> "Juru"; + case "JURMUD I" -> "Juru Muda Tk. I"; + case "JURMUD" -> "Juru Muda"; + default -> pangkat; + }; + } +} diff --git a/src/main/java/id/go/polri/tte/controllers/UserController.java b/src/main/java/id/go/polri/tte/controllers/UserController.java new file mode 100644 index 0000000..06d1dfa --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/UserController.java @@ -0,0 +1,662 @@ +package id.go.polri.tte.controllers; + +import at.favre.lib.crypto.bcrypt.BCrypt; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import id.go.polri.tte.dto.*; +import id.go.polri.tte.models.*; +import id.go.polri.tte.repositories.jdbi.*; +import id.go.polri.tte.responses.*; +import id.go.polri.tte.services.*; +import id.go.polri.tte.utility.JwtUtil; +import io.jooby.Context; +import io.jooby.annotation.*; +import jakarta.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.LocalDate; +import java.util.*; +import java.time.LocalDateTime; + +@Path("/api/v2/auth-service/users") +public class UserController { + private static final Logger logger = LoggerFactory.getLogger(UserController.class); + + private final UserRepository repository; + private final UserRoleRepository userRoleRepository; + private final RoleRepository roleRepository; + private final OneTimePasswordRepository otpRepository; + private final EmailService emailService; + private final NotificationService notificationService; + private final UsageUserRepository usageUserRepository; + private final JwtUtil jwtUtil; + + @Inject + public UserController(UserRepository repository, + UserRoleRepository userRoleRepository, + RoleRepository roleRepository, + OneTimePasswordRepository otpRepository, + EmailService emailService, + NotificationService notificationService, UsageUserRepository usageUserRepository, JwtUtil jwtUtil) { + this.repository = repository; + this.userRoleRepository = userRoleRepository; + this.roleRepository = roleRepository; + this.otpRepository = otpRepository; + this.emailService = emailService; + this.notificationService = notificationService; + this.usageUserRepository = usageUserRepository; + this.jwtUtil = jwtUtil; + } + + @GET("") + public UserListResponse findAll(Context context) { + context.headerMap().forEach((s, s2) -> { + logger.info("header {} : {}", s, s2); + }); + if (context.queryMap().containsKey("limit") && context.queryMap().containsKey("offset") + && context.queryMap().containsKey("orderBy") && context.queryMap().containsKey("direction")) { + + List andConditions = new ArrayList<>(); + List orConditions = new ArrayList<>(); + + int limit = context.query("limit").intValue(); + int offset = context.query("offset").intValue(); + + if (context.queryMap().containsKey("search")) { + String searchValue = context.query("search").value(); + if (searchValue != null && !searchValue.trim().isEmpty()) { + String[] searchableFields = {"name", "nrp", "email", "phone", "jabatan"}; + for (String field : searchableFields) { + orConditions.add(field + " ILIKE '%" + searchValue + "%'"); + } + } + } + + + for (Map.Entry entry : context.queryMap().entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + + if (!Set.of("limit", "offset", "orderBy", "direction", "search").contains(key)) { + if (key.endsWith("_id") || key.equals("username")) { + andConditions.add(key + " = '" + value + "'"); + } else { + orConditions.add(key + " ILIKE '%" + value + "%'"); + } + } + } + + if (!andConditions.isEmpty() || !orConditions.isEmpty()) { + List conditions = new ArrayList<>(); + if (!andConditions.isEmpty()) { + conditions.add(String.join(" AND ", andConditions)); + } + if (!orConditions.isEmpty()) { + conditions.add("(" + String.join(" OR ", orConditions) + ")"); + } + + String whereClause = String.join(" AND ", conditions); + + List list = repository.findByCustomWhereUserLogs(whereClause, limit, offset, + context.query("orderBy").value(), context.query("direction").value()); + int recordsTotal = repository.count(); + int recordsFiltered = repository.countByCustomWhere(whereClause); + + return UserListResponse.builder() + .code(0) + .message("Success") + .data(list) + .recordsFiltered(recordsFiltered) + .recordsTotal(recordsTotal) + .build(); + } else { + List list = repository.findAll(limit, offset, + context.query("orderBy").value(), context.query("direction").value()); + int recordsTotal = repository.count(); + + return UserListResponse.builder() + .code(0) + .message("Success") + .data(list) + .recordsTotal(recordsTotal) + .build(); + } + + } + List list = repository.findAll(); + int recordsTotal = repository.count(); + return UserListResponse.builder() + .code(0) + .message("Success") + .data(list) + .recordsTotal(recordsTotal) + .build(); + } + + @GET("/{id}") + public UserSingleResponse findById(@PathParam UUID id, Context context) { + User item = repository.findWithRolesById(id); + if (item == null) { + return UserSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + return UserSingleResponse.builder().code(0).message("Success").data(item).build(); + } + + @GET("/nrp/{nrp}") + public UserSingleResponse findByNrp(@PathParam String nrp, Context context) { + User item = repository.findByNrp(nrp); + if (item == null) { + return UserSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + return UserSingleResponse.builder().code(0).message("Success").data(item).build(); + } + + @POST("") + public UserSingleResponse insert(Context context) throws JsonProcessingException { + User item = context.body(User.class); + item.setId(UUID.randomUUID()); + + String hashedPassword = at.favre.lib.crypto.bcrypt.BCrypt + .withDefaults() + .hashToString(12, item.getPassword().toCharArray()); + item.setPassword(hashedPassword); + + item.setCreatedAt(LocalDateTime.now()); + item.setUpdatedAt(LocalDateTime.now()); + String satuanJson = new ObjectMapper().writeValueAsString(item.getSatuan()); + boolean result = repository.insert(item, satuanJson); + if (result) { + return UserSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return UserSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @PUT("/{id}") + public UserSingleResponse update(@PathParam UUID id, Context context) throws JsonProcessingException { + User item = context.body(User.class); + User oldUser = repository.findById(id); + + item.setId(oldUser.getId()); + if (item.getName() == null || item.getName().isEmpty()) { + item.setName(oldUser.getName()); + } + + if (item.getEmail() == null || item.getEmail().isEmpty()) { + item.setEmail(oldUser.getEmail()); + } + + if (item.getPhone() == null || item.getPhone().isEmpty()) { + item.setPhone(oldUser.getPhone()); + } + + if (item.getEmailVerifiedAt() == null) { + item.setEmailVerifiedAt(oldUser.getEmailVerifiedAt()); + } + + if (item.getPhoneVerifiedAt() == null) { + item.setPhoneVerifiedAt(oldUser.getPhoneVerifiedAt()); + } + + if (item.getPassword() == null || item.getPassword().isEmpty()) { + item.setPassword(oldUser.getPassword()); + } + + if (item.getNrp() == null || item.getNrp().isEmpty()) { + item.setNrp(oldUser.getNrp()); + } + + if (item.getNik() == null || item.getNik().isEmpty()) { + item.setNik(oldUser.getNik()); + } + + if (item.getResponseStatus() == null || item.getResponseStatus().isEmpty()) { + item.setResponseStatus(oldUser.getResponseStatus()); + } + + if (item.getPangkat() == null || item.getPangkat().isEmpty()) { + item.setPangkat(oldUser.getPangkat()); + } + + if (item.getNamaTanpaGelar() == null || item.getNamaTanpaGelar().isEmpty()) { + item.setNamaTanpaGelar(oldUser.getNamaTanpaGelar()); + } + + if (item.getJabatan() == null || item.getJabatan().isEmpty()) { + item.setJabatan(oldUser.getJabatan()); + } + + if (item.getIs_changed() == null) { + item.setIs_changed(oldUser.getIs_changed()); + } + + if (item.getSatuan() == null || item.getSatuan().isEmpty()) { + item.setSatuan(oldUser.getSatuan()); + } + + if (item.getPangkatLengkap() == null || item.getPangkatLengkap().isEmpty()) { + item.setPangkatLengkap(oldUser.getPangkatLengkap()); + } + + if (item.getSatker() == null || item.getSatker().isEmpty()) { + item.setSatker(oldUser.getSatker()); + } + + if (item.getNamaAplikasi() == null || item.getNamaAplikasi().isEmpty()) { + item.setNamaAplikasi(oldUser.getNamaAplikasi()); + } + + if (item.getNamaPendekDenganGelar() == null) { + item.setNamaPendekDenganGelar(oldUser.getNamaPendekDenganGelar()); + } else if (item.getNamaPendekDenganGelar().isEmpty()) { + item.setNamaPendekDenganGelar(null); + } + + if (item.getDeviceToken() == null || item.getDeviceToken().isEmpty()) { + item.setDeviceToken(oldUser.getDeviceToken()); + } + + item.setCreatedAt(oldUser.getCreatedAt()); + String satuanJson = new ObjectMapper().writeValueAsString(item.getSatuan()); + item.setUpdatedAt(LocalDateTime.now()); + boolean result = repository.update(item, id, satuanJson); + + if (result) { + + logger.info("nama pendek {}", item.getNamaPendekDenganGelar()); + return UserSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return UserSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @DELETE("/{id}") + public BasicResponse delete(@PathParam UUID id) { + boolean result = repository.delete(id); + if (result) { + return BasicResponse.builder().code(0).message("Success").build(); + } else { + return BasicResponse.builder().code(1).message("Failed").build(); + } + } + + @POST("/reset-password") + public BasicResponse resetPassword(Context context) { + UserVerifyDto dto = context.body(UserVerifyDto.class); + + if (dto.getEmail() == null || dto.getEmail().isEmpty()) { + return BasicResponse.builder().code(1).message("Email is required").build(); + } + + if (dto.getPassword() == null || dto.getPassword().isEmpty()) { + return BasicResponse.builder().code(1).message("Password is required").build(); + } + + User user = repository.findLatestByEmail(dto.getEmail()); + if (user == null) { + return BasicResponse.builder().code(1).message("Invalid email").build(); + } + + String hashedPassword = at.favre.lib.crypto.bcrypt.BCrypt.withDefaults() + .hashToString(12, dto.getPassword().toCharArray()); + + user.setPassword(hashedPassword); + user.setUpdatedAt(LocalDateTime.now()); + user.setStatusAccount("active"); + user.setIs_changed(1); + + boolean success = repository.updateCustom(user, UUID.fromString(String.valueOf(user.getId()))); + + if (success) { + return BasicResponse.builder().code(0).message("Password reset successfully").build(); + } else { + return BasicResponse.builder().code(1).message("Failed to reset password").build(); + } + } + + @POST("/reset-password-to-default") + public BasicResponse resetPasswordtoDefault(Context context) { + UserIdDto dto = context.body(UserIdDto.class); + + if (dto.getUser_id() == null) { + return BasicResponse.builder().code(1).message("User id is required").build(); + } + + User user = repository.findById(dto.getUser_id()); + + String hashedPassword = at.favre.lib.crypto.bcrypt.BCrypt.withDefaults() + .hashToString(12, user.getNrp().toCharArray()); + + user.setPassword(hashedPassword); + user.setUpdatedAt(LocalDateTime.now()); + user.setIs_changed(0); + + boolean success = repository.updateCustom(user, user.getId()); + + if (success) { + return BasicResponse.builder().code(0).message("Password reset successfully").build(); + } else { + return BasicResponse.builder().code(1).message("Failed to reset password").build(); + } + } + + @POST("/change-password") + public BasicResponse changePassword(Context context) { + ChangePasswordDto dto = context.body(ChangePasswordDto.class); + if (dto.getOldpassword() == null || dto.getOldpassword().isEmpty()) { + return BasicResponse.builder().code(1).message("Old Password is required").build(); + } + + if (dto.getNewpassword() == null || dto.getNewpassword().isEmpty()) { + return BasicResponse.builder().code(1).message("New Password is required").build(); + } + + User user = repository.findById(dto.getUser_id()); + if (user == null) { + return BasicResponse.builder().code(1).message("Invalid User ID").build(); + } + BCrypt.Result result = BCrypt.verifyer().verify(dto.getOldpassword().toCharArray(), user.getPassword()); + if (!result.verified) { + return BasicResponse.builder().code(1).message("invalid old password").build(); + } + + String hashedPassword = at.favre.lib.crypto.bcrypt.BCrypt.withDefaults() + .hashToString(12, dto.getNewpassword().toCharArray()); + + user.setPassword(hashedPassword); + user.setUpdatedAt(LocalDateTime.now()); + user.setIs_changed(1); + + boolean success = repository.updateCustom(user, user.getId()); + + if (success) { + return BasicResponse.builder().code(0).message("Change password successfully").build(); + } else { + return BasicResponse.builder().code(1).message("Failed to change password").build(); + } + + } + + + @POST("/send-otp") + public BasicResponse sendOtp(Context context) { + SendOtpDto dto = context.body(SendOtpDto.class); + if (dto.getEmail() == null || dto.getEmail().isEmpty()) { + return BasicResponse.builder().code(1).message("Email is required").build(); + } + + User userid = repository.findLatestByEmail(dto.getEmail()); + if (userid == null) { + return BasicResponse.builder().code(1).message("Email not found").build(); + } + + // Cek apakah sudah ada OTP yang aktif + OneTimePassword existingOtp = otpRepository.findLatestActiveByUserId(userid.getId()); + if (existingOtp != null) { + emailService.sendOtpEmail(dto.getEmail(), existingOtp.getCode()); + return BasicResponse.builder() + .code(0) + .message("OTP resend successfully to email " + dto.getEmail()) + .build(); + } + // Kalau tidak ada, buat OTP baru + String otpCode = String.format("%06d", (int) (Math.random() * 1000000)); + LocalDateTime now = LocalDateTime.now(); + LocalDateTime expiredAt = now.plusMinutes(5); + + OneTimePassword otp = new OneTimePassword(); + otp.setId(UUID.randomUUID()); + otp.setUserId(userid.getId()); + otp.setCode(otpCode); + otp.setExpiredAt(expiredAt); + otp.setUsedAt(null); + otp.setCreatedAt(now); + otp.setUpdatedAt(now); + + boolean inserted = otpRepository.upsert(otp); + + if (inserted) { + emailService.sendOtpEmail(dto.getEmail(), otpCode); + return BasicResponse.builder() + .code(0) + .message("OTP sent successfully to email " + dto.getEmail()) + .build(); + } else { + return BasicResponse.builder().code(1).message("Failed to generate OTP").build(); + } + } + + @POST("/verify-otp") + public LoginResponse verifyOtp(Context context) { + VerifyOtpDto dto = context.body(VerifyOtpDto.class); + + if (dto.getEmail() == null || dto.getEmail().isEmpty()) { + return LoginResponse.builder().code(1).message("Email is required").build(); + } + if (dto.getCode() == null || dto.getCode().isEmpty()) { + return LoginResponse.builder().code(1).message("Code OTP is required").build(); + } + + User user = repository.findLatestByEmail(dto.getEmail()); + if (user == null) { + return LoginResponse.builder().code(1).message("Email not found").build(); + } + + OneTimePassword otpActive = otpRepository.findLatestActiveByUserId(user.getId()); + if (otpActive == null) { + OneTimePassword lastOtp = otpRepository.findLatestByUserId(user.getId()); + String msg = (lastOtp != null) ? "OTP has expired" : "OTP not found"; + return LoginResponse.builder().code(1).message(msg).build(); + } + + if (!otpActive.getCode().equals(dto.getCode())) { + return LoginResponse.builder().code(1).message("Invalid or expired OTP").build(); + } + + // ✅ OTP valid → update dan generate token + otpRepository.updateUsedAt(otpActive.getId()); + + List userRoles = userRoleRepository.findByUserId(user.getId()); + List roles = new ArrayList<>(); + + if (userRoles != null) { + for (UserRole ur : userRoles) { + Role role = roleRepository.findById(ur.getRoleId()); + if (role != null && role.getName() != null) { + roles.add(role.getName()); + } + } + } + + // Jika roles kosong, tetap generate token tanpa role + String token = jwtUtil.generateToken( + user.getId().toString(), + roles.isEmpty() ? new String[0] : roles.toArray(new String[0]) + ); + + return LoginResponse.builder() + .code(0) + .message("Verify OTP Success") + .token(token) + .data(LoginResponse.LoginResponseData.builder() + .user(user) + .roles(roles) // bisa kosong, tapi tidak null + .build()) + .build(); + } + + @POST("/send-notification") + public BasicResponse sendNewDocumentNotification(Context context) { + NotificationWaDto dto = context.body(NotificationWaDto.class); + User user = repository.findById(UUID.fromString(dto.getId())); + if (user == null) { + String message = String.format("User dengan id '%s' tidak ditemukan.", dto.getId()); + return BasicResponse.builder().code(1).message(message).build(); + } + + notificationService.sendEmailNotification(user.getEmail(), dto.getFile_id(), dto.getSigning_id()); + String message = "Terdapat dokumen baru yang membutuhkan tindak lanjut pada aplikasi TTE POLRI"; + String phone = user.getPhone(); + phone = phone.replaceAll("[^0-9]", ""); // hapus karakter selain angka + + if (phone.startsWith("0")) { + phone = "62" + phone.substring(1); + } else if (phone.startsWith("8")) { + phone = "62" + phone; + } else if (!phone.startsWith("62")) { + return BasicResponse.builder() + .code(1) + .message("Nomor telepon tidak valid: " + user.getPhone()) + .build(); + } + String responseWa = notificationService.sendWhatsAppNotification(phone, message); + if (responseWa.contains("\"error\"")) { + String errorMessage = responseWa.replaceAll(".*\"message\"\\s*:\\s*\"([^\"]+)\".*", "$1"); + return BasicResponse.builder() + .code(1) + .message(errorMessage) + .build(); + } + return BasicResponse.builder().code(0).message("Notifikasi berhasil dikirim").build(); + } + + @POST("/send-document-approved-notification") + public BasicResponse sendApprovedDocumentNotification(Context context) { + NotificationWaDto dto = context.body(NotificationWaDto.class); + User user = repository.findById(UUID.fromString(dto.getId())); + if (user == null) { + String message = String.format("User dengan id '%s' tidak ditemukan.", dto.getId()); + return BasicResponse.builder().code(1).message(message).build(); + } + + String message = "Dokumen anda telah disetujui"; + String responseWa = notificationService.sendWhatsAppNotification(user.getPhone(), message); + if (responseWa.contains("\"error\"")) { + String errorMessage = responseWa.replaceAll(".*\"message\"\\s*:\\s*\"([^\"]+)\".*", "$1"); + return BasicResponse.builder() + .code(1) + .message(errorMessage) + .build(); + } + return BasicResponse.builder().code(0).message("Notifikasi berhasil dikirim").build(); + } + + @POST("/add-role") + public BasicResponse addRole(Context context) { + UserRoleDto dto = context.body(UserRoleDto.class); + UserRole existing = userRoleRepository.findLatestByUserAndRoleId(dto.getUserId(), dto.getRoleId()); + User user_existing = repository.findById(dto.getUserId()); + Role role_existing = roleRepository.findById(dto.getRoleId()); + if (user_existing == null) { + String message = String.format("User dengan id '%s' tidak ditemukan.", dto.getUserId()); + return BasicResponse.builder().code(1).message(message).build(); + } + if (role_existing == null) { + String message = String.format("Role dengan id '%s' tidak ditemukan.", dto.getRoleId()); + return BasicResponse.builder().code(1).message(message).build(); + } + + if (existing != null) { + // Sudah ada → hapus berdasarkan ID + boolean deleted = userRoleRepository.delete(existing.getId()); + if (deleted) { + return BasicResponse.builder().code(0).message("Role berhasil dihapus dari user.").build(); + } else { + return BasicResponse.builder().code(1).message("Gagal menghapus role dari user.").build(); + } + } else { + // Belum ada → tambahkan + UserRole userRole = new UserRole(); + userRole.setId(UUID.randomUUID()); + userRole.setUserId(dto.getUserId()); + userRole.setRoleId(dto.getRoleId()); + userRole.setCreatedAt(LocalDateTime.now()); + userRole.setUpdatedAt(LocalDateTime.now()); + + boolean isInserted = userRoleRepository.insert(userRole); + if (isInserted) { + return BasicResponse.builder().code(0).message("Role berhasil ditambahkan ke user.").build(); + } else { + return BasicResponse.builder().code(1).message("Gagal menambahkan role ke user.").build(); + } + } + } + + @GET("/total-users-tte") + public UserSingleResponse getTotalUser(Context context) { + int item = repository.count(); + Map result = new HashMap<>(); + result.put("totalUsers", item); + return UserSingleResponse.builder().code(0).message("Success").data(result).build(); + } + + @GET("/list-response-bsre") + public UserSingleResponse listResponse(Context context) { + List responseList = repository.countGroupedByResponseStatus(); + + Map data = new HashMap<>(); + data.put("responseList", responseList); + + return UserSingleResponse.builder() + .code(0) + .message("Success") + .data(data) + .build(); + } + + @POST("/account-suspend") + public BasicResponse accountSuspend(Context context) { + UserIdDto dto = context.body(UserIdDto.class); + + if (dto.getUser_id() == null) { + return BasicResponse.builder().code(1).message("User id is required").build(); + } + + User user = repository.findById(dto.getUser_id()); + + user.setUpdatedAt(LocalDateTime.now()); + user.setStatusAccount("suspended"); + + boolean success = repository.updateCustom(user, user.getId()); + + if (success) { + return BasicResponse.builder().code(0).message("Account Suspended successfully").build(); + } else { + return BasicResponse.builder().code(1).message("Failed to account Suspended").build(); + } + } + + @POST("/usage") + public UsageUserSingleResponse insertUsage(Context context) { + UsageUsers item = context.body(UsageUsers.class); + item.setId(UUID.randomUUID()); + item.setUserId(item.getUserId()); + item.setCreatedAt(LocalDateTime.now()); + boolean result = usageUserRepository.insert(item); + if (result) { + return UsageUserSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return UsageUserSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @GET("/usage") + public Top10UserListResponse findTop10Users(Context context) { + if (context.queryMap().containsKey("start_date") && context.queryMap().containsKey("end_date")) { + String startDateStr = context.query("start_date").value(); + String endDateStr = context.query("end_date").value(); + + // Parsing ke LocalDate + LocalDate startDate = LocalDate.parse(startDateStr); // format yyyy-MM-dd + LocalDate endDate = LocalDate.parse(endDateStr); + + List list = usageUserRepository.findTop10UsersByDate(startDate, endDate); + return Top10UserListResponse.builder().code(0).message("Success").data(list).build(); + } + + List list = usageUserRepository.findTop10Users(); + return Top10UserListResponse.builder().code(0).message("Success").data(list).build(); + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/UserInitialController.java b/src/main/java/id/go/polri/tte/controllers/UserInitialController.java new file mode 100644 index 0000000..7760377 --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/UserInitialController.java @@ -0,0 +1,150 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.dto.AddUserInitialDto; +import id.go.polri.tte.models.UserInitial; +import id.go.polri.tte.models.UserSignature; +import id.go.polri.tte.repositories.jdbi.UserInitialRepository; +import id.go.polri.tte.responses.UserInitialSingleResponse; +import id.go.polri.tte.responses.UserSignatureSingleResponse; +import id.go.polri.tte.utility.CephUtility; +import io.jooby.Context; +import io.jooby.FileUpload; +import io.jooby.annotation.*; +import jakarta.inject.Inject; + +import java.io.*; +import java.time.LocalDateTime; +import java.util.UUID; + +@Path("/api/v2/auth-service/user-initial") +public class UserInitialController { + private final UserInitialRepository repository; + + @Inject + public UserInitialController(UserInitialRepository repository) { + this.repository = repository; + } + + @GET("/{id}") + public void downloadFile(@PathParam UUID id, Context context) { + UserInitial item = repository.findSingleByUserId(id); + if (item == null || item.getFile() == null) { + context.setResponseCode(404).send("File not found"); + return; + } + + String objectName = item.getFile(); + String tempPath = System.getProperty("java.io.tmpdir") + "/" + UUID.randomUUID(); + + CephUtility ceph = context.require(CephUtility.class); + boolean success = ceph.download(objectName, tempPath); + + if (!success) { + context.setResponseCode(400).send("Failed to download file from Ceph"); + return; + } + + File file = new File(tempPath); + if (!file.exists()) { + context.setResponseCode(404).send("Temporary file not found"); + return; + } + + try (InputStream input = new FileInputStream(file)) { + String contentType = "application/octet-stream"; + if (objectName.endsWith(".png")) { + contentType = "image/png"; + } else if (objectName.endsWith(".jpg") || objectName.endsWith(".jpeg")) { + contentType = "image/jpeg"; + } + + context.setResponseHeader("Content-Type", contentType); + context.setResponseHeader("Content-Disposition", "inline; filename=\"" + objectName + "\""); + + context.send(input); + } catch (IOException e) { + e.printStackTrace(); + context.setResponseCode(400).send("Error reading file"); + } finally { + file.delete(); + } + } + + @POST("") + public UserInitialSingleResponse insert(Context context) { + try { + AddUserInitialDto dto = new AddUserInitialDto(); + dto.setUserId(UUID.fromString(context.form("user_id").value())); + UserInitial existing = repository.findSingleByUserId(dto.getUserId()); + FileUpload fileUpload = context.file("file"); + dto.setFile(fileUpload); + + String originalFilename = fileUpload.getFileName(); + String fileExt = originalFilename.substring(originalFilename.lastIndexOf(".")); + String cephFileName = "signatures/" + UUID.randomUUID() + fileExt; + + File tempFile = File.createTempFile("upload-", fileExt); + try (OutputStream out = new FileOutputStream(tempFile)) { + out.write(fileUpload.bytes()); + } + + CephUtility cephUtility = context.require(CephUtility.class); + if (existing != null) { + boolean deleted = repository.delete(dto.getUserId()); + if (!deleted) { + return UserInitialSingleResponse.builder() + .code(1) + .message("Failed to delete existing data") + .data(null) + .build(); + } + } + + boolean uploaded = cephUtility.upload(cephFileName, tempFile.getAbsolutePath()); + + tempFile.delete(); + + if (!uploaded) { + return UserInitialSingleResponse.builder() + .code(1) + .message("Failed to upload to Ceph") + .data(null) + .build(); + } + + UserInitial item = new UserInitial(); + item.setId(UUID.randomUUID()); + item.setUserId(dto.getUserId()); + item.setFile(cephFileName); + item.setCreatedAt(LocalDateTime.now()); + item.setUpdatedAt(LocalDateTime.now()); + + boolean result = repository.insert(item); + + if (result) { + return UserInitialSingleResponse.builder() + .code(0) + .message("Success") + .data(item) + .build(); + } else { + return UserInitialSingleResponse.builder() + .code(1) + .message("Failed to insert data") + .data(null) + .build(); + } + + } catch (Exception e) { + e.printStackTrace(); + return UserInitialSingleResponse.builder() + .code(1) + .message("Exception: " + e.getMessage()) + .data(null) + .build(); + } + } + + + +} diff --git a/src/main/java/id/go/polri/tte/controllers/UserRoleController.java b/src/main/java/id/go/polri/tte/controllers/UserRoleController.java new file mode 100644 index 0000000..97871e1 --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/UserRoleController.java @@ -0,0 +1,141 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.dto.GetUserRoleDetailsDto; +import id.go.polri.tte.models.Role; +import id.go.polri.tte.models.User; +import id.go.polri.tte.models.UserRole; +import id.go.polri.tte.repositories.jdbi.*; +import id.go.polri.tte.responses.UserRoleListResponse; +import id.go.polri.tte.responses.UserRoleSingleResponse; +import id.go.polri.tte.responses.BasicResponse; +import io.jooby.Context; +import io.jooby.annotation.*; +import jakarta.inject.Inject; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.UUID; + +@Path("/api/v2/auth-service/user-roles") +public class UserRoleController { + private final UserRoleRepository repository; + private final UserRepository userRepository; + private final RoleRepository roleRepository; + @Inject + public UserRoleController(UserRoleRepository repository, + UserRepository userRepository, + RoleRepository roleRepository + ) { + this.repository = repository; + this.userRepository = userRepository; + this.roleRepository = roleRepository; + } + + @GET("") + public UserRoleListResponse findAll(Context context) { + if (context.queryMap().containsKey("limit") && context.queryMap().containsKey("offset")) { + int limit = context.query("limit").intValue(); + int offset = context.query("offset").intValue(); + List list = repository.findAll(limit, offset); + int recordsTotal = repository.count(); + return UserRoleListResponse.builder().code(0).message("Success").data(list) + .recordsTotal(recordsTotal).build(); + } + + if (context.queryMap().containsKey("userId")) { + String userId = context.query("userId").value(); + List list = repository.getByUserId(UUID.fromString(userId)); + return UserRoleListResponse.builder().code(0).message("Success").data(list).build(); + } + + if (context.queryMap().containsKey("roleId")) { + String roleId = context.query("roleId").value(); + List list = repository.findByRoleId(UUID.fromString(roleId)); + return UserRoleListResponse.builder().code(0).message("Success").data(list).build(); + } + + List list = repository.findAll(); + return UserRoleListResponse.builder().code(0).message("Success").data(list).build(); + } + + @GET("/{id}") + public UserRoleListResponse findById(@PathParam UUID id, Context context) { + List items = repository.getByUserId(id); + + if (items == null || items.isEmpty()) { + return UserRoleListResponse.builder() + .code(1) + .message("Data tidak ditemukan.") + .data(List.of()) + .recordsTotal(0) + .recordsFiltered(0) + .build(); + } + + int total = items.size(); + + return UserRoleListResponse.builder() + .code(0) + .message("Success") + .data(items) + .recordsTotal(total) + .recordsFiltered(total) + .build(); + } + + @POST("") + public UserRoleSingleResponse insert(Context context) { + UserRole item = context.body(UserRole.class); + UserRole existing = repository.findLatestByUserAndRoleId(item.getUserId(), item.getRoleId()); + User user_existing = userRepository.findById(item.getUserId()); + Role role_existing = roleRepository.findById(item.getRoleId()); + if (user_existing == null) { + String message = String.format("User dengan id '%s' tidak ditemukan.", item.getUserId()); + return UserRoleSingleResponse.builder().code(1).message(message).build(); + } + if (role_existing == null) { + String message = String.format("Role dengan id '%s' tidak ditemukan.", item.getRoleId()); + return UserRoleSingleResponse.builder().code(1).message(message).build(); + } + if (existing != null) { + return UserRoleSingleResponse.builder().code(1).message("User sudah memiliki role tersebut.").build(); + } + item.setId(UUID.randomUUID()); + item.setCreatedAt(LocalDateTime.now()); + item.setUpdatedAt(LocalDateTime.now()); + boolean result = repository.insert(item); + if (result) { + return UserRoleSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return UserRoleSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @PUT("/{id}") + public UserRoleSingleResponse update(@PathParam UUID id, Context context) { + UserRole item = context.body(UserRole.class); + UserRole oldData = repository.findById(id); + + item.setId(oldData.getId()); + item.setCreatedAt(oldData.getCreatedAt()); + item.setUpdatedAt(LocalDateTime.now()); + boolean result = repository.update(item, id); + + if (result) { + return UserRoleSingleResponse.builder().code(0).message("Success").data(item).build(); + } else { + return UserRoleSingleResponse.builder().code(1).message("Failed").data(null).build(); + } + } + + @DELETE("/{id}") + public BasicResponse delete(@PathParam UUID id) { + boolean result = repository.delete(id); + if (result) { + return BasicResponse.builder().code(0).message("Success").build(); + } else { + return BasicResponse.builder().code(1).message("Failed").build(); + } + } + +} diff --git a/src/main/java/id/go/polri/tte/controllers/UserSignatureController.java b/src/main/java/id/go/polri/tte/controllers/UserSignatureController.java new file mode 100644 index 0000000..ed5c89b --- /dev/null +++ b/src/main/java/id/go/polri/tte/controllers/UserSignatureController.java @@ -0,0 +1,148 @@ +package id.go.polri.tte.controllers; + +import id.go.polri.tte.dto.AddUserSignatureDto; +import id.go.polri.tte.models.UserSignature; +import id.go.polri.tte.repositories.jdbi.UserSignatureRepository; +import id.go.polri.tte.responses.UserSignatureSingleResponse; +import id.go.polri.tte.utility.CephUtility; +import io.jooby.Context; +import io.jooby.annotation.*; +import jakarta.inject.Inject; +import io.jooby.FileUpload; + +import java.io.*; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Path("/api/v2/auth-service/user-signature") +public class UserSignatureController { + private final UserSignatureRepository repository; + + @Inject + public UserSignatureController(UserSignatureRepository repository) { + this.repository = repository; + } + + @GET("/{id}") + public void downloadFile(@PathParam UUID id, Context context) { + UserSignature item = repository.findSingleByUserId(id); + if (item == null || item.getFile() == null) { + context.setResponseCode(404).send("File not found"); + return; + } + + String objectName = item.getFile(); + String tempPath = System.getProperty("java.io.tmpdir") + "/" + UUID.randomUUID(); + + CephUtility ceph = context.require(CephUtility.class); + boolean success = ceph.download(objectName, tempPath); + + if (!success) { + context.setResponseCode(400).send("Failed to download file from Ceph"); + return; + } + + File file = new File(tempPath); + if (!file.exists()) { + context.setResponseCode(404).send("Temporary file not found"); + return; + } + + try (InputStream input = new FileInputStream(file)) { + String contentType = "application/octet-stream"; + if (objectName.endsWith(".png")) { + contentType = "image/png"; + } else if (objectName.endsWith(".jpg") || objectName.endsWith(".jpeg")) { + contentType = "image/jpeg"; + } + + context.setResponseHeader("Content-Type", contentType); + context.setResponseHeader("Content-Disposition", "inline; filename=\"" + objectName + "\""); + + context.send(input); + } catch (IOException e) { + e.printStackTrace(); + context.setResponseCode(400).send("Error reading file"); + } finally { + file.delete(); + } + } + + @POST("") + public UserSignatureSingleResponse insert(Context context) { + try { + AddUserSignatureDto dto = new AddUserSignatureDto(); + dto.setUserId(UUID.fromString(context.form("user_id").value())); + UserSignature existing = repository.findSingleByUserId(dto.getUserId()); + FileUpload fileUpload = context.file("file"); + dto.setFile(fileUpload); + + String originalFilename = fileUpload.getFileName(); + String fileExt = originalFilename.substring(originalFilename.lastIndexOf(".")); + String cephFileName = "signatures/" + UUID.randomUUID() + fileExt; + + File tempFile = File.createTempFile("upload-", fileExt); + try (OutputStream out = new FileOutputStream(tempFile)) { + out.write(fileUpload.bytes()); + } + + CephUtility cephUtility = context.require(CephUtility.class); + if (existing != null) { + boolean deleted = repository.delete(dto.getUserId()); + if (!deleted) { + return UserSignatureSingleResponse.builder() + .code(400) + .message("Failed to delete existing data") + .data(null) + .build(); + } + } + + boolean uploaded = cephUtility.upload(cephFileName, tempFile.getAbsolutePath()); + + tempFile.delete(); + + if (!uploaded) { + return UserSignatureSingleResponse.builder() + .code(400) + .message("Failed to upload to Ceph") + .data(null) + .build(); + } + + UserSignature item = new UserSignature(); + item.setId(UUID.randomUUID()); + item.setUserId(dto.getUserId()); + item.setFile(cephFileName); + item.setCreatedAt(LocalDateTime.now()); + item.setUpdatedAt(LocalDateTime.now()); + + boolean result = repository.insert(item); + + if (result) { + return UserSignatureSingleResponse.builder() + .code(200) + .message("Success") + .data(item) + .build(); + } else { + return UserSignatureSingleResponse.builder() + .code(400) + .message("Failed to insert data") + .data(null) + .build(); + } + + } catch (Exception e) { + e.printStackTrace(); + return UserSignatureSingleResponse.builder() + .code(400) + .message("Exception: " + e.getMessage()) + .data(null) + .build(); + } + } + + +} diff --git a/src/main/java/id/go/polri/tte/dto/AddUserInitialDto.java b/src/main/java/id/go/polri/tte/dto/AddUserInitialDto.java new file mode 100644 index 0000000..e4ba2de --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/AddUserInitialDto.java @@ -0,0 +1,17 @@ +package id.go.polri.tte.dto; + +import io.jooby.FileUpload; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.UUID; + +@Data +public class AddUserInitialDto { + @NotBlank(message = "User ID tidak boleh kosong") + private UUID userId; + + @NotNull(message = "File Initial wajib diunggah") + private FileUpload file; +} diff --git a/src/main/java/id/go/polri/tte/dto/AddUserSignatureDto.java b/src/main/java/id/go/polri/tte/dto/AddUserSignatureDto.java new file mode 100644 index 0000000..85fbe1a --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/AddUserSignatureDto.java @@ -0,0 +1,20 @@ +package id.go.polri.tte.dto; + +import io.jooby.FileUpload; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +import lombok.Data; + +import java.util.UUID; + +@Data +public class AddUserSignatureDto { + @NotBlank(message = "User ID tidak boleh kosong") + private UUID userId; + + @NotNull(message = "File Signature wajib diunggah") + private FileUpload file; + + +} diff --git a/src/main/java/id/go/polri/tte/dto/ChangePasswordDto.java b/src/main/java/id/go/polri/tte/dto/ChangePasswordDto.java new file mode 100644 index 0000000..599d3f3 --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/ChangePasswordDto.java @@ -0,0 +1,11 @@ +package id.go.polri.tte.dto; +import lombok.Data; + +import java.util.UUID; + +@Data +public class ChangePasswordDto { + private UUID user_id; + private String oldpassword; + private String newpassword; +} diff --git a/src/main/java/id/go/polri/tte/dto/GetUserRoleDetailsDto.java b/src/main/java/id/go/polri/tte/dto/GetUserRoleDetailsDto.java new file mode 100644 index 0000000..ad553d5 --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/GetUserRoleDetailsDto.java @@ -0,0 +1,21 @@ +package id.go.polri.tte.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.UUID; + +@Data +public class GetUserRoleDetailsDto { + private UUID id; + private UUID userId; + private UUID roleId; + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime createdAt; + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime updatedAt; + @JsonProperty("role_name") + private String roleName; +} diff --git a/src/main/java/id/go/polri/tte/dto/LoginDto.java b/src/main/java/id/go/polri/tte/dto/LoginDto.java new file mode 100644 index 0000000..fb8301e --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/LoginDto.java @@ -0,0 +1,9 @@ +package id.go.polri.tte.dto; + +import lombok.Data; + +@Data +public class LoginDto { + private String email; + private String password; +} diff --git a/src/main/java/id/go/polri/tte/dto/NotificationWaDto.java b/src/main/java/id/go/polri/tte/dto/NotificationWaDto.java new file mode 100644 index 0000000..3337b00 --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/NotificationWaDto.java @@ -0,0 +1,10 @@ +package id.go.polri.tte.dto; + +import lombok.Data; + +@Data +public class NotificationWaDto { + private String id; + private String file_id; + private String signing_id; +} diff --git a/src/main/java/id/go/polri/tte/dto/RegistrasiEsignDto.java b/src/main/java/id/go/polri/tte/dto/RegistrasiEsignDto.java new file mode 100644 index 0000000..3c0dd7a --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/RegistrasiEsignDto.java @@ -0,0 +1,20 @@ +package id.go.polri.tte.dto; + +import jakarta.validation.constraints.Email; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import io.jooby.FileUpload; + +@Data +public class RegistrasiEsignDto { + + @NotBlank(message = "Nama tidak boleh kosong") + private String nama; + + @Email(message = "Format email tidak valid") + @NotBlank(message = "Email tidak boleh kosong") + private String email; + @NotNull(message = "Surat rekomendasi wajib diunggah") + private FileUpload SuratRekomendasi; +} diff --git a/src/main/java/id/go/polri/tte/dto/SendOtpDto.java b/src/main/java/id/go/polri/tte/dto/SendOtpDto.java new file mode 100644 index 0000000..138b7af --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/SendOtpDto.java @@ -0,0 +1,8 @@ +package id.go.polri.tte.dto; + +import lombok.Data; + +@Data +public class SendOtpDto { + private String email; +} diff --git a/src/main/java/id/go/polri/tte/dto/TopOrganizationDTO.java b/src/main/java/id/go/polri/tte/dto/TopOrganizationDTO.java new file mode 100644 index 0000000..8c1eca2 --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/TopOrganizationDTO.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.dto; + +public class TopOrganizationDTO { + private final String orgName; + private final int total; + + public TopOrganizationDTO(String orgName, int total) { + this.orgName = orgName; + this.total = total; + } + + public String getOrgName() { + return orgName; + } + + public int getTotalUsage() { + return total; + } +} diff --git a/src/main/java/id/go/polri/tte/dto/TopUsageUserDto.java b/src/main/java/id/go/polri/tte/dto/TopUsageUserDto.java new file mode 100644 index 0000000..4ec12e4 --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/TopUsageUserDto.java @@ -0,0 +1,40 @@ +package id.go.polri.tte.dto; + +import org.jdbi.v3.core.mapper.reflect.ColumnName; + +import java.util.UUID; + +public class TopUsageUserDto { + private final UUID userId; + private final String userName; + private final String nrp; + private final int total; + + public TopUsageUserDto( + @ColumnName("user_id") UUID userId, + @ColumnName("user_name") String userName, + @ColumnName("nrp") String nrp, + @ColumnName("total") int total + ) { + this.userId = userId; + this.userName = userName; + this.nrp = nrp; + this.total = total; + } + + public UUID getUserId() { + return userId; + } + + public String getUserName() { + return userName; + } + + public String getNrp() { + return nrp; + } + + public int getTotal() { + return total; + } +} diff --git a/src/main/java/id/go/polri/tte/dto/UserIdDto.java b/src/main/java/id/go/polri/tte/dto/UserIdDto.java new file mode 100644 index 0000000..c1160df --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/UserIdDto.java @@ -0,0 +1,10 @@ +package id.go.polri.tte.dto; + +import lombok.Data; + +import java.util.UUID; + +@Data +public class UserIdDto { + private UUID user_id; +} diff --git a/src/main/java/id/go/polri/tte/dto/UserRoleDto.java b/src/main/java/id/go/polri/tte/dto/UserRoleDto.java new file mode 100644 index 0000000..605de40 --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/UserRoleDto.java @@ -0,0 +1,14 @@ +package id.go.polri.tte.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.UUID; + +@Data +public class UserRoleDto { + @JsonProperty("user_id") + private UUID userId; + @JsonProperty("role_id") + private UUID roleId; +} diff --git a/src/main/java/id/go/polri/tte/dto/UserVerifyDto.java b/src/main/java/id/go/polri/tte/dto/UserVerifyDto.java new file mode 100644 index 0000000..931722e --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/UserVerifyDto.java @@ -0,0 +1,9 @@ +package id.go.polri.tte.dto; + +import lombok.Data; + +@Data +public class UserVerifyDto { + private String email; + private String password; +} diff --git a/src/main/java/id/go/polri/tte/dto/UserWithRolesDto.java b/src/main/java/id/go/polri/tte/dto/UserWithRolesDto.java new file mode 100644 index 0000000..46f2d9a --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/UserWithRolesDto.java @@ -0,0 +1,34 @@ +package id.go.polri.tte.dto; + +import lombok.Data; + +import java.util.List; +import java.util.UUID; + +@Data +public class UserWithRolesDto { + private UUID id; + private String name; + private String email; + private String phone; + private String email_verified_at; + private String phone_verified_at; + private String password; + private String nrp; + private String nik; + private String response_status; + private String pangkat; + private String nama_tanpa_gelar; + private String jabatan; + private Integer is_changed; + private List satuan; + private String pangkat_lengkap; + private String satker; + private String nama_aplikasi; + private String nama_pendek_dengan_gelar; + private String device_token; + private String created_at; + private String updated_at; + + private List roles; +} diff --git a/src/main/java/id/go/polri/tte/dto/VerifyOtpDto.java b/src/main/java/id/go/polri/tte/dto/VerifyOtpDto.java new file mode 100644 index 0000000..536164a --- /dev/null +++ b/src/main/java/id/go/polri/tte/dto/VerifyOtpDto.java @@ -0,0 +1,10 @@ +package id.go.polri.tte.dto; + +import lombok.Data; + +@Data +public class VerifyOtpDto { + private String email; + private String code; + +} diff --git a/src/main/java/id/go/polri/tte/jobs/AnalyticsSyncJob.java b/src/main/java/id/go/polri/tte/jobs/AnalyticsSyncJob.java new file mode 100644 index 0000000..b3e675b --- /dev/null +++ b/src/main/java/id/go/polri/tte/jobs/AnalyticsSyncJob.java @@ -0,0 +1,72 @@ +package id.go.polri.tte.jobs; + +import id.go.polri.tte.models.Application; +import id.go.polri.tte.models.ApplicationAnalytics; +import id.go.polri.tte.models.ApplicationMapping; +import id.go.polri.tte.models.threescale.DailyAnalyticResponse; +import id.go.polri.tte.repositories.api.ThreeScaleRepository; +import io.jooby.quartz.Scheduled; +import jakarta.inject.Inject; +import org.jdbi.v3.core.Jdbi; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.UUID; + +public class AnalyticsSyncJob implements Job { + + private final ThreeScaleRepository threeScaleRepository; + protected final Jdbi jdbi; + + @Inject + public AnalyticsSyncJob(ThreeScaleRepository threeScaleRepository, Jdbi jdbi) { + this.threeScaleRepository = threeScaleRepository; + this.jdbi = jdbi; + } + + @Override + @Scheduled("24h") + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + LocalDate today = LocalDate.now(); + String since = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + String metric = "hits"; + List applications = jdbi.withHandle(handle -> handle.registerRowMapper(Application.class, new Application.Mapper()) + .createQuery("select * from applications") + .mapTo(Application.class).list() ); + for (Application application : applications) { + List applicationMappings = jdbi.withHandle(handle -> handle.registerRowMapper(ApplicationMapping.class, new ApplicationMapping.Mapper()) + .createQuery("select * from application_mappings where application_id = :applicationId") + .bind("applicationId", application.getId()) + .mapTo(ApplicationMapping.class).list() ); + for (ApplicationMapping applicationMapping : applicationMappings) { + DailyAnalyticResponse dailyAnalyticResponse = threeScaleRepository.getDailyAnalytics(applicationMapping.getGatewayId(), since, metric); + if (dailyAnalyticResponse != null) { + List applicationAnalytics = jdbi.withHandle(handle -> handle.registerRowMapper(ApplicationAnalytics.class, new ApplicationAnalytics.Mapper()) + .createQuery("select * from application_analytics where hit_date = :hitDate and application_id = :applicationId and gateway_id = :gatewayId") + .bind("hitDate", today) + .bind("applicationId", application.getId()) + .bind("gatewayId", applicationMapping.getGatewayId()) + .mapTo(ApplicationAnalytics.class).list() ); + ApplicationAnalytics analytics = new ApplicationAnalytics(); + analytics.setValue(dailyAnalyticResponse.getTotal()); + analytics.setHitDate(today); + analytics.setApplicationId(application.getId()); + analytics.setGatewayId(applicationMapping.getGatewayId()); + if (applicationAnalytics.isEmpty()) { + analytics.setId(UUID.randomUUID().toString()); + jdbi.useHandle(handle -> handle.createUpdate("insert into application_analytics (id, value, hit_date, application_id, gateway_id) values (:id, :value, :hitDate, :applicationId, :gatewayId)").bindBean(analytics).execute()); + } else { + analytics.setId(applicationAnalytics.get(0).getId()); + jdbi.useHandle(handle -> handle.createUpdate("update application_analytics set value = :value, hit_date = :hitDate, application_id = :applicationId, gateway_id = :gatewayId where id = :id").bindBean(analytics).execute()); + } + } + + } + } + + } +} diff --git a/src/main/java/id/go/polri/tte/jobs/AnalyticsSyncSignerJob.java b/src/main/java/id/go/polri/tte/jobs/AnalyticsSyncSignerJob.java new file mode 100644 index 0000000..11e0770 --- /dev/null +++ b/src/main/java/id/go/polri/tte/jobs/AnalyticsSyncSignerJob.java @@ -0,0 +1,71 @@ +package id.go.polri.tte.jobs; + +import id.go.polri.tte.models.Application; +import id.go.polri.tte.models.ApplicationAnalytics; +import id.go.polri.tte.models.ApplicationMapping; +import id.go.polri.tte.models.threescale.DailyAnalyticResponse; +import id.go.polri.tte.repositories.api.ThreeScaleRepository; +import io.jooby.quartz.Scheduled; +import jakarta.inject.Inject; +import org.jdbi.v3.core.Jdbi; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.UUID; + +public class AnalyticsSyncSignerJob implements Job { + private final ThreeScaleRepository threeScaleRepository; + protected final Jdbi jdbi; + + @Inject + public AnalyticsSyncSignerJob(ThreeScaleRepository threeScaleRepository, Jdbi jdbi) { + this.threeScaleRepository = threeScaleRepository; + this.jdbi = jdbi; + } + + @Override + @Scheduled("24h") + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + LocalDate today = LocalDate.now(); + String since = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + String metric = "Signer"; + List applications = jdbi.withHandle(handle -> handle.registerRowMapper(Application.class, new Application.Mapper()) + .createQuery("select * from applications") + .mapTo(Application.class).list() ); + for (Application application : applications) { + List applicationMappings = jdbi.withHandle(handle -> handle.registerRowMapper(ApplicationMapping.class, new ApplicationMapping.Mapper()) + .createQuery("select * from application_mappings where application_id = :applicationId") + .bind("applicationId", application.getId()) + .mapTo(ApplicationMapping.class).list() ); + for (ApplicationMapping applicationMapping : applicationMappings) { + DailyAnalyticResponse dailyAnalyticResponse = threeScaleRepository.getDailyAnalytics(applicationMapping.getGatewayId(), since, metric); + if (dailyAnalyticResponse != null) { + List applicationAnalytics = jdbi.withHandle(handle -> handle.registerRowMapper(ApplicationAnalytics.class, new ApplicationAnalytics.Mapper()) + .createQuery("select * from application_analytics where hit_date = :hitDate and application_id = :applicationId and gateway_id = :gatewayId") + .bind("hitDate", today) + .bind("applicationId", application.getId()) + .bind("gatewayId", applicationMapping.getGatewayId()) + .mapTo(ApplicationAnalytics.class).list() ); + ApplicationAnalytics analytics = new ApplicationAnalytics(); + analytics.setValue(dailyAnalyticResponse.getTotal()); + analytics.setHitDate(today); + analytics.setApplicationId(application.getId()); + analytics.setGatewayId(applicationMapping.getGatewayId()); + if (applicationAnalytics.isEmpty()) { + analytics.setId(UUID.randomUUID().toString()); + jdbi.useHandle(handle -> handle.createUpdate("insert into application_analytics (id, value, hit_date, application_id, gateway_id) values (:id, :value, :hitDate, :applicationId, :gatewayId)").bindBean(analytics).execute()); + } else { + analytics.setId(applicationAnalytics.get(0).getId()); + jdbi.useHandle(handle -> handle.createUpdate("update application_analytics set value = :value, hit_date = :hitDate, application_id = :applicationId, gateway_id = :gatewayId where id = :id").bindBean(analytics).execute()); + } + } + + } + } + + } +} diff --git a/src/main/java/id/go/polri/tte/jobs/StatusBsreJob.java b/src/main/java/id/go/polri/tte/jobs/StatusBsreJob.java new file mode 100644 index 0000000..fd8af12 --- /dev/null +++ b/src/main/java/id/go/polri/tte/jobs/StatusBsreJob.java @@ -0,0 +1,35 @@ +package id.go.polri.tte.jobs; + +import id.go.polri.tte.services.StatusBsreService; +import io.jooby.quartz.Scheduled; +import jakarta.inject.Inject; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class StatusBsreJob implements Job { + + private static final Logger logger = LoggerFactory.getLogger(StatusBsreJob.class); + + private final StatusBsreService service; + + @Inject + public StatusBsreJob(StatusBsreService service) { + this.service = service; + } + + @Override + @Scheduled("0 0 0 * * ?") + public void execute(JobExecutionContext context) throws JobExecutionException { + logger.info("StatusBsreJob triggered"); + + if (service != null) { + logger.info("Running checkAllUserStatus..."); + service.checkAllUserStatus(1); + } else { + logger.error("StatusBsreService is not initialized."); + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/Application.java b/src/main/java/id/go/polri/tte/models/Application.java new file mode 100644 index 0000000..5bfdf47 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/Application.java @@ -0,0 +1,51 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Application { + + @JsonProperty("id") + private String id; + @JsonProperty("organization_id") + private String organizationId; + @JsonProperty("name") + private String name; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("updated_at") + private java.time.LocalDateTime updatedAt; + + public static class Mapper implements RowMapper { + + @Override + public Application map(ResultSet rs, StatementContext ctx) throws SQLException { + Application item = new Application(); + item.setId(rs.getString("id")); + item.setOrganizationId(rs.getString("organization_id")); + item.setName(rs.getString("name")); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/ApplicationAnalytics.java b/src/main/java/id/go/polri/tte/models/ApplicationAnalytics.java new file mode 100644 index 0000000..a982c1e --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/ApplicationAnalytics.java @@ -0,0 +1,47 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ApplicationAnalytics { + + @JsonProperty("id") + private String id; + @JsonProperty("application_id") + private String applicationId; + @JsonProperty("gateway_id") + private Long gatewayId; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + @JsonProperty("hit_date") + private java.time.LocalDate hitDate; + @JsonProperty("value") + private Integer value; + + public static class Mapper implements RowMapper { + + @Override + public ApplicationAnalytics map(ResultSet rs, StatementContext ctx) throws SQLException { + ApplicationAnalytics item = new ApplicationAnalytics(); + item.setId(rs.getString("id")); + item.setApplicationId(rs.getString("application_id")); + item.setGatewayId(rs.getLong("gateway_id")); + java.sql.Date hitDate = rs.getDate("hit_date"); + if (hitDate != null) { + item.setHitDate(hitDate.toLocalDate()); + } + item.setValue(rs.getInt("value")); + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/ApplicationMapping.java b/src/main/java/id/go/polri/tte/models/ApplicationMapping.java new file mode 100644 index 0000000..7aa113c --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/ApplicationMapping.java @@ -0,0 +1,36 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ApplicationMapping { + + @JsonProperty("id") + private String id; + @JsonProperty("application_id") + private String applicationId; + @JsonProperty("gateway_id") + private Long gatewayId; + + public static class Mapper implements RowMapper { + + @Override + public ApplicationMapping map(ResultSet rs, StatementContext ctx) throws SQLException { + ApplicationMapping item = new ApplicationMapping(); + item.setId(rs.getString("id")); + item.setApplicationId(rs.getString("application_id")); + item.setGatewayId(rs.getLong("gateway_id")); + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/BsreLog.java b/src/main/java/id/go/polri/tte/models/BsreLog.java new file mode 100644 index 0000000..9bb71ec --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/BsreLog.java @@ -0,0 +1,55 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BsreLog { + + @JsonProperty("id") + private UUID id; + @JsonProperty("nik") + private String nik; + @JsonProperty("nrp") + private String nrp; + @JsonProperty("message") + private String message; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("updated_at") + private java.time.LocalDateTime updatedAt; + + public static class Mapper implements RowMapper { + + @Override + public BsreLog map(ResultSet rs, StatementContext ctx) throws SQLException { + BsreLog item = new BsreLog(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setNik(rs.getString("nik")); + item.setNrp(rs.getString("nrp")); + item.setMessage(rs.getString("message")); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/OneTimePassword.java b/src/main/java/id/go/polri/tte/models/OneTimePassword.java new file mode 100644 index 0000000..6895864 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/OneTimePassword.java @@ -0,0 +1,66 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OneTimePassword { + + @JsonProperty("id") + private UUID id; + @JsonProperty("user_id") + private UUID userId; + @JsonProperty("code") + private String code; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("expired_at") + private java.time.LocalDateTime expiredAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("used_at") + private java.time.LocalDateTime usedAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("updated_at") + private java.time.LocalDateTime updatedAt; + + public static class Mapper implements RowMapper { + + @Override + public OneTimePassword map(ResultSet rs, StatementContext ctx) throws SQLException { + OneTimePassword item = new OneTimePassword(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setUserId(UUID.fromString(rs.getString("user_id"))); + item.setCode(rs.getString("code")); + java.sql.Timestamp expiredAt = rs.getTimestamp("expired_at"); + if (expiredAt != null) { + item.setExpiredAt(expiredAt.toLocalDateTime()); + } + java.sql.Timestamp usedAt = rs.getTimestamp("used_at"); + if (usedAt != null) { + item.setUsedAt(usedAt.toLocalDateTime()); + } + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/Organization.java b/src/main/java/id/go/polri/tte/models/Organization.java new file mode 100644 index 0000000..04ed9af --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/Organization.java @@ -0,0 +1,48 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Organization { + + @JsonProperty("id") + private String id; + @JsonProperty("name") + private String name; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("updated_at") + private java.time.LocalDateTime updatedAt; + + public static class Mapper implements RowMapper { + + @Override + public Organization map(ResultSet rs, StatementContext ctx) throws SQLException { + Organization item = new Organization(); + item.setId(rs.getString("id")); + item.setName(rs.getString("name")); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/OrganizationMapping.java b/src/main/java/id/go/polri/tte/models/OrganizationMapping.java new file mode 100644 index 0000000..636cf7b --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/OrganizationMapping.java @@ -0,0 +1,36 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class OrganizationMapping { + + @JsonProperty("id") + private String id; + @JsonProperty("organization_id") + private String organizationId; + @JsonProperty("gateway_id") + private Long gatewayId; + + public static class Mapper implements RowMapper { + + @Override + public OrganizationMapping map(ResultSet rs, StatementContext ctx) throws SQLException { + OrganizationMapping item = new OrganizationMapping(); + item.setId(rs.getString("id")); + item.setOrganizationId(rs.getString("organization_id")); + item.setGatewayId(rs.getLong("gateway_id")); + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/Role.java b/src/main/java/id/go/polri/tte/models/Role.java new file mode 100644 index 0000000..57624d6 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/Role.java @@ -0,0 +1,49 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Role { + + @JsonProperty("id") + private UUID id; + @JsonProperty("name") + private String name; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("updated_at") + private java.time.LocalDateTime updatedAt; + + public static class Mapper implements RowMapper { + + @Override + public Role map(ResultSet rs, StatementContext ctx) throws SQLException { + Role item = new Role(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setName(rs.getString("name")); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/UsageOrganizations.java b/src/main/java/id/go/polri/tte/models/UsageOrganizations.java new file mode 100644 index 0000000..9e02fa9 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/UsageOrganizations.java @@ -0,0 +1,42 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UsageOrganizations { + + @JsonProperty("id") + private UUID id; + @JsonProperty("org_name") + private String orgName; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + + public static class Mapper implements RowMapper { + + @Override + public UsageOrganizations map(ResultSet rs, StatementContext ctx) throws SQLException { + UsageOrganizations item = new UsageOrganizations(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setOrgName(rs.getString("org_name")); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/UsageUsers.java b/src/main/java/id/go/polri/tte/models/UsageUsers.java new file mode 100644 index 0000000..f604b7e --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/UsageUsers.java @@ -0,0 +1,42 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UsageUsers { + + @JsonProperty("id") + private UUID id; + @JsonProperty("user_id") + private UUID userId; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + + public static class Mapper implements RowMapper { + + @Override + public UsageUsers map(ResultSet rs, StatementContext ctx) throws SQLException { + UsageUsers item = new UsageUsers(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setUserId(UUID.fromString(rs.getString("user_id"))); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/User.java b/src/main/java/id/go/polri/tte/models/User.java new file mode 100644 index 0000000..0a7cb62 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/User.java @@ -0,0 +1,268 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.core.JsonProcessingException; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.UUID; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class User { + + @JsonProperty("id") + private UUID id; + @JsonProperty("name") + private String name; + @JsonProperty("email") + private String email; + @JsonProperty("phone") + private String phone; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("email_verified_at") + private java.time.LocalDateTime emailVerifiedAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("phone_verified_at") + private java.time.LocalDateTime phoneVerifiedAt; + @JsonProperty("password") + private String password; + @JsonProperty("nrp") + private String nrp; + @JsonProperty("nik") + private String nik; + @JsonProperty("response_status") + private String responseStatus; + @JsonProperty("pangkat") + private String pangkat; + @JsonProperty("nama_tanpa_gelar") + private String namaTanpaGelar; + @JsonProperty("jabatan") + private String jabatan; + @JsonProperty("is_changed") + private Integer is_changed; + @JsonProperty("satuan") + private List satuan; + @JsonProperty("pangkat_lengkap") + private String pangkatLengkap; + @JsonProperty("satker") + private String satker; + @JsonProperty("nama_aplikasi") + private String namaAplikasi; + @JsonProperty("nama_pendek_dengan_gelar") + private String namaPendekDenganGelar; + @JsonProperty("device_token") + private String deviceToken; + @JsonProperty("status_account") + private String statusAccount; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("updated_at") + private java.time.LocalDateTime updatedAt; + @JsonProperty("roles") + private List roles; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("last_signin") + private java.time.LocalDateTime lastSignin; + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + public static class RolesMapper implements RowMapper { + @Override + public User map(ResultSet rs, StatementContext ctx) throws SQLException { + User item = new User(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setName(rs.getString("name")); + item.setEmail(rs.getString("email")); + item.setPhone(rs.getString("phone")); + java.sql.Timestamp emailVerifiedAt = rs.getTimestamp("email_verified_at"); + if (emailVerifiedAt != null) { + item.setEmailVerifiedAt(emailVerifiedAt.toLocalDateTime()); + } + java.sql.Timestamp phoneVerifiedAt = rs.getTimestamp("phone_verified_at"); + if (phoneVerifiedAt != null) { + item.setPhoneVerifiedAt(phoneVerifiedAt.toLocalDateTime()); + } + item.setPassword(rs.getString("password")); + item.setNrp(rs.getString("nrp")); + item.setNik(rs.getString("nik")); + item.setResponseStatus(rs.getString("response_status")); + item.setPangkat(rs.getString("pangkat")); + item.setNamaTanpaGelar(rs.getString("nama_tanpa_gelar")); + item.setJabatan(rs.getString("jabatan")); + item.setIs_changed(rs.getInt("is_changed")); + item.setSatuan(parseSatuan(rs.getString("satuan"))); + item.setPangkatLengkap(rs.getString("pangkat_lengkap")); + item.setSatker(rs.getString("satker")); + item.setNamaAplikasi(rs.getString("nama_aplikasi")); + item.setNamaPendekDenganGelar(rs.getString("nama_pendek_dengan_gelar")); + item.setDeviceToken(rs.getString("device_token")); + item.setStatusAccount(rs.getString("status_account")); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + item.setRoles(parseRoles(rs.getArray("roles"))); + java.sql.Timestamp lastSignin = rs.getTimestamp("last_signin"); + if (lastSignin != null) { + item.setLastSignin(lastSignin.toLocalDateTime()); + } + return item; + } + } + + public static class NewMapper implements RowMapper { + @Override + public User map(ResultSet rs, StatementContext ctx) throws SQLException { + User item = new User(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setName(rs.getString("name")); + item.setEmail(rs.getString("email")); + item.setPhone(rs.getString("phone")); + java.sql.Timestamp emailVerifiedAt = rs.getTimestamp("email_verified_at"); + if (emailVerifiedAt != null) { + item.setEmailVerifiedAt(emailVerifiedAt.toLocalDateTime()); + } + java.sql.Timestamp phoneVerifiedAt = rs.getTimestamp("phone_verified_at"); + if (phoneVerifiedAt != null) { + item.setPhoneVerifiedAt(phoneVerifiedAt.toLocalDateTime()); + } + item.setPassword(rs.getString("password")); + item.setNrp(rs.getString("nrp")); + item.setNik(rs.getString("nik")); + item.setResponseStatus(rs.getString("response_status")); + item.setPangkat(rs.getString("pangkat")); + item.setNamaTanpaGelar(rs.getString("nama_tanpa_gelar")); + item.setJabatan(rs.getString("jabatan")); + item.setIs_changed(rs.getInt("is_changed")); + item.setSatuan(parseSatuan(rs.getString("satuan"))); + item.setPangkatLengkap(rs.getString("pangkat_lengkap")); + item.setSatker(rs.getString("satker")); + item.setNamaAplikasi(rs.getString("nama_aplikasi")); + item.setNamaPendekDenganGelar(rs.getString("nama_pendek_dengan_gelar")); + item.setDeviceToken(rs.getString("device_token")); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + + java.sql.Timestamp lastSignin = rs.getTimestamp("last_signin"); + if (lastSignin != null) { + item.setLastSignin(lastSignin.toLocalDateTime()); + } + item.setStatusAccount(rs.getString("status_account")); + return item; + } + } + + public static class Mapper implements RowMapper { + @Override + public User map(ResultSet rs, StatementContext ctx) throws SQLException { + User item = new User(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setName(rs.getString("name")); + item.setEmail(rs.getString("email")); + item.setPhone(rs.getString("phone")); + java.sql.Timestamp emailVerifiedAt = rs.getTimestamp("email_verified_at"); + if (emailVerifiedAt != null) { + item.setEmailVerifiedAt(emailVerifiedAt.toLocalDateTime()); + } + java.sql.Timestamp phoneVerifiedAt = rs.getTimestamp("phone_verified_at"); + if (phoneVerifiedAt != null) { + item.setPhoneVerifiedAt(phoneVerifiedAt.toLocalDateTime()); + } + item.setPassword(rs.getString("password")); + item.setNrp(rs.getString("nrp")); + item.setNik(rs.getString("nik")); + item.setResponseStatus(rs.getString("response_status")); + item.setPangkat(rs.getString("pangkat")); + item.setNamaTanpaGelar(rs.getString("nama_tanpa_gelar")); + item.setJabatan(rs.getString("jabatan")); + item.setIs_changed(rs.getInt("is_changed")); + item.setSatuan(parseSatuan(rs.getString("satuan"))); + item.setPangkatLengkap(rs.getString("pangkat_lengkap")); + item.setSatker(rs.getString("satker")); + item.setNamaAplikasi(rs.getString("nama_aplikasi")); + item.setNamaPendekDenganGelar(rs.getString("nama_pendek_dengan_gelar")); + item.setDeviceToken(rs.getString("device_token")); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + item.setStatusAccount(rs.getString("status_account")); + return item; + } + } + + private static List parseSatuan(String satuanString) { + if (satuanString == null || satuanString.isEmpty()) { + return null; + } + try { + return objectMapper.readValue(satuanString, List.class); + } catch (JsonProcessingException e) { + e.printStackTrace(); + return null; + } + } + + public static String convertSatuanToJson(List satuan) throws JsonProcessingException { + if (satuan == null) { + return null; + } + return objectMapper.writeValueAsString(satuan); + } + + private static List parseRoles(java.sql.Array rolesArray) throws SQLException { + if (rolesArray == null) { + return null; + } + String[] roles = (String[]) rolesArray.getArray(); + return Arrays.asList(roles); + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class ResponseStatusCount { + private String responseStatus; + private int jumlah; + + public static class Mapper implements RowMapper { + public Mapper() {} // wajib ada constructor default + + @Override + public ResponseStatusCount map(ResultSet rs, StatementContext ctx) throws SQLException { + ResponseStatusCount count = new ResponseStatusCount(); + count.setResponseStatus(rs.getString("response_status")); + count.setJumlah(rs.getInt("jumlah")); + return count; + } + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/UserInitial.java b/src/main/java/id/go/polri/tte/models/UserInitial.java new file mode 100644 index 0000000..f228c7c --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/UserInitial.java @@ -0,0 +1,52 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserInitial { + + @JsonProperty("id") + private UUID id; + @JsonProperty("user_id") + private UUID userId; + @JsonProperty("file") + private String file; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("updated_at") + private java.time.LocalDateTime updatedAt; + + public static class Mapper implements RowMapper { + + @Override + public UserInitial map(ResultSet rs, StatementContext ctx) throws SQLException { + UserInitial item = new UserInitial(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setUserId(UUID.fromString(rs.getString("user_id"))); + item.setFile(rs.getString("file")); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/UserLogs.java b/src/main/java/id/go/polri/tte/models/UserLogs.java new file mode 100644 index 0000000..5e0e1a7 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/UserLogs.java @@ -0,0 +1,42 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserLogs { + + @JsonProperty("id") + private UUID id; + @JsonProperty("user_id") + private UUID userId; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("last_signin") + private java.time.LocalDateTime lastSignin; + + public static class Mapper implements RowMapper { + + @Override + public UserLogs map(ResultSet rs, StatementContext ctx) throws SQLException { + UserLogs item = new UserLogs(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setUserId(UUID.fromString(rs.getString("user_id"))); + java.sql.Timestamp lastSignin = rs.getTimestamp("last_signin"); + if (lastSignin != null) { + item.setLastSignin(lastSignin.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/UserRole.java b/src/main/java/id/go/polri/tte/models/UserRole.java new file mode 100644 index 0000000..bd6cac7 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/UserRole.java @@ -0,0 +1,52 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserRole { + + @JsonProperty("id") + private UUID id; + @JsonProperty("user_id") + private UUID userId; + @JsonProperty("role_id") + private UUID roleId; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("updated_at") + private java.time.LocalDateTime updatedAt; + + public static class Mapper implements RowMapper { + + @Override + public UserRole map(ResultSet rs, StatementContext ctx) throws SQLException { + UserRole item = new UserRole(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setUserId(UUID.fromString(rs.getString("user_id"))); + item.setRoleId(UUID.fromString(rs.getString("role_id"))); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/UserSignature.java b/src/main/java/id/go/polri/tte/models/UserSignature.java new file mode 100644 index 0000000..4780ce9 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/UserSignature.java @@ -0,0 +1,52 @@ +package id.go.polri.tte.models; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserSignature { + + @JsonProperty("id") + private UUID id; + @JsonProperty("user_id") + private UUID userId; + @JsonProperty("file") + private String file; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("created_at") + private java.time.LocalDateTime createdAt; + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") + @JsonProperty("updated_at") + private java.time.LocalDateTime updatedAt; + + public static class Mapper implements RowMapper { + + @Override + public UserSignature map(ResultSet rs, StatementContext ctx) throws SQLException { + UserSignature item = new UserSignature(); + item.setId(UUID.fromString(rs.getString("id"))); + item.setUserId(UUID.fromString(rs.getString("user_id"))); + item.setFile(rs.getString("file")); + java.sql.Timestamp createdAt = rs.getTimestamp("created_at"); + if (createdAt != null) { + item.setCreatedAt(createdAt.toLocalDateTime()); + } + java.sql.Timestamp updatedAt = rs.getTimestamp("updated_at"); + if (updatedAt != null) { + item.setUpdatedAt(updatedAt.toLocalDateTime()); + } + return item; + } + } +} diff --git a/src/main/java/id/go/polri/tte/models/login/User.java b/src/main/java/id/go/polri/tte/models/login/User.java new file mode 100644 index 0000000..ce03404 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/login/User.java @@ -0,0 +1,11 @@ +package id.go.polri.tte.models.login; +import lombok.Data; + +@Data +public class User { + private String id; + private String name; + private String email; + private String phone; + private String[] roles; +} diff --git a/src/main/java/id/go/polri/tte/models/threescale/Account.java b/src/main/java/id/go/polri/tte/models/threescale/Account.java new file mode 100644 index 0000000..b7a5ac3 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/threescale/Account.java @@ -0,0 +1,10 @@ +package id.go.polri.tte.models.threescale; + +import lombok.Data; + +@Data +public class Account{ + private String name; + private String link; + private int id; +} \ No newline at end of file diff --git a/src/main/java/id/go/polri/tte/models/threescale/Application.java b/src/main/java/id/go/polri/tte/models/threescale/Application.java new file mode 100644 index 0000000..c04f191 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/threescale/Application.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.models.threescale; + +import lombok.Data; + +@Data +public class Application{ + private Service service; + private String name; + private String link; + private String description; + private int id; + private String state; + private Plan plan; + private Account account; +} \ No newline at end of file diff --git a/src/main/java/id/go/polri/tte/models/threescale/DailyAnalyticResponse.java b/src/main/java/id/go/polri/tte/models/threescale/DailyAnalyticResponse.java new file mode 100644 index 0000000..441a1e9 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/threescale/DailyAnalyticResponse.java @@ -0,0 +1,13 @@ +package id.go.polri.tte.models.threescale; + +import java.util.List; +import lombok.Data; + +@Data +public class DailyAnalyticResponse{ + private Period period; + private int total; + private Application application; + private Metric metric; + private List values; +} \ No newline at end of file diff --git a/src/main/java/id/go/polri/tte/models/threescale/Event.java b/src/main/java/id/go/polri/tte/models/threescale/Event.java new file mode 100644 index 0000000..fb0114f --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/threescale/Event.java @@ -0,0 +1,11 @@ +package id.go.polri.tte.models.threescale; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class Event { + private String action; + private String type; +} diff --git a/src/main/java/id/go/polri/tte/models/threescale/Metric.java b/src/main/java/id/go/polri/tte/models/threescale/Metric.java new file mode 100644 index 0000000..8f795cb --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/threescale/Metric.java @@ -0,0 +1,13 @@ +package id.go.polri.tte.models.threescale; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class Metric{ + private String unit; + @JsonProperty("system_name") + private String systemName; + private String name; + private int id; +} \ No newline at end of file diff --git a/src/main/java/id/go/polri/tte/models/threescale/Period.java b/src/main/java/id/go/polri/tte/models/threescale/Period.java new file mode 100644 index 0000000..79f77ca --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/threescale/Period.java @@ -0,0 +1,12 @@ +package id.go.polri.tte.models.threescale; + +import lombok.Data; + +@Data +public class Period{ + private String timezone; + private String granularity; + private String name; + private String until; + private String since; +} \ No newline at end of file diff --git a/src/main/java/id/go/polri/tte/models/threescale/Plan.java b/src/main/java/id/go/polri/tte/models/threescale/Plan.java new file mode 100644 index 0000000..7fe44e7 --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/threescale/Plan.java @@ -0,0 +1,9 @@ +package id.go.polri.tte.models.threescale; + +import lombok.Data; + +@Data +public class Plan{ + private String name; + private int id; +} \ No newline at end of file diff --git a/src/main/java/id/go/polri/tte/models/threescale/Service.java b/src/main/java/id/go/polri/tte/models/threescale/Service.java new file mode 100644 index 0000000..6974b3b --- /dev/null +++ b/src/main/java/id/go/polri/tte/models/threescale/Service.java @@ -0,0 +1,8 @@ +package id.go.polri.tte.models.threescale; + +import lombok.Data; + +@Data +public class Service{ + private int id; +} \ No newline at end of file diff --git a/src/main/java/id/go/polri/tte/module/CephModule.java b/src/main/java/id/go/polri/tte/module/CephModule.java new file mode 100644 index 0000000..157f7c7 --- /dev/null +++ b/src/main/java/id/go/polri/tte/module/CephModule.java @@ -0,0 +1,21 @@ +package id.go.polri.tte.module; + +import com.typesafe.config.Config; +import id.go.polri.tte.utility.CephUtility; +import io.jooby.Extension; +import io.jooby.Jooby; +import org.jetbrains.annotations.NotNull; + +public class CephModule implements Extension { + @Override + public void install(@NotNull Jooby application) throws Exception { + Config config = application.getConfig(); + String endpoint = config.getString("ceph.endpoint"); + String accessKey = config.getString("ceph.accessKey"); + String secretKey = config.getString("ceph.secretKey"); + String bucketName = config.getString("ceph.bucketName"); + + CephUtility cephUtility = new CephUtility(endpoint, accessKey, secretKey, bucketName); + application.getServices().put(CephUtility.class, cephUtility); + } +} diff --git a/src/main/java/id/go/polri/tte/module/EmailModule.java b/src/main/java/id/go/polri/tte/module/EmailModule.java new file mode 100644 index 0000000..6d977e0 --- /dev/null +++ b/src/main/java/id/go/polri/tte/module/EmailModule.java @@ -0,0 +1,24 @@ +package id.go.polri.tte.module; + +import id.go.polri.tte.services.EmailService; +import io.jooby.Extension; +import io.jooby.Jooby; +import org.jetbrains.annotations.NotNull; + + +public class EmailModule implements Extension { + + @Override + public void install(@NotNull Jooby application) throws Exception { + String username = application.getConfig().getString("email.username"); + String password = application.getConfig().getString("email.password"); + String host = application.getConfig().getString("email.host"); + int port = application.getConfig().getInt("email.port"); + String encryption = application.getConfig().getString("email.encryption"); + String fromAddress = application.getConfig().getString("email.from_address"); + String fromName = application.getConfig().getString("email.from_name"); + + EmailService emailService = new EmailService(username, password, host, port, encryption, fromAddress, fromName); + application.getServices().put(EmailService.class, emailService); + } +} diff --git a/src/main/java/id/go/polri/tte/module/EsignModule.java b/src/main/java/id/go/polri/tte/module/EsignModule.java new file mode 100644 index 0000000..c232325 --- /dev/null +++ b/src/main/java/id/go/polri/tte/module/EsignModule.java @@ -0,0 +1,18 @@ +package id.go.polri.tte.module; + +import id.go.polri.tte.repositories.api.EsignRepository; +import io.jooby.Extension; +import io.jooby.Jooby; +import org.jetbrains.annotations.NotNull; + +public class EsignModule implements Extension { + + @Override + public void install(@NotNull Jooby application) throws Exception { + String baseUrl = application.getConfig().getString("esign.baseUrl"); + String username = application.getConfig().getString("esign.username"); + String password = application.getConfig().getString("esign.password"); + EsignRepository esignRepository = new EsignRepository(baseUrl, username, password); + application.getServices().put(EsignRepository.class, esignRepository); + } +} diff --git a/src/main/java/id/go/polri/tte/module/JwtModule.java b/src/main/java/id/go/polri/tte/module/JwtModule.java new file mode 100644 index 0000000..fe78c32 --- /dev/null +++ b/src/main/java/id/go/polri/tte/module/JwtModule.java @@ -0,0 +1,18 @@ +package id.go.polri.tte.module; + +import com.typesafe.config.Config; +import id.go.polri.tte.utility.JwtUtil; +import io.jooby.Extension; +import io.jooby.Jooby; +import org.jetbrains.annotations.NotNull; + +public class JwtModule implements Extension { + @Override + public void install(@NotNull Jooby application) throws Exception { + Config config = application.getConfig(); + String secret = config.getString("jwt.secret"); + Long expirationTime = config.getLong("jwt.expiration"); + JwtUtil jwtUtil = new JwtUtil(secret, expirationTime); + application.getServices().put(JwtUtil.class, jwtUtil); + } +} diff --git a/src/main/java/id/go/polri/tte/module/NotificationModule.java b/src/main/java/id/go/polri/tte/module/NotificationModule.java new file mode 100644 index 0000000..680566b --- /dev/null +++ b/src/main/java/id/go/polri/tte/module/NotificationModule.java @@ -0,0 +1,24 @@ +package id.go.polri.tte.module; + +import id.go.polri.tte.services.*; +import io.jooby.Extension; +import io.jooby.Jooby; +import org.jetbrains.annotations.NotNull; + +public class NotificationModule implements Extension { + + @Override + public void install(@NotNull Jooby application) throws Exception { + String username = application.getConfig().getString("email.username"); + String password = application.getConfig().getString("email.password"); + String host = application.getConfig().getString("email.host"); + int port = application.getConfig().getInt("email.port"); + String encryption = application.getConfig().getString("email.encryption"); + String fromAddress = application.getConfig().getString("email.from_address"); + String fromName = application.getConfig().getString("email.from_name"); + String otpApiBaseUrl = application.getConfig().getString("OTP_API_BASE_URL"); + String otpApiToken = application.getConfig().getString("OTP_API_TOKEN"); + NotificationService notificationService = new NotificationService(username, password, host, port, encryption, fromAddress, fromName, otpApiBaseUrl, otpApiToken); + application.getServices().put(NotificationService.class, notificationService); + } +} diff --git a/src/main/java/id/go/polri/tte/module/SippModule.java b/src/main/java/id/go/polri/tte/module/SippModule.java new file mode 100644 index 0000000..bbf5845 --- /dev/null +++ b/src/main/java/id/go/polri/tte/module/SippModule.java @@ -0,0 +1,18 @@ +package id.go.polri.tte.module; + +import id.go.polri.tte.repositories.api.SippRepository; +import io.jooby.Extension; +import io.jooby.Jooby; +import org.jetbrains.annotations.NotNull; + +public class SippModule implements Extension { + + @Override + public void install(@NotNull Jooby application) throws Exception { + String baseUrl = application.getConfig().getString("sipp.baseUrl"); + String auth = application.getConfig().getString("sipp.auth"); + String cid = application.getConfig().getString("sipp.cid"); + SippRepository sippRepository = new SippRepository(baseUrl, auth, cid); + application.getServices().put(SippRepository.class, sippRepository); + } +} diff --git a/src/main/java/id/go/polri/tte/module/StatusBsreModule.java b/src/main/java/id/go/polri/tte/module/StatusBsreModule.java new file mode 100644 index 0000000..27ed003 --- /dev/null +++ b/src/main/java/id/go/polri/tte/module/StatusBsreModule.java @@ -0,0 +1,35 @@ +package id.go.polri.tte.module; + +import id.go.polri.tte.models.User; +import id.go.polri.tte.repositories.jdbi.UserRepository; +import id.go.polri.tte.services.StatusBsreService; +import io.jooby.Extension; +import io.jooby.Jooby; +import org.jdbi.v3.core.Jdbi; +import org.jdbi.v3.core.mapper.reflect.BeanMapper; +import org.jetbrains.annotations.NotNull; + +public class StatusBsreModule implements Extension { + + @Override + public void install(@NotNull Jooby application) throws Exception { + + // Create Jdbi instance + Jdbi jdbi = application.require(Jdbi.class); + + jdbi.registerRowMapper(BeanMapper.factory(User.class)); + + // Register Jdbi to the service registry + application.getServices().put(Jdbi.class, jdbi); + + // Retrieve other configurations (example) + String bsreApiUrl = application.getConfig().getString("bsre.baseUrl"); + String username = application.getConfig().getString("bsre.username"); + String password = application.getConfig().getString("bsre.password"); + int delayInSeconds = application.getConfig().getInt("bsre.delayInSeconds"); + + // Create and register the StatusBsreService + StatusBsreService statusBsreService = new StatusBsreService(bsreApiUrl, username, password, delayInSeconds, jdbi); + application.getServices().put(StatusBsreService.class, statusBsreService); + } +} diff --git a/src/main/java/id/go/polri/tte/module/ThreeScaleModule.java b/src/main/java/id/go/polri/tte/module/ThreeScaleModule.java new file mode 100644 index 0000000..1de409d --- /dev/null +++ b/src/main/java/id/go/polri/tte/module/ThreeScaleModule.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.module; + +import com.typesafe.config.Config; +import id.go.polri.tte.repositories.api.ThreeScaleRepository; +import io.jooby.Extension; +import io.jooby.Jooby; +import org.jetbrains.annotations.NotNull; + +public class ThreeScaleModule implements Extension { + @Override + public void install(@NotNull Jooby application) throws Exception { + Config config = application.getConfig(); + String baseUrl = config.getString("threescale.baseUrl"); + String token = config.getString("threescale.token"); + + ThreeScaleRepository threeScaleRepository = new ThreeScaleRepository(baseUrl, token); + application.getServices().put(ThreeScaleRepository.class, threeScaleRepository); + } +} \ No newline at end of file diff --git a/src/main/java/id/go/polri/tte/repositories/api/EsignRepository.java b/src/main/java/id/go/polri/tte/repositories/api/EsignRepository.java new file mode 100644 index 0000000..8c03377 --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/api/EsignRepository.java @@ -0,0 +1,120 @@ +package id.go.polri.tte.repositories.api; + +import id.go.polri.tte.dto.RegistrasiEsignDto; +import io.jooby.FileUpload; +import org.asynchttpclient.*; +import org.asynchttpclient.request.body.multipart.FilePart; +import org.asynchttpclient.request.body.multipart.StringPart; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; + +import static org.asynchttpclient.Dsl.asyncHttpClient; + +public class EsignRepository { + private static final Logger logger = LoggerFactory.getLogger(EsignRepository.class); + + private final String baseUrl; + private final String username; + private final String password; + + public EsignRepository(String baseUrl, String username, String password) { + this.baseUrl = baseUrl; + this.username = username; + this.password = password; + } + + public String registrasi(RegistrasiEsignDto dto) { + List tempFiles = new ArrayList<>(); + try { + RequestBuilder requestBuilder = new RequestBuilder("POST"); + requestBuilder.setUrl(baseUrl + "/api/user/registrasi"); + String auth = username + ":" + password; + String encodedAuth = java.util.Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8)); + requestBuilder.addHeader("Authorization", "Basic " + encodedAuth); + + // Add string parts + requestBuilder.addBodyPart(new StringPart("nama", dto.getNama(), "text/plain", StandardCharsets.UTF_8, null)); + requestBuilder.addBodyPart(new StringPart("email", dto.getEmail(), "text/plain", StandardCharsets.UTF_8, null)); + + // Add file parts + if (dto.getSuratRekomendasi() != null) { + File suratFile = convertFileUploadToFile(dto.getSuratRekomendasi()); + tempFiles.add(suratFile); + requestBuilder.addBodyPart(new FilePart("surat_rekomendasi", suratFile, "application/pdf", null, dto.getSuratRekomendasi().getFileName())); + } + + // Execute request + try (AsyncHttpClient client = asyncHttpClient() ) { + Response response = client.executeRequest(requestBuilder.build()).toCompletableFuture().get(); + logger.info("Response from eSign API: {}", response.getResponseBody()); + return response.getResponseBody(); + } + } catch (IOException | ExecutionException | InterruptedException e) { + logger.error("Error while registering user to eSign API: {}", e.getMessage(), e); + return "{\"error\": \"Gagal registrasi ke eSign API. Detail: " + e.getMessage() + "\"}"; + } finally { + // Clean up temporary files + for (File file : tempFiles) { + if (file != null && file.exists()) { + boolean deleted = file.delete(); + if (!deleted) { + logger.warn("Temporary file {} could not be deleted.", file.getAbsolutePath()); + } + } + } + } + } + + public String uploadKeystore(FileUpload keystore, String password, String nik) { + File tempFile = null; + try { + RequestBuilder requestBuilder = new RequestBuilder("POST"); + requestBuilder.setUrl(baseUrl + "/api/user/keystore"); + String auth = username + ":" + this.password; + String encodedAuth = java.util.Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8)); + requestBuilder.addHeader("Authorization", "Basic " + encodedAuth); + + // Convert keystore file + tempFile = convertFileUploadToFile(keystore); + requestBuilder.addBodyPart(new FilePart("keystore", tempFile, "application/x-pkcs12", null, keystore.getFileName())); + + // Add string fields + requestBuilder.addBodyPart(new StringPart("password", password, "text/plain", StandardCharsets.UTF_8, null)); + requestBuilder.addBodyPart(new StringPart("nik", nik, "text/plain", StandardCharsets.UTF_8, null)); + + // Execute request + try (AsyncHttpClient client = asyncHttpClient() ) { + Response response = client.executeRequest(requestBuilder.build()).toCompletableFuture().get(); + logger.info("Response from eSign keystore upload: {}", response.getResponseBody()); + return response.getResponseBody(); + } + } catch (IOException | ExecutionException | InterruptedException e) { + logger.error("Error uploading keystore to eSign API: {}", e.getMessage(), e); + return "{\"error\": \"Gagal upload keystore ke eSign API. Detail: " + e.getMessage() + "\"}"; + } finally { + // Clean up temporary file + if (tempFile != null && tempFile.exists()) { + boolean deleted = tempFile.delete(); + if (!deleted) { + logger.warn("Temporary keystore file {} could not be deleted.", tempFile.getAbsolutePath()); + } + } + } + } + + private File convertFileUploadToFile(FileUpload fileUpload) throws IOException { + File tempFile = File.createTempFile("upload-", "-" + fileUpload.getFileName()); + try (FileOutputStream fos = new FileOutputStream(tempFile)) { + fos.write(fileUpload.bytes()); + } + return tempFile; + } +} diff --git a/src/main/java/id/go/polri/tte/repositories/api/SippRepository.java b/src/main/java/id/go/polri/tte/repositories/api/SippRepository.java new file mode 100644 index 0000000..21fc82e --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/api/SippRepository.java @@ -0,0 +1,60 @@ +package id.go.polri.tte.repositories.api; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.asynchttpclient.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.ExecutionException; + +import static org.asynchttpclient.Dsl.asyncHttpClient; + +public class SippRepository { + + private static final Logger logger = LoggerFactory.getLogger(SippRepository.class); + private final String baseUrl; + private final String cid; + private final String auth; + private final ObjectMapper objectMapper; + + public SippRepository(String baseUrl, String auth, String cid) { + this.baseUrl = baseUrl; + this.cid = cid; + this.auth = auth; + this.objectMapper = new ObjectMapper(); + } + + public JsonNode findByNrp(String nrp) { + try { + + Request request = new RequestBuilder("GET") + .setUrl(baseUrl + "?nrp=" + nrp) + .addHeader("cid", cid) + .addHeader("Authorization", auth ) + .build(); + + try (AsyncHttpClient client = asyncHttpClient() ) { + Response response = client.executeRequest(request).toCompletableFuture().get(); + if (response.getStatusCode() == 200) { + String rawResponse = response.getResponseBody(); + logger.info("Raw response from SIPP API: {}", rawResponse); + JsonNode jsonResponse = objectMapper.readTree(rawResponse); + return jsonResponse; + } else { + logger.error(baseUrl + "?nrp=" + nrp); + logger.error("Error from SIPP API: {} - {}", response.getStatusCode(), response.getResponseBody()); + return objectMapper.createObjectNode() + .put("status_code", response.getStatusCode()) + .put("status", "error") + .put("message", response.getResponseBody()); + } + } + } catch (ExecutionException | InterruptedException | java.io.IOException e) { + logger.error("Error calling SIPP API: {}", e.getMessage(), e); + return objectMapper.createObjectNode() + .put("status", "error") + .put("message", e.getMessage()); + } + } +} diff --git a/src/main/java/id/go/polri/tte/repositories/api/ThreeScaleRepository.java b/src/main/java/id/go/polri/tte/repositories/api/ThreeScaleRepository.java new file mode 100644 index 0000000..bbf4de8 --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/api/ThreeScaleRepository.java @@ -0,0 +1,88 @@ +package id.go.polri.tte.repositories.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import id.go.polri.tte.models.threescale.DailyAnalyticResponse; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.netty.handler.ssl.SslProvider; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.Request; +import org.asynchttpclient.RequestBuilder; +import org.asynchttpclient.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLException; +import javax.net.ssl.X509TrustManager; +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.util.TimeZone; +import java.util.concurrent.ExecutionException; + +import static org.asynchttpclient.Dsl.asyncHttpClient; +import static org.asynchttpclient.Dsl.config; + +public class ThreeScaleRepository { + private static final Logger logger = LoggerFactory.getLogger(ThreeScaleRepository.class); + private final String baseUrl; + private final String token; + private final ObjectMapper objectMapper; + + public ThreeScaleRepository(String baseUrl, String token) { + this.baseUrl = baseUrl; + this.token = token; + this.objectMapper = new ObjectMapper(); + } + + public DailyAnalyticResponse getDailyAnalytics(long applicationId, String since, String metric) { + String url = String.format("%s/stats/applications/%d/usage.json?access_token=%s&metric_name=%s&since=%s&period=day&granularity=day&timezone=%s&skip_change=true", + baseUrl, applicationId, token, metric,since, TimeZone.getDefault().getID()); + + + Request request = new RequestBuilder("GET") + .setUrl(url) + .build(); + + try (AsyncHttpClient client = asyncHttpClient(config() + .setSslContext(createSslContext()))) { + Response response = client.executeRequest(request).toCompletableFuture().get(); + if (response.getStatusCode() == 200) { + return objectMapper.readValue(response.getResponseBody(), DailyAnalyticResponse.class); + } else { + logger.error(url); + logger.error("Error from 3Scale API: {} - {}", response.getStatusCode(), response.getResponseBody()); + } + } catch (IOException | ExecutionException | InterruptedException e) { + logger.error("Error calling 3Scale API: {}", e.getMessage(), e); + } + return null; + } + + private SslContext createSslContext() { + X509TrustManager tm = new X509TrustManager() { + + @Override + public void checkClientTrusted(X509Certificate[] xcs, String string) { + } + + @Override + public void checkServerTrusted(X509Certificate[] xcs, String string) { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + }; + + SslProvider sslProvider = SslContext.defaultClientProvider(); + SslContextBuilder sslContextBuilder = SslContextBuilder.forClient(); + sslContextBuilder.trustManager(tm); + sslContextBuilder.sslProvider(sslProvider); + try { + return sslContextBuilder.build(); + } catch (SSLException e) { + throw new RuntimeException(e.getMessage(), e); + } + } +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/ApplicationAnalyticsRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/ApplicationAnalyticsRepository.java new file mode 100644 index 0000000..07017be --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/ApplicationAnalyticsRepository.java @@ -0,0 +1,74 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.ApplicationAnalytics; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; + +@RegisterRowMapper(ApplicationAnalytics.Mapper.class) +public interface ApplicationAnalyticsRepository { + + @SqlQuery("select * from application_analytics order by id") + List findAll(); + + @SqlQuery("select count(id) from application_analytics") + int count(); + + @SqlQuery("select * from application_analytics order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from application_analytics order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from application_analytics where id = :id") + ApplicationAnalytics findById(String id); + + @SqlQuery("select * from application_analytics where application_id = :applicationId") + List findByApplicationId(String applicationId); + + @SqlQuery("select * from application_analytics where application_id = :applicationId order by id desc limit 1") + ApplicationAnalytics findLatestByApplicationId(String applicationId); + + @SqlQuery("select * from application_analytics where gateway_id = :gatewayId") + List findByGatewayId(String gatewayId); + + @SqlQuery("select * from application_analytics where gateway_id = :gatewayId order by id desc limit 1") + ApplicationAnalytics findLatestByGatewayId(String gatewayId); + + @SqlQuery("select * from application_analytics where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from application_analytics where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO application_analytics ( " + + " id,"+ + " application_id,"+ + " gateway_id,"+ + " hit_date,"+ + " value)"+ + " VALUES ("+ + " :id,"+ + " :applicationId,"+ + " :gatewayId,"+ + " :hitDate,"+ + " :value)") + boolean insert(@BindBean ApplicationAnalytics applicationAnalytics); + + @SqlUpdate("UPDATE application_analytics SET " + + " id = :id,"+ + " application_id = :applicationId,"+ + " gateway_id = :gatewayId,"+ + " hit_date = :hitDate,"+ + " value = :value WHERE id = :oldId") + boolean update(@BindBean ApplicationAnalytics applicationAnalytics, String oldId); + + @SqlUpdate("delete from application_analytics where id=:id") + boolean delete(String id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/ApplicationMappingRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/ApplicationMappingRepository.java new file mode 100644 index 0000000..d78bb5b --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/ApplicationMappingRepository.java @@ -0,0 +1,68 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.ApplicationMapping; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; + +@RegisterRowMapper(ApplicationMapping.Mapper.class) +public interface ApplicationMappingRepository { + + @SqlQuery("select * from application_mappings order by id") + List findAll(); + + @SqlQuery("select count(id) from application_mappings") + int count(); + + @SqlQuery("select * from application_mappings order by id offset :offset rows fetch next :limit rows only") + List findAll(int limit, int offset); + + @SqlQuery("select * from application_mappings order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from application_mappings where id = :id") + ApplicationMapping findById(String id); + + @SqlQuery("select * from application_mappings where application_id = :applicationId") + List findByApplicationId(String applicationId); + + @SqlQuery("SELECT * FROM application_mappings WHERE application_id = :applicationId ORDER BY id DESC FETCH FIRST 1 ROWS ONLY") + ApplicationMapping findLatestByApplicationId(String applicationId); + + @SqlQuery("select * from application_mappings where gateway_id = :gatewayId") + List findByGatewayId(String gatewayId); + + @SqlQuery("select * from application_mappings where gateway_id = :gatewayId order by id desc fetch first 1 row only") + ApplicationMapping findLatestByGatewayId(String gatewayId); + + @SqlQuery("select * from application_mappings where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from application_mappings where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO application_mappings ( " + + " id,"+ + " application_id,"+ + " gateway_id)"+ + " VALUES ("+ + " :id,"+ + " :applicationId,"+ + " :gatewayId)") + boolean insert(@BindBean ApplicationMapping applicationMapping); + + @SqlUpdate("UPDATE application_mappings SET " + + " id = :id,"+ + " application_id = :applicationId,"+ + " gateway_id = :gatewayId WHERE id = :oldId") + boolean update(@BindBean ApplicationMapping applicationMapping, String oldId); + + @SqlUpdate("delete from application_mappings where id=:id") + boolean delete(String id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/ApplicationRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/ApplicationRepository.java new file mode 100644 index 0000000..e3e0621 --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/ApplicationRepository.java @@ -0,0 +1,68 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.Application; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; + +@RegisterRowMapper(Application.Mapper.class) +public interface ApplicationRepository { + + @SqlQuery("SELECT DISTINCT ON (name) * FROM applications ORDER BY name, id") + List findAll(); + + @SqlQuery("SELECT COUNT(DISTINCT name) FROM applications") + int count(); + + @SqlQuery("select * from applications order by id offset :offset rows fetch next :limit rows only") + List findAll(int limit, int offset); + + @SqlQuery("select * from applications order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from applications where id = :id") + Application findById(String id); + + @SqlQuery("select * from applications where organization_id = :organizationId") + List findByOrganizationId(String organizationId); + + @SqlQuery("SELECT * FROM applications WHERE organization_id = :organizationId ORDER BY id DESC FETCH FIRST 1 ROW ONLY") + Application findLatestByOrganizationId(String organizationId); + + @SqlQuery("select * from applications where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from applications where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO applications ( " + + " id,"+ + " organization_id,"+ + " name,"+ + " created_at,"+ + " updated_at)"+ + " VALUES ("+ + " :id,"+ + " :organizationId,"+ + " :name,"+ + " :createdAt,"+ + " :updatedAt)") + boolean insert(@BindBean Application applications); + + @SqlUpdate("UPDATE applications SET " + + " id = :id,"+ + " organization_id = :organizationId,"+ + " name = :name,"+ + " created_at = :createdAt,"+ + " updated_at = :updatedAt WHERE id = :oldId") + boolean update(@BindBean Application applications, String oldId); + + @SqlUpdate("delete from applications where id=:id") + boolean delete(String id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/BsreLogRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/BsreLogRepository.java new file mode 100644 index 0000000..d64fb77 --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/BsreLogRepository.java @@ -0,0 +1,78 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.BsreLog; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; +import java.util.UUID; + +@RegisterRowMapper(BsreLog.Mapper.class) +public interface BsreLogRepository { + + @SqlQuery("select * from bsre_logs order by id") + List findAll(); + + @SqlQuery("select count(id) from bsre_logs") + int count(); + + @SqlQuery("select * from bsre_logs order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from bsre_logs order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from bsre_logs where id = :id") + BsreLog findById(UUID id); + + @SqlQuery("select * from bsre_logs where nik = :nik") + List findByNik(String nik); + + @SqlQuery("select * from bsre_logs where nik = :nik order by id desc limit 1") + BsreLog findLatestByNik(String nik); + + @SqlQuery("select * from bsre_logs where nrp = :nrp") + List findByNrp(String nrp); + + @SqlQuery("select * from bsre_logs where nrp = :nrp order by id desc limit 1") + BsreLog findLatestByNrp(String nrp); + + @SqlQuery("select * from bsre_logs where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from bsre_logs where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO bsre_logs ( " + + " id,"+ + " nik,"+ + " nrp,"+ + " message,"+ + " created_at,"+ + " updated_at)"+ + " VALUES ("+ + " :id,"+ + " :nik,"+ + " :nrp,"+ + " :message,"+ + " :createdAt,"+ + " :updatedAt)") + boolean insert(@BindBean BsreLog bsreLog); + + @SqlUpdate("UPDATE bsre_logs SET " + + " id = :id,"+ + " nik = :nik,"+ + " nrp = :nrp,"+ + " message = :message,"+ + " created_at = :createdAt,"+ + " updated_at = :updatedAt WHERE id = :oldId") + boolean update(@BindBean BsreLog bsreLog, UUID oldId); + + @SqlUpdate("delete from bsre_logs where id=:id") + boolean delete(UUID id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/OneTimePasswordRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/OneTimePasswordRepository.java new file mode 100644 index 0000000..02ddfb2 --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/OneTimePasswordRepository.java @@ -0,0 +1,98 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.OneTimePassword; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; +import java.util.UUID; + +@RegisterRowMapper(OneTimePassword.Mapper.class) +public interface OneTimePasswordRepository { + + @SqlQuery("select * from one_time_passwords order by id") + List findAll(); + + @SqlQuery("select count(id) from one_time_passwords") + int count(); + + @SqlQuery("select * from one_time_passwords order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from one_time_passwords order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from one_time_passwords where id = :id") + OneTimePassword findById(UUID id); + + @SqlQuery("select * from one_time_passwords where user_id = :userId") + OneTimePassword findByUserId(UUID userId); + + @SqlQuery("select * from one_time_passwords where user_id = :userId order by id desc limit 1") + OneTimePassword findLatestByUserId(UUID userId); + + @SqlQuery("SELECT * FROM one_time_passwords " + + "WHERE user_id = :userId " + + "AND used_at IS NULL " + + "AND expired_at > CURRENT_TIMESTAMP " + + "ORDER BY created_at DESC " + + "LIMIT 1") + OneTimePassword findLatestActiveByUserId(UUID userId); + + @SqlQuery("select * from one_time_passwords where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from one_time_passwords where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO one_time_passwords ( " + + " id,"+ + " user_id,"+ + " code,"+ + " expired_at,"+ + " used_at,"+ + " created_at,"+ + " updated_at)"+ + " VALUES ("+ + " :id,"+ + " :userId,"+ + " :code,"+ + " :expiredAt,"+ + " :usedAt,"+ + " :createdAt,"+ + " :updatedAt)") + boolean insert(@BindBean OneTimePassword oneTimePassword); + + @SqlUpdate("UPDATE one_time_passwords SET " + + " id = :id,"+ + " user_id = :userId,"+ + " code = :code,"+ + " expired_at = :expiredAt,"+ + " used_at = :usedAt,"+ + " created_at = :createdAt,"+ + " updated_at = :updatedAt WHERE id = :oldId") + boolean update(@BindBean OneTimePassword oneTimePassword, UUID oldId); + + @SqlUpdate("UPDATE one_time_passwords SET used_at = NOW() WHERE id = :id") + boolean updateUsedAt(@Bind("id") UUID id); + + @SqlUpdate("delete from one_time_passwords where id=:id") + boolean delete(UUID id); + + @SqlUpdate("INSERT INTO one_time_passwords ( " + + "id, user_id, code, expired_at, used_at, created_at, updated_at) " + + "VALUES (" + + ":id, :userId, :code, :expiredAt, NULL, :createdAt, :updatedAt) " + + "ON CONFLICT (user_id, used_at) DO UPDATE SET " + + "code = EXCLUDED.code, " + + "expired_at = EXCLUDED.expired_at, " + + "updated_at = EXCLUDED.updated_at") + boolean upsert(@BindBean OneTimePassword oneTimePassword); + + +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/OrganizationMappingRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/OrganizationMappingRepository.java new file mode 100644 index 0000000..810a04f --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/OrganizationMappingRepository.java @@ -0,0 +1,68 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.OrganizationMapping; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; + +@RegisterRowMapper(OrganizationMapping.Mapper.class) +public interface OrganizationMappingRepository { + + @SqlQuery("select * from organization_mappings order by id") + List findAll(); + + @SqlQuery("select count(id) from organization_mappings") + int count(); + + @SqlQuery("select * from organization_mappings order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from organization_mappings order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from organization_mappings where id = :id") + OrganizationMapping findById(String id); + + @SqlQuery("select * from organization_mappings where organization_id = :organizationId") + List findByOrganizationId(String organizationId); + + @SqlQuery("select * from organization_mappings where organization_id = :organizationId order by id desc limit 1") + OrganizationMapping findLatestByOrganizationId(String organizationId); + + @SqlQuery("select * from organization_mappings where gateway_id = :gatewayId") + List findByGatewayId(String gatewayId); + + @SqlQuery("select * from organization_mappings where gateway_id = :gatewayId order by id desc limit 1") + OrganizationMapping findLatestByGatewayId(String gatewayId); + + @SqlQuery("select * from organization_mappings where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from organization_mappings where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO organization_mappings ( " + + " id,"+ + " organization_id,"+ + " gateway_id)"+ + " VALUES ("+ + " :id,"+ + " :organizationId,"+ + " :gatewayId)") + boolean insert(@BindBean OrganizationMapping organizationMapping); + + @SqlUpdate("UPDATE organization_mappings SET " + + " id = :id,"+ + " organization_id = :organizationId,"+ + " gateway_id = :gatewayId WHERE id = :oldId") + boolean update(@BindBean OrganizationMapping organizationMapping, String oldId); + + @SqlUpdate("delete from organization_mappings where id=:id") + boolean delete(String id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/OrganizationRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/OrganizationRepository.java new file mode 100644 index 0000000..e2023e4 --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/OrganizationRepository.java @@ -0,0 +1,59 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.Organization; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; + +@RegisterRowMapper(Organization.Mapper.class) +public interface OrganizationRepository { + + @SqlQuery("select * from organization order by id") + List findAll(); + + @SqlQuery("select count(id) from organization") + int count(); + + @SqlQuery("select * from organization order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from organization order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from organization where id = :id") + Organization findById(String id); + + @SqlQuery("select * from organization where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from organization where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO organization ( " + + " id,"+ + " name,"+ + " created_at,"+ + " updated_at)"+ + " VALUES ("+ + " :id,"+ + " :name,"+ + " :createdAt,"+ + " :updatedAt)") + boolean insert(@BindBean Organization organization); + + @SqlUpdate("UPDATE organization SET " + + " id = :id,"+ + " name = :name,"+ + " created_at = :createdAt,"+ + " updated_at = :updatedAt WHERE id = :oldId") + boolean update(@BindBean Organization organization, String oldId); + + @SqlUpdate("delete from organization where id=:id") + boolean delete(String id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/RoleRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/RoleRepository.java new file mode 100644 index 0000000..ced1a27 --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/RoleRepository.java @@ -0,0 +1,60 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.Role; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; +import java.util.UUID; + +@RegisterRowMapper(Role.Mapper.class) +public interface RoleRepository { + + @SqlQuery("select * from roles order by id") + List findAll(); + + @SqlQuery("select count(id) from roles") + int count(); + + @SqlQuery("select * from roles order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from roles order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from roles where id = :id") + Role findById(UUID id); + + @SqlQuery("select * from roles where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from roles where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO roles ( " + + " id,"+ + " name,"+ + " created_at,"+ + " updated_at)"+ + " VALUES ("+ + " :id,"+ + " :name,"+ + " :createdAt,"+ + " :updatedAt)") + boolean insert(@BindBean Role roles); + + @SqlUpdate("UPDATE roles SET " + + " id = :id,"+ + " name = :name,"+ + " created_at = :createdAt,"+ + " updated_at = :updatedAt WHERE id = :oldId") + boolean update(@BindBean Role roles, UUID oldId); + + @SqlUpdate("delete from roles where id=:id") + boolean delete(UUID id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/UsageOrganizationRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/UsageOrganizationRepository.java new file mode 100644 index 0000000..cc9aec1 --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/UsageOrganizationRepository.java @@ -0,0 +1,76 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.dto.TopOrganizationDTO; +import id.go.polri.tte.models.UsageOrganizations; +import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +@RegisterRowMapper(UsageOrganizations.Mapper.class) +public interface UsageOrganizationRepository { + + @SqlQuery("select * from usage_organizations order by id") + List findAll(); + + @SqlQuery("select count(id) from usage_organizations") + int count(); + + @SqlQuery("select * from usage_organizations order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from usage_organizations order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from usage_organizations where id = :id") + UsageOrganizations findById(String id); + + @SqlQuery("select * from usage_organizations where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from usage_organizations where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlQuery(""" + SELECT org_name, COUNT(*) AS total + FROM usage_organizations + GROUP BY org_name + ORDER BY total DESC + LIMIT 10 +""") + @RegisterConstructorMapper(TopOrganizationDTO.class) + List findTop10Organizations(); + + @SqlQuery(""" + SELECT org_name, COUNT(*) AS total + FROM usage_organizations + WHERE created_at::date BETWEEN :startDate AND :endDate + GROUP BY org_name + ORDER BY total DESC + LIMIT 10 +""") + @RegisterConstructorMapper(TopOrganizationDTO.class) + List findTop10OrganizationsByDate(@Bind("startDate") LocalDate startDate, @Bind("endDate") LocalDate endDate); + + @SqlUpdate("INSERT INTO usage_organizations ( " + + " id,"+ + " org_name,"+ + " created_at)"+ + " VALUES ("+ + " :id,"+ + " :orgName,"+ + " :createdAt)") + boolean insert(@BindBean UsageOrganizations usage_organizations); + + + @SqlUpdate("delete from usage_organizations where id=:id") + boolean delete(String id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/UsageUserRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/UsageUserRepository.java new file mode 100644 index 0000000..cd9c20b --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/UsageUserRepository.java @@ -0,0 +1,78 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.dto.TopOrganizationDTO; +import id.go.polri.tte.dto.TopUsageUserDto; +import id.go.polri.tte.models.UsageUsers; +import org.jdbi.v3.sqlobject.config.RegisterConstructorMapper; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.time.LocalDate; +import java.util.List; + +@RegisterRowMapper(UsageUsers.Mapper.class) +public interface UsageUserRepository { + + @SqlQuery("select * from usage_users order by id") + List findAll(); + + @SqlQuery("select count(id) from usage_users") + int count(); + + @SqlQuery("select * from usage_users order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from usage_users order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from usage_users where id = :id") + UsageUsers findById(String id); + + @SqlQuery("select * from usage_users where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from usage_users where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlQuery(""" + SELECT u.id AS user_id, u.name AS user_name, u.nrp AS nrp, COUNT(*) AS total + FROM usage_users uu + JOIN users u ON uu.user_id = u.id + GROUP BY u.id, u.name + ORDER BY total DESC + LIMIT 10 +""") + @RegisterConstructorMapper(TopUsageUserDto.class) + List findTop10Users(); + + @SqlQuery(""" + SELECT u.id AS user_id, u.name AS user_name,u.nrp AS nrp, COUNT(*) AS total + FROM usage_users uu + JOIN users u ON uu.user_id = u.id + WHERE uu.created_at::date BETWEEN :startDate AND :endDate + GROUP BY u.id, u.name + ORDER BY total DESC + LIMIT 10 +""") + @RegisterConstructorMapper(TopUsageUserDto.class) + List findTop10UsersByDate(@Bind("startDate") LocalDate startDate, @Bind("endDate") LocalDate endDate); + + @SqlUpdate("INSERT INTO usage_users ( " + + " id,"+ + " user_id,"+ + " created_at)"+ + " VALUES ("+ + " :id,"+ + " :userId,"+ + " :createdAt)") + boolean insert(@BindBean UsageUsers usage_users); + + + @SqlUpdate("delete from usage_users where id=:id") + boolean delete(String id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/UserInitialRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/UserInitialRepository.java new file mode 100644 index 0000000..8a1a9c9 --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/UserInitialRepository.java @@ -0,0 +1,72 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.UserInitial; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; +import java.util.UUID; + +@RegisterRowMapper(UserInitial.Mapper.class) +public interface UserInitialRepository { + + @SqlQuery("select * from user_initials order by id") + List findAll(); + + @SqlQuery("select count(id) from user_initials") + int count(); + + @SqlQuery("select * from user_initials order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from user_initials order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from user_initials where id = :id") + UserInitial findById(UUID id); + + @SqlQuery("select * from user_initials where user_id = :userId") + List findByUserId(UUID userId); + + @SqlQuery("select * from user_initials where user_id = :userId") + UserInitial findSingleByUserId(UUID userId); + + @SqlQuery("select * from user_initials where user_id = :userId order by id desc limit 1") + UserInitial findLatestByUserId(UUID userId); + + @SqlQuery("select * from user_initials where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from user_initials where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO user_initials ( " + + " id,"+ + " user_id,"+ + " file,"+ + " created_at,"+ + " updated_at)"+ + " VALUES ("+ + " :id,"+ + " :userId,"+ + " :file,"+ + " :createdAt,"+ + " :updatedAt)") + boolean insert(@BindBean UserInitial userInitial); + + @SqlUpdate("UPDATE user_initials SET " + + " id = :id,"+ + " user_id = :userId,"+ + " file = :file,"+ + " created_at = :createdAt,"+ + " updated_at = :updatedAt WHERE id = :oldId") + boolean update(@BindBean UserInitial userInitial, UUID oldId); + + @SqlUpdate("delete from user_initials where user_id=:userId") + boolean delete(UUID userId); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/UserLogsRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/UserLogsRepository.java new file mode 100644 index 0000000..42acc4a --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/UserLogsRepository.java @@ -0,0 +1,73 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.UserLogs; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; +import java.util.UUID; + +@RegisterRowMapper(UserLogs.Mapper.class) +public interface UserLogsRepository { + + @SqlQuery("select * from user_logs order by id") + List findAll(); + + @SqlQuery("select count(id) from user_logs") + int count(); + + @SqlQuery("select * from user_logs order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from user_logs order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from user_logs where id = :id") + UserLogs findById(UUID id); + + @SqlQuery("select * from user_logs where user_id = :userId") + List findByUserId(UUID userId); + + @SqlQuery("select * from user_logs where user_id = :userId order by id desc limit 1") + UserLogs findLatestByUserId(UUID userId); + + @SqlQuery("SELECT * FROM user_logs " + + "WHERE user_id = :userId " + + "AND last_signin > CURRENT_TIMESTAMP " + + "ORDER BY id DESC " + + "LIMIT 1") + UserLogs findLatestActiveByUserId(UUID userId); + + @SqlQuery("select * from user_logs where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from user_logs where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO user_logs ( " + + " id,"+ + " user_id,"+ + " last_signin)"+ + " VALUES ("+ + " :id,"+ + " :userId,"+ + " :lastSignin)") + boolean insert(@BindBean UserLogs UserLogs); + + @SqlUpdate("UPDATE user_logs SET " + + " id = :id,"+ + " user_id = :userId,"+ + " last_signin = :lastSignin WHERE id = :oldId") + boolean update(@BindBean UserLogs UserLogs, UUID oldId); + + @SqlUpdate("UPDATE user_logs SET used_at = NOW() WHERE id = :id") + boolean updateUsedAt(@Bind("id") UUID id); + + @SqlUpdate("delete from user_logs where id=:id") + boolean delete(UUID id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/UserRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/UserRepository.java new file mode 100644 index 0000000..2e9d031 --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/UserRepository.java @@ -0,0 +1,251 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.User; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; +import java.util.UUID; + +@RegisterRowMapper(User.Mapper.class) +public interface UserRepository { + + @SqlQuery("select * from users order by id") + List findAll(); + + @SqlQuery("select count(id) from users") + int count(); + + @SqlQuery("SELECT response_status, COUNT(*) AS jumlah FROM users GROUP BY response_status") + @RegisterRowMapper(User.ResponseStatusCount.Mapper.class) + List countGroupedByResponseStatus(); + +// @SqlQuery("select * from users order by id limit :limit offset :offset") +// List findAll(int limit, int offset); + + @SqlQuery(""" + SELECT u.*, ul.last_signin AS last_signin + FROM users u + LEFT JOIN ( + SELECT DISTINCT ON (user_id) user_id, last_signin + FROM user_logs + ORDER BY user_id, last_signin DESC + ) ul ON u.id = ul.user_id + ORDER BY u.id + LIMIT :limit OFFSET :offset + """) + @RegisterRowMapper(User.NewMapper.class) + List findAll(@Bind("limit") int limit, @Bind("offset") int offset); + +// @SqlQuery("select * from users order by limit :limit offset :offset") +// List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery(""" + SELECT u.*, ul.last_signin AS last_signin + FROM users u + LEFT JOIN ( + SELECT DISTINCT ON (user_id) user_id, last_signin + FROM user_logs + ORDER BY user_id, last_signin DESC + ) ul ON u.id = ul.user_id + ORDER BY + LIMIT :limit OFFSET :offset + """) + @RegisterRowMapper(User.NewMapper.class) + List findAll(@Bind("limit") int limit, + @Bind("offset") int offset, + @Define("orderBy") String orderBy, + @Define("direction") String direction); + + @SqlQuery("select * from users where id = :id") + User findById(UUID id); +//@SqlQuery(""" +// SELECT u.*, ul.last_signin AS last_signin +// FROM users u +// LEFT JOIN ( +// SELECT user_id, last_signin +// FROM user_logs +// ORDER BY last_signin DESC +// LIMIT 1 +// ) ul ON u.id = ul.user_id +// WHERE u.id = :id +//""") +//@RegisterRowMapper(User.RolesMapper.class) +//User findById(@Bind("id") UUID id); + + @SqlQuery("select * from users where nrp = :nrp") + User findByNrp(String nrp); + + @SqlQuery(""" + SELECT + u.id, u.name, u.email, u.phone, u.email_verified_at, u.phone_verified_at, + u.password, u.nrp, u.nik, u.response_status, u.pangkat, u.nama_tanpa_gelar, + u.jabatan, u.is_changed, u.satuan, u.pangkat_lengkap, u.satker, u.nama_aplikasi, + u.nama_pendek_dengan_gelar, u.device_token, u.created_at,u.status_account, u.updated_at, + ARRAY_AGG(r.name) AS roles, + ul.last_signin + FROM users u + LEFT JOIN user_roles ur ON u.id = ur.user_id + LEFT JOIN roles r ON ur.role_id = r.id + LEFT JOIN ( + SELECT user_id, last_signin + FROM user_logs + WHERE user_id = :id + ORDER BY last_signin DESC + LIMIT 1 + ) ul ON u.id = ul.user_id + WHERE u.id = :id + GROUP BY u.id, ul.last_signin +""") + @RegisterRowMapper(User.RolesMapper.class) + User findWithRolesById(@Bind("id") UUID id); + + @SqlQuery("select * from users where email = :email") + List findByEmail(String email); + + @SqlQuery("select * from users where email = :email order by id desc limit 1") + User findLatestByEmail(String email); + + @SqlQuery("select * from users where phone = :phone") + List findByPhone(String phone); + + @SqlQuery("select * from users where phone = :phone order by id desc limit 1") + User findLatestByPhone(String phone); + +// @SqlQuery("select * from users where nrp = :nrp") +// List findByNrp(String nrp); + + @SqlQuery("select * from users where nrp = :nrp order by id desc limit 1") + User findLatestByNrp(String nrp); + + @SqlQuery("select * from users where nik = :nik") + List findByNik(String nik); + + @SqlQuery("select * from users where nik = :nik order by id desc limit 1") + User findLatestByNik(String nik); + + @SqlQuery("select * from users where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery(""" + SELECT u.*, ul.last_signin AS last_signin + FROM users u + LEFT JOIN ( + SELECT DISTINCT ON (user_id) user_id, last_signin + FROM user_logs + ORDER BY user_id, last_signin DESC + ) ul ON u.id = ul.user_id + WHERE + ORDER BY + LIMIT :limit OFFSET :offset +""") + @RegisterRowMapper(User.NewMapper.class) + List findByCustomWhereUserLogs(@Define("condition") String condition, @Bind("limit") int limit, + @Bind("offset") int offset, @Define("orderBy") String orderBy, + @Define("direction") String direction); + + @SqlQuery("select count(id) from users where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO users ( " + + " id,"+ + " name,"+ + " email,"+ + " phone,"+ + " email_verified_at,"+ + " phone_verified_at,"+ + " password,"+ + " nrp,"+ + " nik,"+ + " response_status,"+ + " pangkat,"+ + " nama_tanpa_gelar,"+ + " jabatan,"+ + " is_changed, " + + " satuan,"+ + " pangkat_lengkap,"+ + " satker,"+ + " nama_aplikasi,"+ + "nama_pendek_dengan_gelar,"+ + " device_token,"+ + " created_at,"+ + " updated_at)"+ + " VALUES ("+ + " :id,"+ + " :name,"+ + " :email,"+ + " :phone,"+ + " :emailVerifiedAt,"+ + " :phoneVerifiedAt,"+ + " :password,"+ + " :nrp,"+ + " :nik,"+ + " :responseStatus,"+ + " :pangkat,"+ + " :namaTanpaGelar,"+ + " :jabatan,"+ + " :is_changed,"+ + " CAST(:satuanJson AS jsonb),"+ + " :pangkatLengkap,"+ + " :satker,"+ + " :namaAplikasi,"+ + ":namaPendekDenganGelar,"+ + " :deviceToken,"+ + " :createdAt,"+ + " :updatedAt)") + boolean insert(@BindBean User user, @Bind("satuanJson") String satuanJson); + + @SqlUpdate("UPDATE users SET " + + " id = :id,"+ + " name = :name,"+ + " email = :email,"+ + " phone = :phone,"+ + " email_verified_at = :emailVerifiedAt,"+ + " phone_verified_at = :phoneVerifiedAt,"+ + " password = :password,"+ + " nrp = :nrp,"+ + " nik = :nik,"+ + " response_status = :responseStatus,"+ + " pangkat = :pangkat,"+ + " nama_tanpa_gelar = :namaTanpaGelar,"+ + " jabatan = :jabatan,"+ + " is_changed = :is_changed,"+ + " satuan = CAST(:satuanJson AS jsonb),"+ + " pangkat_lengkap = :pangkatLengkap,"+ + " satker = :satker,"+ + " nama_aplikasi = :namaAplikasi,"+ + "nama_pendek_dengan_gelar = :namaPendekDenganGelar, "+ + " device_token = :deviceToken,"+ + " created_at = :createdAt,"+ + " updated_at = :updatedAt WHERE id = :oldId") + boolean update(@BindBean User user, UUID oldId, @Bind("satuanJson") String satuanJson); + + @SqlUpdate("UPDATE users SET " + + " id = :id,"+ + " name = :name,"+ + " email = :email,"+ + " phone = :phone,"+ + " email_verified_at = :emailVerifiedAt,"+ + " phone_verified_at = :phoneVerifiedAt,"+ + " password = :password,"+ + " nrp = :nrp,"+ + " nik = :nik,"+ + " response_status = :responseStatus,"+ + " pangkat = :pangkat,"+ + " nama_tanpa_gelar = :namaTanpaGelar,"+ + " jabatan = :jabatan,"+ + " is_changed = :is_changed,"+ + " pangkat_lengkap = :pangkatLengkap,"+ + " device_token = :deviceToken,"+ + " status_account = :statusAccount,"+ + " created_at = :createdAt,"+ + " updated_at = :updatedAt WHERE id = :oldId") + boolean updateCustom(@BindBean User user, UUID oldId); + + @SqlUpdate("delete from users where id=:id") + boolean delete(UUID id); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/UserRoleRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/UserRoleRepository.java new file mode 100644 index 0000000..e1c14ee --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/UserRoleRepository.java @@ -0,0 +1,93 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.dto.GetUserRoleDetailsDto; +import id.go.polri.tte.models.UserRole; +import org.jdbi.v3.sqlobject.config.RegisterBeanMapper; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; +import java.util.UUID; + +@RegisterRowMapper(UserRole.Mapper.class) +public interface UserRoleRepository { + + @SqlQuery("select * from user_roles order by id") + List findAll(); + + @SqlQuery("select count(id) from user_roles") + int count(); + + @SqlQuery("select * from user_roles order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from user_roles order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from user_roles where id = :id") + UserRole findById(UUID id); + + @SqlQuery("select * from user_roles where user_id = :userId") + List findByUserId(UUID userId); + + @SqlQuery("select * from user_roles where user_id = :userId order by id desc limit 1") + UserRole findLatestByUserId(UUID userId); + + @SqlQuery("select * from user_roles where role_id = :roleId") + List findByRoleId(UUID roleId); + + @SqlQuery("select * from user_roles where role_id = :roleId order by id desc limit 1") + UserRole findLatestByRoleId(UUID roleId); + + @SqlQuery("select * from user_roles where user_id = :userId AND role_id = :roleId order by id desc limit 1") + UserRole findLatestByUserAndRoleId(UUID userId, UUID roleId); + + @SqlQuery("select * from user_roles where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from user_roles where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlQuery(""" + SELECT ur.*, r.name AS role_name + FROM user_roles ur + JOIN users u ON u.id = ur.user_id + JOIN roles r ON r.id = ur.role_id + WHERE ur.user_id = :userId +""") + @RegisterBeanMapper(GetUserRoleDetailsDto.class) + List getByUserId(@Bind("userId") UUID userId); + + @SqlUpdate("INSERT INTO user_roles ( " + + " id,"+ + " user_id,"+ + " role_id,"+ + " created_at,"+ + " updated_at)"+ + " VALUES ("+ + " :id,"+ + " :userId,"+ + " :roleId,"+ + " :createdAt,"+ + " :updatedAt)") + boolean insert(@BindBean UserRole userRole); + + @SqlUpdate("UPDATE user_roles SET " + + " id = :id,"+ + " user_id = :userId,"+ + " role_id = :roleId,"+ + " created_at = :createdAt,"+ + " updated_at = :updatedAt WHERE id = :oldId") + boolean update(@BindBean UserRole userRole, UUID oldId); + + @SqlUpdate("delete from user_roles where id=:id") + boolean delete(UUID id); + + @SqlUpdate("delete from user_roles where user_id=:id AND role_id = :roleId") + boolean deleteByUserRoleId(UUID userId, UUID roleId); +} diff --git a/src/main/java/id/go/polri/tte/repositories/jdbi/UserSignatureRepository.java b/src/main/java/id/go/polri/tte/repositories/jdbi/UserSignatureRepository.java new file mode 100644 index 0000000..9db10fa --- /dev/null +++ b/src/main/java/id/go/polri/tte/repositories/jdbi/UserSignatureRepository.java @@ -0,0 +1,72 @@ +package id.go.polri.tte.repositories.jdbi; + +import id.go.polri.tte.models.UserSignature; +import org.jdbi.v3.sqlobject.config.RegisterRowMapper; +import org.jdbi.v3.sqlobject.customizer.Bind; +import org.jdbi.v3.sqlobject.customizer.BindBean; +import org.jdbi.v3.sqlobject.customizer.Define; +import org.jdbi.v3.sqlobject.statement.SqlQuery; +import org.jdbi.v3.sqlobject.statement.SqlUpdate; + +import java.util.List; +import java.util.UUID; + +@RegisterRowMapper(UserSignature.Mapper.class) +public interface UserSignatureRepository { + + @SqlQuery("select * from user_signatures order by id") + List findAll(); + + @SqlQuery("select count(id) from user_signatures") + int count(); + + @SqlQuery("select * from user_signatures order by id limit :limit offset :offset") + List findAll(int limit, int offset); + + @SqlQuery("select * from user_signatures order by limit :limit offset :offset") + List findAll(@Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + + @SqlQuery("select * from user_signatures where id = :id") + UserSignature findById(UUID id); + + @SqlQuery("select * from user_signatures where user_id = :userId") + List findByUserId(UUID userId); + + @SqlQuery("select * from user_signatures where user_id = :userId") + UserSignature findSingleByUserId(UUID userId); + + @SqlQuery("select * from user_signatures where user_id = :userId order by id desc limit 1") + UserSignature findLatestByUserId(String userId); + + @SqlQuery("select * from user_signatures where order by limit :limit offset :offset") + List findByCustomWhere(@Define("condition") String condition, @Bind("limit") int limit, @Bind("offset") int offset, @Define("orderBy") String orderBy, @Define("direction") String direction); + + @SqlQuery("select count(id) from user_signatures where ") + int countByCustomWhere(@Define("condition") String condition); + + @SqlUpdate("INSERT INTO user_signatures ( " + + " id,"+ + " user_id,"+ + " file,"+ + " created_at,"+ + " updated_at)"+ + " VALUES ("+ + " :id,"+ + " :userId,"+ + " :file,"+ + " :createdAt,"+ + " :updatedAt)") + boolean insert(@BindBean UserSignature userSignature); + + @SqlUpdate("UPDATE user_signatures SET " + + " id = :id,"+ + " user_id = :userId,"+ + " file = :file,"+ + " created_at = :createdAt,"+ + " updated_at = :updatedAt WHERE id = :oldId") + boolean update(@BindBean UserSignature userSignature, UUID oldId); + + @SqlUpdate("delete from user_signatures where user_id=:userId") + boolean delete(UUID userId); +} diff --git a/src/main/java/id/go/polri/tte/responses/ApplicationAnalyticsListResponse.java b/src/main/java/id/go/polri/tte/responses/ApplicationAnalyticsListResponse.java new file mode 100644 index 0000000..12db83d --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/ApplicationAnalyticsListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.ApplicationAnalytics; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class ApplicationAnalyticsListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/ApplicationAnalyticsSingleResponse.java b/src/main/java/id/go/polri/tte/responses/ApplicationAnalyticsSingleResponse.java new file mode 100644 index 0000000..c84fd43 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/ApplicationAnalyticsSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.ApplicationAnalytics; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class ApplicationAnalyticsSingleResponse extends BasicResponse { + + private ApplicationAnalytics data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/ApplicationListResponse.java b/src/main/java/id/go/polri/tte/responses/ApplicationListResponse.java new file mode 100644 index 0000000..57bc72b --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/ApplicationListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.Application; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class ApplicationListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/ApplicationMappingListResponse.java b/src/main/java/id/go/polri/tte/responses/ApplicationMappingListResponse.java new file mode 100644 index 0000000..51536aa --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/ApplicationMappingListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.ApplicationMapping; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class ApplicationMappingListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/ApplicationMappingSingleResponse.java b/src/main/java/id/go/polri/tte/responses/ApplicationMappingSingleResponse.java new file mode 100644 index 0000000..9bec7fb --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/ApplicationMappingSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.ApplicationMapping; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class ApplicationMappingSingleResponse extends BasicResponse { + + private ApplicationMapping data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/ApplicationSingleResponse.java b/src/main/java/id/go/polri/tte/responses/ApplicationSingleResponse.java new file mode 100644 index 0000000..5afd34f --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/ApplicationSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.Application; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class ApplicationSingleResponse extends BasicResponse { + + private Application data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/BasicResponse.java b/src/main/java/id/go/polri/tte/responses/BasicResponse.java new file mode 100644 index 0000000..ed8d134 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/BasicResponse.java @@ -0,0 +1,11 @@ +package id.go.polri.tte.responses; + +import lombok.Data; +import lombok.experimental.SuperBuilder; + +@Data +@SuperBuilder +public class BasicResponse { + private int code; + private String message; +} diff --git a/src/main/java/id/go/polri/tte/responses/BsreLogListResponse.java b/src/main/java/id/go/polri/tte/responses/BsreLogListResponse.java new file mode 100644 index 0000000..fb463f7 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/BsreLogListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.BsreLog; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class BsreLogListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/BsreLogSingleResponse.java b/src/main/java/id/go/polri/tte/responses/BsreLogSingleResponse.java new file mode 100644 index 0000000..9bb5269 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/BsreLogSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.BsreLog; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class BsreLogSingleResponse extends BasicResponse { + + private BsreLog data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/LoginResponse.java b/src/main/java/id/go/polri/tte/responses/LoginResponse.java new file mode 100644 index 0000000..ab58b35 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/LoginResponse.java @@ -0,0 +1,27 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.User; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class LoginResponse extends BasicResponse { + private String token; + private LoginResponseData data; + + @Data + @Builder + public static class LoginResponseData { + private User user; + private List roles; + + } + +} + diff --git a/src/main/java/id/go/polri/tte/responses/LoginSingleResponse.java b/src/main/java/id/go/polri/tte/responses/LoginSingleResponse.java new file mode 100644 index 0000000..bd545cf --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/LoginSingleResponse.java @@ -0,0 +1,20 @@ +package id.go.polri.tte.responses; + +import java.util.UUID; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class LoginSingleResponse { + private int code; + private String message; + private LoginResponseSingleData user; + + @Data + @Builder + public static class LoginResponseSingleData { + private UUID id; + private int isChanged; + } +} diff --git a/src/main/java/id/go/polri/tte/responses/OneTimePasswordListResponse.java b/src/main/java/id/go/polri/tte/responses/OneTimePasswordListResponse.java new file mode 100644 index 0000000..e190e75 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/OneTimePasswordListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.OneTimePassword; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class OneTimePasswordListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/OneTimePasswordSingleResponse.java b/src/main/java/id/go/polri/tte/responses/OneTimePasswordSingleResponse.java new file mode 100644 index 0000000..90c8204 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/OneTimePasswordSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.OneTimePassword; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class OneTimePasswordSingleResponse extends BasicResponse { + + private OneTimePassword data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/OrganizationListResponse.java b/src/main/java/id/go/polri/tte/responses/OrganizationListResponse.java new file mode 100644 index 0000000..025b15a --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/OrganizationListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.Organization; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class OrganizationListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/OrganizationMappingListResponse.java b/src/main/java/id/go/polri/tte/responses/OrganizationMappingListResponse.java new file mode 100644 index 0000000..1bdcf31 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/OrganizationMappingListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.OrganizationMapping; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class OrganizationMappingListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/OrganizationMappingSingleResponse.java b/src/main/java/id/go/polri/tte/responses/OrganizationMappingSingleResponse.java new file mode 100644 index 0000000..83fe9a8 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/OrganizationMappingSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.OrganizationMapping; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class OrganizationMappingSingleResponse extends BasicResponse { + + private OrganizationMapping data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/OrganizationSingleResponse.java b/src/main/java/id/go/polri/tte/responses/OrganizationSingleResponse.java new file mode 100644 index 0000000..7a09a60 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/OrganizationSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.Organization; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class OrganizationSingleResponse extends BasicResponse { + + private Organization data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/RoleListResponse.java b/src/main/java/id/go/polri/tte/responses/RoleListResponse.java new file mode 100644 index 0000000..a346d2c --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/RoleListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.Role; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class RoleListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/RoleSingleResponse.java b/src/main/java/id/go/polri/tte/responses/RoleSingleResponse.java new file mode 100644 index 0000000..caccd82 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/RoleSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.Role; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class RoleSingleResponse extends BasicResponse { + + private Role data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/SippResponse.java b/src/main/java/id/go/polri/tte/responses/SippResponse.java new file mode 100644 index 0000000..a64c8b5 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/SippResponse.java @@ -0,0 +1,12 @@ +package id.go.polri.tte.responses; + +import lombok.Data; +import lombok.experimental.SuperBuilder; + +@Data +@SuperBuilder +public class SippResponse { + private int code; + private String message; + private Object data; +} diff --git a/src/main/java/id/go/polri/tte/responses/StatusResponse.java b/src/main/java/id/go/polri/tte/responses/StatusResponse.java new file mode 100644 index 0000000..6fd9a99 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/StatusResponse.java @@ -0,0 +1,14 @@ +package id.go.polri.tte.responses; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class StatusResponse { + private String status; + @JsonProperty("status_code") + private int statusCode; + private String message; +} diff --git a/src/main/java/id/go/polri/tte/responses/Top10OrganizationListResponse.java b/src/main/java/id/go/polri/tte/responses/Top10OrganizationListResponse.java new file mode 100644 index 0000000..e788270 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/Top10OrganizationListResponse.java @@ -0,0 +1,17 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.dto.TopOrganizationDTO; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class Top10OrganizationListResponse extends BasicResponse { + + private List data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/Top10UserListResponse.java b/src/main/java/id/go/polri/tte/responses/Top10UserListResponse.java new file mode 100644 index 0000000..738ff01 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/Top10UserListResponse.java @@ -0,0 +1,17 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.dto.TopUsageUserDto; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class Top10UserListResponse extends BasicResponse { + + private List data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/UsageOrganizationSingleResponse.java b/src/main/java/id/go/polri/tte/responses/UsageOrganizationSingleResponse.java new file mode 100644 index 0000000..450d7a9 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/UsageOrganizationSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.UsageOrganizations; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class UsageOrganizationSingleResponse extends BasicResponse { + + private UsageOrganizations data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/UsageUserSingleResponse.java b/src/main/java/id/go/polri/tte/responses/UsageUserSingleResponse.java new file mode 100644 index 0000000..6e63b23 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/UsageUserSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.UsageUsers; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class UsageUserSingleResponse extends BasicResponse { + + private UsageUsers data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/UserInitialListResponse.java b/src/main/java/id/go/polri/tte/responses/UserInitialListResponse.java new file mode 100644 index 0000000..d55c0ec --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/UserInitialListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.UserInitial; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class UserInitialListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/UserInitialSingleResponse.java b/src/main/java/id/go/polri/tte/responses/UserInitialSingleResponse.java new file mode 100644 index 0000000..b162725 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/UserInitialSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.UserInitial; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class UserInitialSingleResponse extends BasicResponse { + + private UserInitial data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/UserListResponse.java b/src/main/java/id/go/polri/tte/responses/UserListResponse.java new file mode 100644 index 0000000..b42f4de --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/UserListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.User; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class UserListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/UserRoleListResponse.java b/src/main/java/id/go/polri/tte/responses/UserRoleListResponse.java new file mode 100644 index 0000000..e8fda71 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/UserRoleListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.UserRole; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class UserRoleListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/UserRoleSingleResponse.java b/src/main/java/id/go/polri/tte/responses/UserRoleSingleResponse.java new file mode 100644 index 0000000..eac10c5 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/UserRoleSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.UserRole; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class UserRoleSingleResponse extends BasicResponse { + + private UserRole data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/UserSignatureListResponse.java b/src/main/java/id/go/polri/tte/responses/UserSignatureListResponse.java new file mode 100644 index 0000000..8883653 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/UserSignatureListResponse.java @@ -0,0 +1,19 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.UserSignature; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class UserSignatureListResponse extends BasicResponse { + + private List data; + private int recordsTotal; + private int recordsFiltered; + +} diff --git a/src/main/java/id/go/polri/tte/responses/UserSignatureSingleResponse.java b/src/main/java/id/go/polri/tte/responses/UserSignatureSingleResponse.java new file mode 100644 index 0000000..f78d6a9 --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/UserSignatureSingleResponse.java @@ -0,0 +1,15 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.UserSignature; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class UserSignatureSingleResponse extends BasicResponse { + + private UserSignature data; + +} diff --git a/src/main/java/id/go/polri/tte/responses/UserSingleResponse.java b/src/main/java/id/go/polri/tte/responses/UserSingleResponse.java new file mode 100644 index 0000000..4a68cbe --- /dev/null +++ b/src/main/java/id/go/polri/tte/responses/UserSingleResponse.java @@ -0,0 +1,14 @@ +package id.go.polri.tte.responses; + +import id.go.polri.tte.models.User; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.SuperBuilder; + +@EqualsAndHashCode(callSuper = true) +@Data +@SuperBuilder +public class UserSingleResponse extends BasicResponse { + + private Object data; +} diff --git a/src/main/java/id/go/polri/tte/services/EmailService.java b/src/main/java/id/go/polri/tte/services/EmailService.java new file mode 100644 index 0000000..a70884f --- /dev/null +++ b/src/main/java/id/go/polri/tte/services/EmailService.java @@ -0,0 +1,78 @@ +package id.go.polri.tte.services; + +import jakarta.mail.*; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; +import java.nio.charset.StandardCharsets; +import java.util.Properties; +import java.time.Year; + +public class EmailService { + private final String username; + private final String password; + private final String host; + private final int port; + private final String encryption; + private final String fromAddress; + private final String fromName; + + public EmailService(String username, String password, String host, int port, String encryption, String fromAddress, String fromName) { + this.username = username; + this.password = password; + this.host = host; + this.port = port; + this.encryption = encryption; + this.fromAddress = fromAddress; + this.fromName = fromName; + } + + private String loadHtmlTemplate(String templateName) { + try (var inputStream = getClass().getClassLoader().getResourceAsStream("templates/" + templateName)) { + if (inputStream == null) { + throw new RuntimeException("Template not found: " + templateName); + } + return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); + } catch (Exception e) { + throw new RuntimeException("Error reading template", e); + } + } + + public void sendOtpEmail(String recipientEmail, String otpCode) { + Properties props = new Properties(); + props.put("mail.smtp.auth", "true"); + + if (encryption.equalsIgnoreCase("ssl")) { + props.put("mail.smtp.socketFactory.port", String.valueOf(port)); + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.fallback", "false"); + } else if (encryption.equalsIgnoreCase("tls")) { + props.put("mail.smtp.starttls.enable", "true"); + } + + props.put("mail.smtp.host", host); + props.put("mail.smtp.port", String.valueOf(port)); + + Session session = Session.getInstance(props, new Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + + try { + String htmlTemplate = loadHtmlTemplate("otp-email.html"); + String emailBody = String.format(htmlTemplate, otpCode, Year.now().getValue()); + + Message message = new MimeMessage(session); + message.setFrom(new InternetAddress(fromAddress, fromName)); + message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail)); + message.setSubject("Kode OTP Anda"); + message.setContent(emailBody, "text/html; charset=utf-8"); + + Transport.send(message); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} + diff --git a/src/main/java/id/go/polri/tte/services/NotificationService.java b/src/main/java/id/go/polri/tte/services/NotificationService.java new file mode 100644 index 0000000..3617479 --- /dev/null +++ b/src/main/java/id/go/polri/tte/services/NotificationService.java @@ -0,0 +1,117 @@ +package id.go.polri.tte.services; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.mail.*; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Year; +import java.util.Properties; + +public class NotificationService { + private final String username; + private final String password; + private final String host; + private final int port; + private final String encryption; + private final String fromAddress; + private final String fromName; + private final String otpApiBaseUrl; + private final String otpApiToken; + private final HttpClient httpClient; + + public NotificationService(String username, String password, String host, int port, String encryption, + String fromAddress, String fromName, String otpApiBaseUrl, String otpApiToken) { + this.username = username; + this.password = password; + this.host = host; + this.port = port; + this.encryption = encryption; + this.fromAddress = fromAddress; + this.fromName = fromName; + this.otpApiBaseUrl = otpApiBaseUrl; + this.otpApiToken = otpApiToken; + this.httpClient = HttpClient.newHttpClient(); + } + + private String loadHtmlTemplate(String templateName) { + try (var inputStream = getClass().getClassLoader().getResourceAsStream("templates/" + templateName)) { + if (inputStream == null) { + throw new RuntimeException("Template not found: " + templateName); + } + return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); + } catch (Exception e) { + throw new RuntimeException("Error reading template", e); + } + } + + public void sendEmailNotification(String recipientEmail, String file_id, String signing_id) { + Properties props = new Properties(); + props.put("mail.smtp.auth", "true"); + + if (encryption.equalsIgnoreCase("ssl")) { + props.put("mail.smtp.socketFactory.port", String.valueOf(port)); + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.fallback", "false"); + } else if (encryption.equalsIgnoreCase("tls")) { + props.put("mail.smtp.starttls.enable", "true"); + } + + props.put("mail.smtp.host", host); + props.put("mail.smtp.port", String.valueOf(port)); + + Session session = Session.getInstance(props, new Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + + try { + String htmlTemplate = loadHtmlTemplate("notification-email.html"); + String emailBody = htmlTemplate + .replace("${file_id}", file_id) + .replace("${signing_id}", signing_id) + .replace("${year}", String.valueOf(Year.now().getValue())); + Message message = new MimeMessage(session); + message.setFrom(new InternetAddress(fromAddress, fromName)); + message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientEmail)); + message.setSubject("Dokumen Baru Tersedia"); + message.setContent(emailBody, "text/html; charset=utf-8"); + + Transport.send(message); + } catch (Exception e) { + throw new RuntimeException("Failed to send email", e); + } + } + + public String sendWhatsAppNotification(String phoneNumber, String message) { + try { + ObjectMapper objectMapper = new ObjectMapper(); + String jsonPayload = objectMapper.createObjectNode() + .put("content", message) + .put("contactMsisdn", phoneNumber) + .toString(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(otpApiBaseUrl)) + .header("Authorization", "Bearer " + otpApiToken) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(jsonPayload)) + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + JsonNode jsonResponse = objectMapper.readTree(response.body()); + System.out.println("WhatsApp Response: " + jsonResponse); + return response.body(); + } catch (Exception e) { + throw new RuntimeException("Failed to send WhatsApp notification", e); + } + } +} diff --git a/src/main/java/id/go/polri/tte/services/StatusBsreService.java b/src/main/java/id/go/polri/tte/services/StatusBsreService.java new file mode 100644 index 0000000..5fac776 --- /dev/null +++ b/src/main/java/id/go/polri/tte/services/StatusBsreService.java @@ -0,0 +1,127 @@ +package id.go.polri.tte.services; + +import id.go.polri.tte.models.User; +import id.go.polri.tte.repositories.jdbi.UserRepository; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Base64; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.List; +import java.util.Map; + +import org.jdbi.v3.core.Jdbi; +import org.jdbi.v3.core.mapper.reflect.BeanMapper; +import com.google.common.util.concurrent.RateLimiter; + +public class StatusBsreService { + + private static final Logger logger = LoggerFactory.getLogger(StatusBsreService.class); + private final HttpClient httpClient; + private final String bsreApiUrl; + private final String username; + private final String password; + protected final Jdbi jdbi; + private final double rateLimitPerSecond; + + // Konstruktor dengan dependency injection + public StatusBsreService(String bsreApiUrl, String username, String password, int delayInSeconds, Jdbi jdbi) { + this.httpClient = HttpClient.newHttpClient(); + this.bsreApiUrl = bsreApiUrl; + this.username = username; + this.password = password; + this.jdbi = jdbi; + this.rateLimitPerSecond = delayInSeconds > 0 ? 1.0 / delayInSeconds : 5.0; + } + + public void checkAllUserStatus(int delayInSeconds) { + logger.info("Starting to check status for all users..."); + long startTime = System.currentTimeMillis(); + List niks = jdbi.withHandle(handle -> + handle.createQuery("SELECT nik FROM users WHERE nik IS NOT NULL AND nik <> ''") + .mapTo(String.class) + .list() + ); + logger.info("Found {} users to check.", niks.size()); + RateLimiter limiter = RateLimiter.create(rateLimitPerSecond); + int processed = 0; + int error = 0; + + for (String nik : niks) { + limiter.acquire(); // Rate-limiting here + logger.info("Checking status for user with NIK: {}", nik); + + boolean success = false; + int attempt = 0; + int maxRetries = 8; + + while (!success && attempt < maxRetries) { + attempt++; + try { + String auth = username + ":" + password; + String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes()); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(bsreApiUrl + "/api/user/status/" + nik)) + .header("Authorization", "Basic " + encodedAuth) + .GET() + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonResponse = objectMapper.readTree(response.body()); + String statusBaru = jsonResponse.path("status").asText(); + logger.info("Received status '{}' for user: {}", statusBaru, nik); + + jdbi.useHandle(handle -> { + handle.createUpdate("UPDATE users SET response_status = :response_status, updated_at = CURRENT_TIMESTAMP WHERE nik = :nik") + .bind("response_status", statusBaru) + .bind("nik", nik) + .execute(); + }); + + logger.info("Updated status for user {}: {}", nik, statusBaru); + success = true; + + } else { + logger.warn("Attempt {}: Failed to get status for user {}. Status code: {}", attempt, nik, response.statusCode()); + } + + } catch (Exception e) { + logger.warn("Attempt {}: Error processing user {}: {}", attempt, nik, e.getMessage()); + } + + if (!success && attempt < maxRetries) { + try { + Thread.sleep(200); // Delay before retry (1 second) + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + logger.error("Retry sleep interrupted for user {}", nik); + break; + } + } + } + + if (!success) { + logger.error("All retry attempts failed for user: {}", nik); + error++; + } + + processed++; + } + + long endTime = System.currentTimeMillis(); + long durationInSeconds = (endTime - startTime) / 1000; + + logger.info("Finished checking status for all users."); + logger.info("Processed {} users in {} seconds.", processed, durationInSeconds); + logger.info("Error Users {}", error); + } + +} diff --git a/src/main/java/id/go/polri/tte/utility/CephUtility.java b/src/main/java/id/go/polri/tte/utility/CephUtility.java new file mode 100644 index 0000000..8e4c9a0 --- /dev/null +++ b/src/main/java/id/go/polri/tte/utility/CephUtility.java @@ -0,0 +1,85 @@ +package id.go.polri.tte.utility; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.S3Configuration; +import software.amazon.awssdk.services.s3.model.GetObjectResponse; +import software.amazon.awssdk.services.s3.model.ObjectCannedACL; +import software.amazon.awssdk.services.s3.model.PutObjectResponse; + +import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.ByteBuffer; +import java.nio.file.Paths; + +public class CephUtility { + private static final Logger logger = LoggerFactory.getLogger(CephUtility.class); + private final String endpoint; + private final String bucketName; + private final AwsBasicCredentials credentials; + + public CephUtility(String endpoint, String accessKey, String secretKey, String bucketName) { + this.endpoint = endpoint; + this.bucketName = bucketName; + + credentials = AwsBasicCredentials.create(accessKey, secretKey); + } + + public boolean upload(String objectname, String filename) { + boolean success = false; + try (S3Client client = S3Client.builder() + .endpointOverride(new URI(endpoint)) + .credentialsProvider(StaticCredentialsProvider.create(credentials)) + .serviceConfiguration(S3Configuration.Builder::pathStyleAccessEnabled) + .region(Region.US_EAST_1) // this is not used, but the AWS SDK requires it + .build()) { + File file = new File(filename); + try (InputStream is = new FileInputStream(file)) { + byte[] bytes = is.readAllBytes(); + ByteBuffer input = ByteBuffer.wrap(bytes); + PutObjectResponse response = client.putObject( + req -> { + req.bucket(this.bucketName) + .key(objectname) + .acl(ObjectCannedACL.AUTHENTICATED_READ);; + }, + RequestBody.fromByteBuffer(input) + ); + + success = response.sdkHttpResponse().isSuccessful(); + } catch (FileNotFoundException e) { + logger.error(e.getMessage(), e); + } + } catch (IOException | URISyntaxException e) { + logger.error(e.getMessage(), e); + } + return success; + } + + public boolean download(String objectname, String output) { + boolean success = false; + try (S3Client client = S3Client.builder() + .endpointOverride(new URI(endpoint)) + .credentialsProvider(StaticCredentialsProvider.create(credentials)) + .serviceConfiguration(S3Configuration.Builder::pathStyleAccessEnabled) + .region(Region.US_EAST_1) // this is not used, but the AWS SDK requires it + .build()) { + GetObjectResponse response = client.getObject( + req -> { + req.bucket(this.bucketName).key(objectname); + }, + Paths.get(output) + ); + success = response.sdkHttpResponse().isSuccessful();; + } catch (URISyntaxException e) { + logger.error(e.getMessage(), e); + } + return success; + } +} diff --git a/src/main/java/id/go/polri/tte/utility/JwtUtil.java b/src/main/java/id/go/polri/tte/utility/JwtUtil.java new file mode 100644 index 0000000..98059ed --- /dev/null +++ b/src/main/java/id/go/polri/tte/utility/JwtUtil.java @@ -0,0 +1,64 @@ +package id.go.polri.tte.utility; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.Keys; + +import java.security.Key; +import java.util.*; + +public class JwtUtil { + private final String secret; + private final long expirationTime; + private final Key key; + + public JwtUtil(String secret, long expirationTime) { + this.secret =secret; + this.expirationTime = expirationTime * 1000; // in milliseconds + this.key = Keys.hmacShaKeyFor(secret.getBytes()); + } + + public Claims getAllClaimsFromToken(String token) { + return Jwts.parserBuilder() + .setSigningKey(key) + .build() + .parseClaimsJws(token) + .getBody(); + } + + public String getSubjectFromToken(String token) { + return getAllClaimsFromToken(token).getSubject(); + } + + public Date getExpirationDateFromToken(String token) { + return getAllClaimsFromToken(token).getExpiration(); + } + + private Boolean isTokenExpired(String token) { + final Date expiration = getExpirationDateFromToken(token); + return expiration.before(new Date()); + } + + public String generateToken(String subject, String[] role) { + Map claims = new HashMap<>(); + claims.put("role", Arrays.asList(role)); + return doGenerateToken(claims, subject); + } + + private String doGenerateToken(Map claims, String subject) { + final Date createdDate = new Date(); + final Date expirationDate = new Date(createdDate.getTime() + expirationTime); + + return Jwts.builder() + .setClaims(claims) + .setSubject(subject) + .setIssuedAt(createdDate) + .setExpiration(expirationDate) + .signWith(key) + .compact(); + } + + public Boolean validateToken(String token) { + return !isTokenExpired(token); + } +} diff --git a/src/main/resources/templates/notification-email.html b/src/main/resources/templates/notification-email.html new file mode 100644 index 0000000..4b1c5c6 --- /dev/null +++ b/src/main/resources/templates/notification-email.html @@ -0,0 +1,29 @@ + + + + + + Sertifikat Elektronik POLRI + + + +
+

Sertifikat Elektronik POLRI

+

Terdapat dokumen baru yang membutuhkan tindak lanjut pada aplikasi TTE POLRI.

+

+ Buka Dokumen +

+ +
+ + \ No newline at end of file diff --git a/src/main/resources/templates/otp-email.html b/src/main/resources/templates/otp-email.html new file mode 100644 index 0000000..3197b1d --- /dev/null +++ b/src/main/resources/templates/otp-email.html @@ -0,0 +1,370 @@ + + + + + + Sertifikat Elektronik POLRI + + + +Masukkan kode OTP di aplikasi + + + + + + + + + diff --git a/src/test/java/app/IntegrationTest.java b/src/test/java/app/IntegrationTest.java new file mode 100644 index 0000000..965b8a7 --- /dev/null +++ b/src/test/java/app/IntegrationTest.java @@ -0,0 +1,31 @@ +package app; + +import id.go.polri.tte.app.App; +import io.jooby.test.JoobyTest; +import io.jooby.StatusCode; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@JoobyTest(App.class) +public class IntegrationTest { + + static OkHttpClient client = new OkHttpClient(); + + @Test + public void shouldSayHi(int serverPort) throws IOException { + Request req = new Request.Builder() + .url("http://localhost:" + serverPort) + .build(); + + try (Response rsp = client.newCall(req).execute()) { + assertEquals("Welcome to Jooby!", rsp.body().string()); + assertEquals(StatusCode.OK.value(), rsp.code()); + } + } +} diff --git a/src/test/java/app/UnitTest.java b/src/test/java/app/UnitTest.java new file mode 100644 index 0000000..03104c8 --- /dev/null +++ b/src/test/java/app/UnitTest.java @@ -0,0 +1,12 @@ +package app; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class UnitTest { + @Test + public void welcome() { + + } +}