Compare commits
18 Commits
af80d8c7f6
...
a22a7a1aeb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a22a7a1aeb | ||
|
|
d335b70b37 | ||
|
|
c4e95e61a9 | ||
|
|
1bcc642c49 | ||
|
|
3fe7000d53 | ||
|
|
35667518a7 | ||
|
|
6ac3798ea8 | ||
|
|
14f5850629 | ||
|
|
37ed3f76f3 | ||
|
|
ab08cbf9e2 | ||
|
|
776b66fcd7 | ||
|
|
7819357450 | ||
|
|
7c599770d7 | ||
|
|
604ea38b61 | ||
|
|
d9a5717836 | ||
|
|
b8c63c6221 | ||
|
|
c64f46ce82 | ||
|
|
2ca3cf3564 |
+14
-13
@@ -4,36 +4,37 @@ GIN_MODE=debug
|
||||
|
||||
# Default Database Configuration (PostgreSQL)
|
||||
DB_ANTRIAN_CONNECTION=postgres
|
||||
DB_ANTRIAN_USERNAME=rssa
|
||||
DB_ANTRIAN_USERNAME=user
|
||||
DB_ANTRIAN_PASSWORD=supersecret
|
||||
DB_ANTRIAN_HOST=localhost
|
||||
DB_ANTRIAN_DATABASE=antrian_operasi
|
||||
DB_ANTRIAN_DATABASE=my_db
|
||||
DB_ANTRIAN_PORT=5432
|
||||
DB_ANTRIAN_SSLMODE=disable
|
||||
|
||||
# DATABASE SIMRS
|
||||
DB_SIMRS_CONNECTION=postgres
|
||||
DB_SIMRS_USERNAME=brawijaya
|
||||
DB_SIMRS_PASSWORD=ub*2025
|
||||
DB_SIMRS_HOST=10.10.123.238
|
||||
DB_SIMRS_DATABASE=simrs
|
||||
DB_SIMRS_USERNAME=user
|
||||
DB_SIMRS_PASSWORD=supersecret
|
||||
DB_SIMRS_HOST=localhost
|
||||
DB_SIMRS_DATABASE=my_db
|
||||
DB_SIMRS_PORT=5432
|
||||
DB_SIMRS_SSLMODE=disable
|
||||
|
||||
SECURITY_TRUSTED_ORIGINS=http://localhost:3000
|
||||
|
||||
# DB SATU DATA DEV
|
||||
DB_ANTRIAN_CONNECTION=postgres
|
||||
DB_ANTRIAN_USERNAME=stim
|
||||
DB_ANTRIAN_PASSWORD=stim*RS54
|
||||
DB_ANTRIAN_HOST=10.10.123.165
|
||||
DB_ANTRIAN_DATABASE=satu_db
|
||||
DB_ANTRIAN_PORT=5000
|
||||
DB_ANTRIAN_SSLMODE=disable
|
||||
DB_ROLE_ACCESS_CONNECTION=postgres
|
||||
DB_ROLE_ACCESS_USERNAME=user
|
||||
DB_ROLE_ACCESS_PASSWORD=supersecret
|
||||
DB_ROLE_ACCESS_HOST=localhost
|
||||
DB_ROLE_ACCESS_DATABASE=my_db
|
||||
DB_ROLE_ACCESS_PORT=5432
|
||||
DB_ROLE_ACCESS_SSLMODE=disable
|
||||
|
||||
#KEYCLOAK CREDENTIAL
|
||||
KEYCLOAK_BASE_URL=https://keycloak.example.com
|
||||
KEYCLOAK_REALM=myrealm
|
||||
KEYCLOAK_AUDIENCE=my-client-id
|
||||
KEYCLOAK_SECRET_KEY=super-secret
|
||||
KEYCLOAK_ISSUER=https://keycloak.example.com/realms/myrealm
|
||||
KEYCLOAK_IS_ENABLE=false
|
||||
+1
-1
@@ -38,7 +38,7 @@ func gracefulShutdown(apiServer *http.Server, done chan bool) {
|
||||
// @title Antrian Operasi API
|
||||
// @version 1.0
|
||||
// @description Dokumentasi API Antrian Operasi
|
||||
// @host localhost:8080
|
||||
// @host 10.10.150.184:8080
|
||||
// @BasePath /api
|
||||
|
||||
// @securityDefinitions.apikey BearerAuth
|
||||
|
||||
+368
-4
@@ -15,6 +15,192 @@ const docTemplate = `{
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/access/eligible-menu": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Access Role"
|
||||
],
|
||||
"summary": "Get Pages By Keycloak Id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Keycloak ID",
|
||||
"name": "keycloak_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/access/list-user": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Access Role"
|
||||
],
|
||||
"summary": "Get List User And Role",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Search Keyword",
|
||||
"name": "search",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "10",
|
||||
"description": "Limit",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "0",
|
||||
"description": "Offset",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/access.UserRoleResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/access/role-permission": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Access Role"
|
||||
],
|
||||
"summary": "Get List Role Page Settings",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Search Keyword",
|
||||
"name": "search",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "10",
|
||||
"description": "Limit",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "0",
|
||||
"description": "Offset",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/access.ListRolePermissionPaginateResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/access/role-permission/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Access Role"
|
||||
],
|
||||
"summary": "Detail Role Page Settings",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id role",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/access.DetailRolePageResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/access/sync-keycloak-role": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Access Role"
|
||||
],
|
||||
"summary": "Sync Keycloak Role",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Sync Keycloak Role",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/access.SyncKeycloakRoleRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/antrian-operasi/": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -504,6 +690,39 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/keycloak/refresh-token": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Keycloak"
|
||||
],
|
||||
"summary": "Requesting new token to keycloak using refresh token",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Valid Refresh Token",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/keycloak.RefreshTokenRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/reference/diagnosa/": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -757,6 +976,116 @@ const docTemplate = `{
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"access.AccessPage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"page": {
|
||||
"type": "string"
|
||||
},
|
||||
"parent_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"access.DetailRolePageResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"access_page": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/access.AccessPage"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"access.ListRolePermissionPaginateResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/access.RolePermissionModel"
|
||||
}
|
||||
},
|
||||
"paging": {
|
||||
"$ref": "#/definitions/shared.PaginationInfo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"access.RolePermissionModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"access.SyncKeycloakRoleRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"email",
|
||||
"keycloak_id",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"client_role": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"keycloak_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"access.UserRoleResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"hak_akses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"antrianoperasi.CreatePasienOperasiRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -875,8 +1204,7 @@ const docTemplate = `{
|
||||
"jenisKelamin",
|
||||
"namaPasien",
|
||||
"noKtp",
|
||||
"noRekamMedis",
|
||||
"nomorTelepon"
|
||||
"noRekamMedis"
|
||||
],
|
||||
"properties": {
|
||||
"alamat": {
|
||||
@@ -900,7 +1228,6 @@ const docTemplate = `{
|
||||
},
|
||||
"nomorTelepon": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -1247,6 +1574,17 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"keycloak.RefreshTokenRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"refresh_token"
|
||||
],
|
||||
"properties": {
|
||||
"refresh_token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pasien.PasienResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1339,6 +1677,32 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"shared.PaginationInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"currentPage": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hasNext": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hasPrev": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"limit": {
|
||||
"type": "integer"
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
},
|
||||
"totalPages": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"spesialis.SpesialisModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1408,7 +1772,7 @@ const docTemplate = `{
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = &swag.Spec{
|
||||
Version: "1.0",
|
||||
Host: "localhost:8080",
|
||||
Host: "10.10.150.184:8080",
|
||||
BasePath: "/api",
|
||||
Schemes: []string{},
|
||||
Title: "Antrian Operasi API",
|
||||
|
||||
+368
-4
@@ -6,9 +6,195 @@
|
||||
"contact": {},
|
||||
"version": "1.0"
|
||||
},
|
||||
"host": "localhost:8080",
|
||||
"host": "10.10.150.184:8080",
|
||||
"basePath": "/api",
|
||||
"paths": {
|
||||
"/access/eligible-menu": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Access Role"
|
||||
],
|
||||
"summary": "Get Pages By Keycloak Id",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Keycloak ID",
|
||||
"name": "keycloak_id",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/access/list-user": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Access Role"
|
||||
],
|
||||
"summary": "Get List User And Role",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Search Keyword",
|
||||
"name": "search",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "10",
|
||||
"description": "Limit",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "0",
|
||||
"description": "Offset",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/access.UserRoleResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/access/role-permission": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Access Role"
|
||||
],
|
||||
"summary": "Get List Role Page Settings",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Search Keyword",
|
||||
"name": "search",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "10",
|
||||
"description": "Limit",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "0",
|
||||
"description": "Offset",
|
||||
"name": "offset",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/access.ListRolePermissionPaginateResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/access/role-permission/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Access Role"
|
||||
],
|
||||
"summary": "Detail Role Page Settings",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "id role",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/access.DetailRolePageResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/access/sync-keycloak-role": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Access Role"
|
||||
],
|
||||
"summary": "Sync Keycloak Role",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Sync Keycloak Role",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/access.SyncKeycloakRoleRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/antrian-operasi/": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -498,6 +684,39 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/keycloak/refresh-token": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Keycloak"
|
||||
],
|
||||
"summary": "Requesting new token to keycloak using refresh token",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Valid Refresh Token",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/keycloak.RefreshTokenRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/shared.BaseErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/reference/diagnosa/": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -751,6 +970,116 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"access.AccessPage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"page": {
|
||||
"type": "string"
|
||||
},
|
||||
"parent_id": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"access.DetailRolePageResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"access_page": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/access.AccessPage"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"access.ListRolePermissionPaginateResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/access.RolePermissionModel"
|
||||
}
|
||||
},
|
||||
"paging": {
|
||||
"$ref": "#/definitions/shared.PaginationInfo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"access.RolePermissionModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is_active": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"access.SyncKeycloakRoleRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"email",
|
||||
"keycloak_id",
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"client_role": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"keycloak_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"access.UserRoleResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"hak_akses": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"antrianoperasi.CreatePasienOperasiRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -869,8 +1198,7 @@
|
||||
"jenisKelamin",
|
||||
"namaPasien",
|
||||
"noKtp",
|
||||
"noRekamMedis",
|
||||
"nomorTelepon"
|
||||
"noRekamMedis"
|
||||
],
|
||||
"properties": {
|
||||
"alamat": {
|
||||
@@ -894,7 +1222,6 @@
|
||||
},
|
||||
"nomorTelepon": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -1241,6 +1568,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"keycloak.RefreshTokenRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"refresh_token"
|
||||
],
|
||||
"properties": {
|
||||
"refresh_token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pasien.PasienResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -1333,6 +1671,32 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"shared.PaginationInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"currentPage": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hasNext": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hasPrev": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"limit": {
|
||||
"type": "integer"
|
||||
},
|
||||
"offset": {
|
||||
"type": "integer"
|
||||
},
|
||||
"total": {
|
||||
"type": "integer"
|
||||
},
|
||||
"totalPages": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
},
|
||||
"spesialis.SpesialisModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
+239
-3
@@ -1,5 +1,77 @@
|
||||
basePath: /api
|
||||
definitions:
|
||||
access.AccessPage:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
is_active:
|
||||
type: boolean
|
||||
page:
|
||||
type: string
|
||||
parent_id:
|
||||
type: string
|
||||
type: object
|
||||
access.DetailRolePageResponse:
|
||||
properties:
|
||||
access_page:
|
||||
items:
|
||||
$ref: '#/definitions/access.AccessPage'
|
||||
type: array
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
status:
|
||||
type: boolean
|
||||
type: object
|
||||
access.ListRolePermissionPaginateResponse:
|
||||
properties:
|
||||
data:
|
||||
items:
|
||||
$ref: '#/definitions/access.RolePermissionModel'
|
||||
type: array
|
||||
paging:
|
||||
$ref: '#/definitions/shared.PaginationInfo'
|
||||
type: object
|
||||
access.RolePermissionModel:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
is_active:
|
||||
type: boolean
|
||||
name:
|
||||
type: string
|
||||
type: object
|
||||
access.SyncKeycloakRoleRequest:
|
||||
properties:
|
||||
client_role:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
email:
|
||||
type: string
|
||||
keycloak_id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- email
|
||||
- keycloak_id
|
||||
- name
|
||||
type: object
|
||||
access.UserRoleResponse:
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
hak_akses:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
type: object
|
||||
antrianoperasi.CreatePasienOperasiRequest:
|
||||
properties:
|
||||
diagnosisItems:
|
||||
@@ -94,7 +166,6 @@ definitions:
|
||||
nomorTelepon:
|
||||
items:
|
||||
type: string
|
||||
minItems: 1
|
||||
type: array
|
||||
tanggalLahir:
|
||||
type: string
|
||||
@@ -105,7 +176,6 @@ definitions:
|
||||
- namaPasien
|
||||
- noKtp
|
||||
- noRekamMedis
|
||||
- nomorTelepon
|
||||
type: object
|
||||
antrianoperasi.PasienOperasi:
|
||||
properties:
|
||||
@@ -327,6 +397,13 @@ definitions:
|
||||
- published
|
||||
type: string
|
||||
type: object
|
||||
keycloak.RefreshTokenRequest:
|
||||
properties:
|
||||
refresh_token:
|
||||
type: string
|
||||
required:
|
||||
- refresh_token
|
||||
type: object
|
||||
pasien.PasienResponse:
|
||||
properties:
|
||||
alamat:
|
||||
@@ -387,6 +464,23 @@ definitions:
|
||||
success:
|
||||
type: boolean
|
||||
type: object
|
||||
shared.PaginationInfo:
|
||||
properties:
|
||||
currentPage:
|
||||
type: integer
|
||||
hasNext:
|
||||
type: boolean
|
||||
hasPrev:
|
||||
type: boolean
|
||||
limit:
|
||||
type: integer
|
||||
offset:
|
||||
type: integer
|
||||
total:
|
||||
type: integer
|
||||
totalPages:
|
||||
type: integer
|
||||
type: object
|
||||
spesialis.SpesialisModel:
|
||||
properties:
|
||||
id:
|
||||
@@ -420,13 +514,134 @@ definitions:
|
||||
select:
|
||||
type: string
|
||||
type: object
|
||||
host: localhost:8080
|
||||
host: 10.10.150.184:8080
|
||||
info:
|
||||
contact: {}
|
||||
description: Dokumentasi API Antrian Operasi
|
||||
title: Antrian Operasi API
|
||||
version: "1.0"
|
||||
paths:
|
||||
/access/eligible-menu:
|
||||
get:
|
||||
parameters:
|
||||
- description: Keycloak ID
|
||||
in: query
|
||||
name: keycloak_id
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/shared.BaseResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/shared.BaseErrorResponse'
|
||||
summary: Get Pages By Keycloak Id
|
||||
tags:
|
||||
- Access Role
|
||||
/access/list-user:
|
||||
get:
|
||||
parameters:
|
||||
- description: Search Keyword
|
||||
in: query
|
||||
name: search
|
||||
type: string
|
||||
- default: "10"
|
||||
description: Limit
|
||||
in: query
|
||||
name: limit
|
||||
type: string
|
||||
- default: "0"
|
||||
description: Offset
|
||||
in: query
|
||||
name: offset
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/access.UserRoleResponse'
|
||||
type: array
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/shared.BaseErrorResponse'
|
||||
summary: Get List User And Role
|
||||
tags:
|
||||
- Access Role
|
||||
/access/role-permission:
|
||||
get:
|
||||
parameters:
|
||||
- description: Search Keyword
|
||||
in: query
|
||||
name: search
|
||||
type: string
|
||||
- default: "10"
|
||||
description: Limit
|
||||
in: query
|
||||
name: limit
|
||||
type: string
|
||||
- default: "0"
|
||||
description: Offset
|
||||
in: query
|
||||
name: offset
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/access.ListRolePermissionPaginateResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/shared.BaseErrorResponse'
|
||||
summary: Get List Role Page Settings
|
||||
tags:
|
||||
- Access Role
|
||||
/access/role-permission/{id}:
|
||||
get:
|
||||
parameters:
|
||||
- description: id role
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/access.DetailRolePageResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/shared.BaseErrorResponse'
|
||||
summary: Detail Role Page Settings
|
||||
tags:
|
||||
- Access Role
|
||||
/access/sync-keycloak-role:
|
||||
post:
|
||||
parameters:
|
||||
- description: Sync Keycloak Role
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/access.SyncKeycloakRoleRequest'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/shared.BaseResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/shared.BaseErrorResponse'
|
||||
summary: Sync Keycloak Role
|
||||
tags:
|
||||
- Access Role
|
||||
/antrian-operasi/:
|
||||
get:
|
||||
parameters:
|
||||
@@ -747,6 +962,27 @@ paths:
|
||||
summary: Get Table Antrian per Sub Spesialis
|
||||
tags:
|
||||
- Dashboard
|
||||
/keycloak/refresh-token:
|
||||
post:
|
||||
parameters:
|
||||
- description: Valid Refresh Token
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/keycloak.RefreshTokenRequest'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/shared.BaseResponse'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/shared.BaseErrorResponse'
|
||||
summary: Requesting new token to keycloak using refresh token
|
||||
tags:
|
||||
- Keycloak
|
||||
/reference/diagnosa/:
|
||||
get:
|
||||
parameters:
|
||||
|
||||
@@ -28,6 +28,7 @@ func LoadConfig() *Config {
|
||||
Realm: getEnv("KEYCLOAK_REALM", "sandbox"),
|
||||
Audience: getEnv("KEYCLOAK_AUDIENCE", "akbar-test"),
|
||||
Issuer: getEnv("KEYCLOAK_ISSUER", "https://auth.rssa.top/realms/sandbox"),
|
||||
SecretKey: getEnv("KEYCLOAK_SECRET_KEY", ""),
|
||||
IsEnabled: getEnvAsBool("KEYCLOAK_IS_ENABLE", false),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -55,5 +55,6 @@ type KeycloakConfig struct {
|
||||
Realm string
|
||||
Audience string
|
||||
Issuer string
|
||||
SecretKey string
|
||||
IsEnabled bool
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
package access
|
||||
|
||||
import (
|
||||
"antrian-operasi/internal/shared"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type AccessHandler struct {
|
||||
repo IAccessRepository
|
||||
}
|
||||
|
||||
func NewAccessHandler(repo IAccessRepository) AccessHandler {
|
||||
return AccessHandler{repo}
|
||||
}
|
||||
|
||||
// SyncKeycloakRole godoc
|
||||
// @Summary Sync Keycloak Role
|
||||
// @Tags Access Role
|
||||
// @Param body body SyncKeycloakRoleRequest true "Sync Keycloak Role"
|
||||
// @Success 200 {object} shared.BaseResponse
|
||||
// @Failure 500 {object} shared.BaseErrorResponse
|
||||
// @Router /access/sync-keycloak-role [post]
|
||||
func (h AccessHandler) SyncKeycloakRole(c *gin.Context) {
|
||||
var req SyncKeycloakRoleRequest
|
||||
|
||||
//bind json body
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(400, shared.BaseErrorResponse{
|
||||
Success: false,
|
||||
Code: 400,
|
||||
Message: "error bind json",
|
||||
Errors: shared.ValidationError(err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
//check user role exist
|
||||
users, err := h.repo.FindUserByKeycloakId(c, req.KeycloakId)
|
||||
if err != nil {
|
||||
errMessage := []string{err.Error()}
|
||||
c.JSON(500, shared.BaseErrorResponse{
|
||||
Success: false,
|
||||
Code: 500,
|
||||
Message: "error finding user by keycloak id",
|
||||
Errors: errMessage,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
//if not exist, create user & permission
|
||||
if len(users) == 0 {
|
||||
err = h.repo.CreateUserPermission(c, req)
|
||||
} else { //if exist, update role permission
|
||||
userId := users[0].ID
|
||||
err = h.repo.UpdateUserPermission(c, userId, req)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
errMessage := []string{err.Error()}
|
||||
c.JSON(500, shared.BaseErrorResponse{
|
||||
Success: false,
|
||||
Code: 500,
|
||||
Message: "update / insert permission error",
|
||||
Errors: errMessage,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, shared.BaseResponse[SyncKeycloakRoleRequest]{
|
||||
Success: true,
|
||||
Code: 200,
|
||||
Message: "success sync role",
|
||||
Data: req,
|
||||
})
|
||||
}
|
||||
|
||||
// GetPageByKeycloakId godoc
|
||||
// @Summary Get Pages By Keycloak Id
|
||||
// @Tags Access Role
|
||||
// @Param keycloak_id query string true "Keycloak ID"
|
||||
// @Success 200 {object} shared.BaseResponse
|
||||
// @Failure 500 {object} shared.BaseErrorResponse
|
||||
// @Router /access/eligible-menu [get]
|
||||
func (h AccessHandler) GetPageByKeycloakId(c *gin.Context) {
|
||||
keycloakId := c.Query("keycloak_id")
|
||||
|
||||
pageResult, err := h.repo.GetAvailablePageByKeycloakId(c, keycloakId)
|
||||
if err != nil {
|
||||
errMessage := []string{err.Error()}
|
||||
c.JSON(500, shared.BaseErrorResponse{
|
||||
Success: false,
|
||||
Code: 500,
|
||||
Message: "error fetch page by keycloak id",
|
||||
Errors: errMessage,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, shared.BaseResponse[[]AvailableMenuResponse]{
|
||||
Success: true,
|
||||
Code: 200,
|
||||
Message: "success fetch eligible page",
|
||||
Data: MapMenuModelToResponse(pageResult),
|
||||
})
|
||||
}
|
||||
|
||||
// ListUserRole godoc
|
||||
// @Summary Get List User And Role
|
||||
// @Tags Access Role
|
||||
// @Param search query string false "Search Keyword"
|
||||
// @Param limit query string false "Limit" default(10)
|
||||
// @Param offset query string false "Offset" default(0)
|
||||
// @Success 200 {object} []UserRoleResponse
|
||||
// @Failure 500 {object} shared.BaseErrorResponse
|
||||
// @Router /access/list-user [get]
|
||||
func (h AccessHandler) ListUserRole(c *gin.Context) {
|
||||
var query QueryListUserRole
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
res, err := h.repo.ListUserRole(c.Request.Context(), query)
|
||||
if err != nil {
|
||||
c.JSON(500, shared.BaseErrorResponse{
|
||||
Success: false,
|
||||
Code: 500,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200,
|
||||
shared.ToBaseResponsePaginate(
|
||||
res.Data, res.Paging, true, 200, "success get list user role",
|
||||
))
|
||||
}
|
||||
|
||||
// ListRolePageSettings godoc
|
||||
// @Summary Get List Role Page Settings
|
||||
// @Tags Access Role
|
||||
// @Param search query string false "Search Keyword"
|
||||
// @Param limit query string false "Limit" default(10)
|
||||
// @Param offset query string false "Offset" default(0)
|
||||
// @Success 200 {object} ListRolePermissionPaginateResponse
|
||||
// @Failure 500 {object} shared.BaseErrorResponse
|
||||
// @Router /access/role-permission [get]
|
||||
func (h AccessHandler) ListRolePageSettings(c *gin.Context) {
|
||||
var query QueryListRolePermission
|
||||
if err := c.ShouldBindQuery(&query); err != nil {
|
||||
c.JSON(400, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
res, err := h.repo.ListRolePermission(c.Request.Context(), query)
|
||||
if err != nil {
|
||||
c.JSON(500, shared.BaseErrorResponse{
|
||||
Success: false,
|
||||
Code: 500,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200,
|
||||
shared.ToBaseResponsePaginate(
|
||||
res.Data, res.Paging, true, 200, "success get list role permission",
|
||||
))
|
||||
}
|
||||
|
||||
// DetailRolePageSettings godoc
|
||||
// @Summary Detail Role Page Settings
|
||||
// @Tags Access Role
|
||||
// @Param id path string true "id role"
|
||||
// @Success 200 {object} DetailRolePageResponse
|
||||
// @Failure 500 {object} shared.BaseErrorResponse
|
||||
// @Router /access/role-permission/{id} [get]
|
||||
func (h AccessHandler) DetailRolePageSettings(c *gin.Context) {
|
||||
idPermission := c.Param("id")
|
||||
|
||||
res, err := h.repo.DetailRolePermission(c, idPermission)
|
||||
if err != nil {
|
||||
c.JSON(500, shared.BaseErrorResponse{
|
||||
Success: false,
|
||||
Code: 500,
|
||||
Message: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200,
|
||||
shared.ToBaseResponse(
|
||||
res, true, 200, "success get detail role permission",
|
||||
))
|
||||
}
|
||||
|
||||
func (h AccessHandler) UpdateRolePageSettings(c *gin.Context) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package access
|
||||
|
||||
import "database/sql"
|
||||
|
||||
type RolePermissionModel struct {
|
||||
ID string `db:"id" json:"id"`
|
||||
Name string `db:"name" json:"name"`
|
||||
IsActive bool `db:"is_active" json:"is_active"`
|
||||
}
|
||||
|
||||
type RolePageModel struct {
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Icon sql.NullString `db:"icon"`
|
||||
Url sql.NullString `db:"url"`
|
||||
Level int `db:"level"`
|
||||
Sort int `db:"sort"`
|
||||
ParentId sql.NullString `db:"parent"`
|
||||
}
|
||||
|
||||
type RoleUserModel struct {
|
||||
ID string `db:"id"`
|
||||
Name string `db:"name"`
|
||||
Email string `db:"email"`
|
||||
KeycloakId string `db:"keycloak_id"`
|
||||
}
|
||||
|
||||
type RoleUserPermissionModel struct {
|
||||
ID string `db:"id"`
|
||||
IdUser string `db:"id_user"`
|
||||
IdPermission string `db:"id_permission"`
|
||||
PermissionName *string `db:"permission_name"`
|
||||
}
|
||||
|
||||
type RolePagePermissionModel struct {
|
||||
ID string `db:"id"`
|
||||
IdPermission string `db:"id_permission"`
|
||||
IdPage string `db:"id_page"`
|
||||
}
|
||||
@@ -0,0 +1,762 @@
|
||||
package access
|
||||
|
||||
import (
|
||||
"antrian-operasi/internal/database"
|
||||
queryUtils "antrian-operasi/internal/utils/query"
|
||||
"context"
|
||||
"database/sql"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
const DB_NAME = "db_role_access"
|
||||
const TBL_USER = "role_users"
|
||||
const TBL_PERMISSION = "role_permission"
|
||||
const TBL_USER_PERMISSION = "role_user_permission"
|
||||
const TBL_ROLE_PAGES = "role_pages"
|
||||
const TBL_PAGE_PERMISSION = "role_page_permission"
|
||||
|
||||
type IAccessRepository interface {
|
||||
FindUserByKeycloakId(c context.Context, id string) ([]RoleUserModel, error)
|
||||
CreateUserPermission(c context.Context, req SyncKeycloakRoleRequest) error
|
||||
UpdateUserPermission(c context.Context, userId string, req SyncKeycloakRoleRequest) error
|
||||
GetAvailablePageByKeycloakId(c context.Context, keycloakId string) ([]RolePageModel, error)
|
||||
ListUserRole(c context.Context, q QueryListUserRole) (ListUserRolePaginateResponse, error)
|
||||
ListRolePermission(c context.Context, q QueryListRolePermission) (ListRolePermissionPaginateResponse, error)
|
||||
DetailRolePermission(c context.Context, permission_id string) (DetailRolePageResponse, error)
|
||||
}
|
||||
|
||||
type accessRepo struct {
|
||||
queryBuilder *queryUtils.QueryBuilder
|
||||
db database.Service
|
||||
}
|
||||
|
||||
func NewRepository(dbService database.Service) IAccessRepository {
|
||||
queryBuilder := queryUtils.NewQueryBuilder(queryUtils.DBTypePostgreSQL).SetAllowedColumns([]string{
|
||||
"id", "name", "is_active", "keycloak_id", "id_user", "id_permission", "email", "created_at",
|
||||
}).SetAllowedTables([]string{TBL_USER})
|
||||
|
||||
queryBuilder.SetSecurityOptions(false, 100)
|
||||
|
||||
return accessRepo{
|
||||
queryBuilder: queryBuilder,
|
||||
db: dbService,
|
||||
}
|
||||
}
|
||||
|
||||
func (r accessRepo) FindUserByKeycloakId(c context.Context, id string) ([]RoleUserModel, error) {
|
||||
var result []RoleUserModel
|
||||
|
||||
query := queryUtils.DynamicQuery{
|
||||
From: TBL_USER,
|
||||
Fields: []queryUtils.SelectField{
|
||||
{Expression: "id"},
|
||||
{Expression: "keycloak_id"},
|
||||
},
|
||||
Filters: []queryUtils.FilterGroup{
|
||||
{
|
||||
Filters: []queryUtils.DynamicFilter{
|
||||
{Column: "keycloak_id", Operator: queryUtils.OpEqual, Value: id},
|
||||
}, LogicOp: "AND",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dbconn, err := r.db.GetSQLXDB(DB_NAME)
|
||||
if err != nil {
|
||||
log.Printf("Unable to connect db : %s", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
err = r.queryBuilder.ExecuteQuery(c, dbconn, query, &result)
|
||||
if err != nil {
|
||||
log.Printf("Unable to execute query search user : %s", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (r accessRepo) CreateUserPermission(c context.Context, req SyncKeycloakRoleRequest) error {
|
||||
db, err := r.db.GetSQLXDB(DB_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// START TRANSACTION
|
||||
tx, err := db.BeginTx(c, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// insert user
|
||||
userId, err := r.insertUser(c, tx, req)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.getOrCreateUserPermission(c, db, tx, userId, req.Roles)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r accessRepo) UpdateUserPermission(c context.Context, userId string, req SyncKeycloakRoleRequest) error {
|
||||
db, err := r.db.GetSQLXDB(DB_NAME)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// START TRANSACTION
|
||||
tx, err := db.BeginTx(c, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// delete all user permission
|
||||
err = r.deletePermissionByUserId(c, tx, userId)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.getOrCreateUserPermission(c, db, tx, userId, req.Roles)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r accessRepo) GetAvailablePageByKeycloakId(c context.Context, keycloakId string) ([]RolePageModel, error) {
|
||||
var result []RolePageModel
|
||||
|
||||
dbconn, err := r.db.GetSQLXDB(DB_NAME)
|
||||
if err != nil {
|
||||
log.Printf("Unable to connect db : %s", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
fetchUsers, err := r.FindUserByKeycloakId(c, keycloakId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(fetchUsers) == 0 {
|
||||
log.Printf("user not found, keycloak id : %s", keycloakId)
|
||||
return nil, err
|
||||
}
|
||||
user := &fetchUsers[0]
|
||||
|
||||
var permissionIds []string
|
||||
fetchUserPermission, err := r.getUserPermissionByUserId(c, dbconn, user.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, p := range fetchUserPermission {
|
||||
permissionIds = append(permissionIds, p.IdPermission)
|
||||
}
|
||||
|
||||
var pageIds []string
|
||||
fetchPagePermission, err := r.getPageIdsByPermissionIds(c, dbconn, permissionIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, pg := range fetchPagePermission {
|
||||
pageIds = append(pageIds, pg.IdPage)
|
||||
}
|
||||
|
||||
result, err = r.getPageByIds(c, dbconn, pageIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r accessRepo) ListUserRole(c context.Context, q QueryListUserRole) (ListUserRolePaginateResponse, error) {
|
||||
var result ListUserRolePaginateResponse
|
||||
|
||||
query := queryUtils.DynamicQuery{
|
||||
From: TBL_USER,
|
||||
Fields: []queryUtils.SelectField{
|
||||
{Expression: "id"},
|
||||
{Expression: "name"},
|
||||
{Expression: "email"},
|
||||
},
|
||||
Sort: []queryUtils.SortField{
|
||||
{Column: "created_at", Order: "DESC"},
|
||||
},
|
||||
}
|
||||
|
||||
if q.Search != "" {
|
||||
searchFilters := []queryUtils.DynamicFilter{
|
||||
{Column: "name", Operator: queryUtils.OpILike, Value: "%" + q.Search + "%"},
|
||||
{Column: "email", Operator: queryUtils.OpILike, Value: "%" + q.Search + "%"},
|
||||
}
|
||||
|
||||
query.Filters = append(query.Filters, queryUtils.FilterGroup{Filters: searchFilters, LogicOp: "OR"})
|
||||
}
|
||||
|
||||
dbconn, err := r.db.GetSQLXDB(DB_NAME)
|
||||
if err != nil {
|
||||
log.Printf("Unable to connect db : %s", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// query count
|
||||
countData, err := r.queryBuilder.ExecuteCount(c, dbconn, query)
|
||||
if err != nil {
|
||||
log.Printf("Unable to execute query count : %s ", err)
|
||||
return result, err
|
||||
}
|
||||
result.Paging.Limit = q.Limit
|
||||
result.Paging.Offset = q.Offset
|
||||
result.Paging.Total = int(countData)
|
||||
result.Paging.CalculatePagingInfo()
|
||||
|
||||
// query data
|
||||
queryData := query
|
||||
queryData.Limit = q.Limit
|
||||
queryData.Offset = q.Offset
|
||||
err = r.queryBuilder.ExecuteQuery(
|
||||
c, dbconn, queryData, &result.Data)
|
||||
if err != nil {
|
||||
log.Printf("Unable to execute query data : %s", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
userIds := make([]string, 0, len(result.Data))
|
||||
for _, item := range result.Data {
|
||||
userIds = append(userIds, item.ID)
|
||||
}
|
||||
|
||||
// fetch role
|
||||
userPermission, err := r.getPermissionNameByUserIds(c, dbconn, userIds)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
groupPermissionByUser := make(map[string][]string)
|
||||
for _, p := range userPermission {
|
||||
groupPermissionByUser[p.IdUser] = append(groupPermissionByUser[p.IdUser], *p.PermissionName)
|
||||
}
|
||||
|
||||
// join result with role
|
||||
for idx := range result.Data {
|
||||
result.Data[idx].HakAkses = groupPermissionByUser[result.Data[idx].ID]
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r accessRepo) ListRolePermission(c context.Context, q QueryListRolePermission) (ListRolePermissionPaginateResponse, error) {
|
||||
var result ListRolePermissionPaginateResponse
|
||||
|
||||
query := queryUtils.DynamicQuery{
|
||||
From: TBL_PERMISSION,
|
||||
Fields: []queryUtils.SelectField{
|
||||
{Expression: "id"},
|
||||
{Expression: "name"},
|
||||
{Expression: "is_active"},
|
||||
},
|
||||
Sort: []queryUtils.SortField{
|
||||
{Column: "created_at", Order: "DESC"},
|
||||
},
|
||||
}
|
||||
|
||||
if q.Search != "" {
|
||||
searchFilters := []queryUtils.DynamicFilter{
|
||||
{Column: "name", Operator: queryUtils.OpILike, Value: "%" + q.Search + "%"},
|
||||
}
|
||||
|
||||
query.Filters = append(query.Filters, queryUtils.FilterGroup{Filters: searchFilters, LogicOp: "OR"})
|
||||
}
|
||||
|
||||
dbconn, err := r.db.GetSQLXDB(DB_NAME)
|
||||
if err != nil {
|
||||
log.Printf("Unable to connect db : %s", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// query count
|
||||
countData, err := r.queryBuilder.ExecuteCount(c, dbconn, query)
|
||||
if err != nil {
|
||||
log.Printf("Unable to execute query count : %s ", err)
|
||||
return result, err
|
||||
}
|
||||
result.Paging.Limit = q.Limit
|
||||
result.Paging.Offset = q.Offset
|
||||
result.Paging.Total = int(countData)
|
||||
result.Paging.CalculatePagingInfo()
|
||||
|
||||
// query data
|
||||
queryData := query
|
||||
queryData.Limit = q.Limit
|
||||
queryData.Offset = q.Offset
|
||||
err = r.queryBuilder.ExecuteQuery(
|
||||
c, dbconn, queryData, &result.Data)
|
||||
if err != nil {
|
||||
log.Printf("Unable to execute query data : %s", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r accessRepo) DetailRolePermission(c context.Context, permission_id string) (DetailRolePageResponse, error) {
|
||||
var result DetailRolePageResponse
|
||||
|
||||
// fetch role
|
||||
query := queryUtils.DynamicQuery{
|
||||
From: TBL_PERMISSION,
|
||||
Fields: []queryUtils.SelectField{
|
||||
{Expression: "id"},
|
||||
{Expression: "name"},
|
||||
{Expression: "is_active"},
|
||||
},
|
||||
Filters: []queryUtils.FilterGroup{
|
||||
{
|
||||
Filters: []queryUtils.DynamicFilter{
|
||||
{Column: "id", Operator: queryUtils.OpEqual, Value: permission_id},
|
||||
}, LogicOp: "AND",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
dbconn, err := r.db.GetSQLXDB(DB_NAME)
|
||||
if err != nil {
|
||||
log.Printf("Unable to connect db : %s", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
err = r.queryBuilder.ExecuteQueryRow(
|
||||
c, dbconn, query, &result)
|
||||
if err != nil {
|
||||
log.Printf("Unable to execute query data : %s", err)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// fetch all pages -> compare with eligible pages -> map to DetailRolePageResponse.AccessPage
|
||||
allPages, err := r.getAllPages(c, dbconn)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// fetch eligible page for role
|
||||
eligiblePagesMap := make(map[string]bool)
|
||||
eligiblePages, err := r.getPageIdsByPermissionIds(c, dbconn, []string{permission_id})
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
for _, p := range eligiblePages {
|
||||
eligiblePagesMap[p.IdPage] = true
|
||||
}
|
||||
|
||||
for _, p := range allPages {
|
||||
isActive := false
|
||||
if eligiblePagesMap[p.ID] {
|
||||
isActive = true
|
||||
}
|
||||
|
||||
result.AccessPage = append(result.AccessPage, AccessPage{
|
||||
ID: p.ID,
|
||||
Page: p.Name,
|
||||
IsActive: isActive,
|
||||
ParentId: &p.ParentId.String,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// PRIVATE FUNCTIONS
|
||||
|
||||
// Table user function
|
||||
|
||||
func (r accessRepo) insertUser(c context.Context, tx *sql.Tx, req SyncKeycloakRoleRequest) (string, error) {
|
||||
newUserId := uuid.New().String()
|
||||
|
||||
insertUserQuery := queryUtils.InsertData{
|
||||
Columns: []string{
|
||||
"id", "name", "email", "keycloak_id", "created_at",
|
||||
},
|
||||
Values: []interface{}{
|
||||
newUserId, req.Username, req.Email, req.KeycloakId, time.Now(),
|
||||
},
|
||||
}
|
||||
|
||||
returningCols := []string{
|
||||
"id",
|
||||
}
|
||||
|
||||
sql, args, err := r.queryBuilder.BuildInsertQuery(TBL_USER, insertUserQuery, returningCols...)
|
||||
if err != nil {
|
||||
log.Printf("error building query create user %s", err)
|
||||
return newUserId, err
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(c, sql, args...)
|
||||
if err != nil {
|
||||
log.Printf("error executing query create user %s", err)
|
||||
return newUserId, err
|
||||
}
|
||||
log.Printf(sql, args)
|
||||
log.Printf("success insert user")
|
||||
|
||||
return newUserId, nil
|
||||
}
|
||||
|
||||
// End Table user function
|
||||
|
||||
// Table permission functions
|
||||
|
||||
func (r accessRepo) findPermissionByRoleName(c context.Context, dbconn *sqlx.DB, roles []string) ([]RolePermissionModel, error) {
|
||||
var result []RolePermissionModel
|
||||
|
||||
query := queryUtils.DynamicQuery{
|
||||
From: TBL_PERMISSION,
|
||||
Fields: []queryUtils.SelectField{
|
||||
{Expression: "id"},
|
||||
{Expression: "name"},
|
||||
},
|
||||
Filters: []queryUtils.FilterGroup{
|
||||
{
|
||||
Filters: []queryUtils.DynamicFilter{
|
||||
{Column: "name", Operator: queryUtils.OpIn, Value: roles},
|
||||
}, LogicOp: "AND",
|
||||
},
|
||||
},
|
||||
}
|
||||
err := r.queryBuilder.ExecuteQuery(c, dbconn, query, &result)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r accessRepo) insertPermissionByRoleName(c context.Context, tx *sql.Tx, newRoles []string) ([]string, error) {
|
||||
var idRoles []string
|
||||
|
||||
if len(newRoles) > 0 {
|
||||
var valuePermission [][]interface{}
|
||||
|
||||
for _, role := range newRoles {
|
||||
id := uuid.New().String()
|
||||
itemValues := []interface{}{id, role, false}
|
||||
|
||||
idRoles = append(idRoles, id)
|
||||
valuePermission = append(valuePermission, itemValues)
|
||||
}
|
||||
|
||||
insertPermissionQuery := queryUtils.InsertBulkData{
|
||||
Columns: []string{
|
||||
"id", "name", "is_active",
|
||||
},
|
||||
Values: valuePermission,
|
||||
}
|
||||
|
||||
returningCols := []string{
|
||||
"id",
|
||||
}
|
||||
sql, args, err := r.queryBuilder.BuildBulkInsertQuery(TBL_PERMISSION, insertPermissionQuery, returningCols...)
|
||||
if err != nil {
|
||||
log.Printf("error building query insert new permission %s", err)
|
||||
|
||||
return idRoles, err
|
||||
}
|
||||
_, err = tx.ExecContext(c, sql, args...)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return idRoles, err
|
||||
}
|
||||
log.Printf(sql, args)
|
||||
log.Printf("success insert new permission")
|
||||
}
|
||||
|
||||
return idRoles, nil
|
||||
}
|
||||
|
||||
// END table permission functions
|
||||
|
||||
// Table user permission functions
|
||||
|
||||
func (r accessRepo) deletePermissionByUserId(c context.Context, tx *sql.Tx, userId string) error {
|
||||
filters := []queryUtils.FilterGroup{
|
||||
{
|
||||
Filters: []queryUtils.DynamicFilter{
|
||||
{Column: "id_user", Operator: queryUtils.OpEqual, Value: userId},
|
||||
},
|
||||
},
|
||||
}
|
||||
sql, args, err := r.queryBuilder.BuildDeleteQuery(TBL_USER_PERMISSION, filters)
|
||||
if err != nil {
|
||||
log.Printf("Unable to create delete user permission query : %v", err)
|
||||
return err
|
||||
}
|
||||
_, err = tx.ExecContext(c, sql, args...)
|
||||
if err != nil {
|
||||
log.Printf("Unable to executing delete user permission : %v", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r accessRepo) insertUserPermission(c context.Context, tx *sql.Tx, userId string, roleIds []string) error {
|
||||
if len(roleIds) > 0 {
|
||||
var valueUserPermission [][]interface{}
|
||||
|
||||
for _, roleId := range roleIds {
|
||||
id := uuid.New().String()
|
||||
itemValues := []interface{}{id, userId, roleId}
|
||||
|
||||
valueUserPermission = append(valueUserPermission, itemValues)
|
||||
}
|
||||
|
||||
insertUserPermissionQuery := queryUtils.InsertBulkData{
|
||||
Columns: []string{
|
||||
"id", "id_user", "id_permission",
|
||||
},
|
||||
Values: valueUserPermission,
|
||||
}
|
||||
|
||||
returningCols := []string{
|
||||
"id",
|
||||
}
|
||||
sql, args, err := r.queryBuilder.BuildBulkInsertQuery(TBL_USER_PERMISSION, insertUserPermissionQuery, returningCols...)
|
||||
if err != nil {
|
||||
log.Printf("error building query insert user permission %s", err)
|
||||
|
||||
return err
|
||||
}
|
||||
_, err = tx.ExecContext(c, sql, args...)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return err
|
||||
}
|
||||
log.Printf(sql, args)
|
||||
log.Printf("success insert user permission")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r accessRepo) getOrCreateUserPermission(c context.Context, db *sqlx.DB, tx *sql.Tx, userId string, roles []string) error {
|
||||
var permissionIds []string
|
||||
mapPermissionExist := make(map[string]string)
|
||||
var newRoles []string
|
||||
|
||||
// fetch permission by name, append the permission ids
|
||||
fetchRoles, err := r.findPermissionByRoleName(c, db, roles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(fetchRoles) > 0 {
|
||||
for _, item := range fetchRoles {
|
||||
permissionIds = append(permissionIds, item.ID)
|
||||
mapPermissionExist[item.Name] = item.ID
|
||||
}
|
||||
}
|
||||
|
||||
// if permission not exist, insert non-existed permission first then append the permission ids
|
||||
for _, role := range roles {
|
||||
if mapPermissionExist[role] == "" {
|
||||
newRoles = append(newRoles, role)
|
||||
}
|
||||
}
|
||||
// insert new , non existed permission
|
||||
if len(newRoles) > 0 {
|
||||
newRoleIds, err := r.insertPermissionByRoleName(c, tx, newRoles)
|
||||
if err != nil {
|
||||
return err
|
||||
} else { // append new role ids to permission ids
|
||||
permissionIds = append(permissionIds, newRoleIds...)
|
||||
}
|
||||
}
|
||||
// insert all permission to user
|
||||
err = r.insertUserPermission(c, tx, userId, permissionIds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r accessRepo) getUserPermissionByUserId(c context.Context, db *sqlx.DB, userId string) ([]RoleUserPermissionModel, error) {
|
||||
var result []RoleUserPermissionModel
|
||||
|
||||
query := queryUtils.DynamicQuery{
|
||||
From: TBL_USER_PERMISSION,
|
||||
Fields: []queryUtils.SelectField{
|
||||
{Expression: "id"},
|
||||
{Expression: "id_user"},
|
||||
{Expression: "id_permission"},
|
||||
},
|
||||
Filters: []queryUtils.FilterGroup{
|
||||
{
|
||||
Filters: []queryUtils.DynamicFilter{
|
||||
{Column: "id_user", Operator: queryUtils.OpEqual, Value: userId},
|
||||
}, LogicOp: "AND",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := r.queryBuilder.ExecuteQuery(c, db, query, &result)
|
||||
if err != nil {
|
||||
log.Printf("error executing fetch user permission : %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r accessRepo) getPermissionNameByUserIds(c context.Context, db *sqlx.DB, userIds []string) ([]RoleUserPermissionModel, error) {
|
||||
var result []RoleUserPermissionModel
|
||||
|
||||
query := queryUtils.DynamicQuery{
|
||||
From: TBL_USER_PERMISSION,
|
||||
Aliases: "up",
|
||||
Fields: []queryUtils.SelectField{
|
||||
{Expression: "up.id", Alias: "id"},
|
||||
{Expression: "up.id_user", Alias: "id_user"},
|
||||
{Expression: "up.id_permission", Alias: "id_permission"},
|
||||
{Expression: "p.name", Alias: "permission_name"},
|
||||
},
|
||||
Joins: []queryUtils.Join{
|
||||
{
|
||||
Type: "LEFT",
|
||||
Table: TBL_PERMISSION,
|
||||
Alias: "p",
|
||||
OnConditions: queryUtils.FilterGroup{
|
||||
Filters: []queryUtils.DynamicFilter{
|
||||
{
|
||||
Column: "p.id", Operator: queryUtils.OpEqual, Value: "up.id_permission",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Filters: []queryUtils.FilterGroup{
|
||||
{
|
||||
Filters: []queryUtils.DynamicFilter{
|
||||
{Column: "id_user", Operator: queryUtils.OpIn, Value: userIds},
|
||||
}, LogicOp: "AND",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := r.queryBuilder.ExecuteQuery(c, db, query, &result)
|
||||
if err != nil {
|
||||
log.Printf("error executing fetch user permission : %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// End Table user permission functions
|
||||
|
||||
// Table role page permission functions
|
||||
|
||||
func (r accessRepo) getPageIdsByPermissionIds(c context.Context, db *sqlx.DB, permissionIds []string) ([]RolePagePermissionModel, error) {
|
||||
var result []RolePagePermissionModel
|
||||
|
||||
query := queryUtils.DynamicQuery{
|
||||
From: TBL_PAGE_PERMISSION,
|
||||
Fields: []queryUtils.SelectField{
|
||||
{Expression: "id"},
|
||||
{Expression: "id_permission"},
|
||||
{Expression: "id_page"},
|
||||
},
|
||||
Filters: []queryUtils.FilterGroup{
|
||||
{
|
||||
Filters: []queryUtils.DynamicFilter{
|
||||
{Column: "id_permission", Operator: queryUtils.OpIn, Value: permissionIds},
|
||||
}, LogicOp: "AND",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := r.queryBuilder.ExecuteQuery(c, db, query, &result)
|
||||
if err != nil {
|
||||
log.Printf("error executing fetch user permission : %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// End role page permission functions
|
||||
|
||||
// Table pages functions
|
||||
|
||||
func (r accessRepo) getPageByIds(c context.Context, db *sqlx.DB, ids []string) ([]RolePageModel, error) {
|
||||
var result []RolePageModel
|
||||
|
||||
query := queryUtils.DynamicQuery{
|
||||
From: TBL_ROLE_PAGES,
|
||||
Fields: []queryUtils.SelectField{
|
||||
{Expression: "id"},
|
||||
{Expression: "name"},
|
||||
{Expression: "icon"},
|
||||
{Expression: "url"},
|
||||
{Expression: "level"},
|
||||
{Expression: "sort"},
|
||||
{Expression: "parent"},
|
||||
},
|
||||
Filters: []queryUtils.FilterGroup{
|
||||
{
|
||||
Filters: []queryUtils.DynamicFilter{
|
||||
{Column: "id", Operator: queryUtils.OpIn, Value: ids},
|
||||
}, LogicOp: "AND",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := r.queryBuilder.ExecuteQuery(c, db, query, &result)
|
||||
if err != nil {
|
||||
log.Printf("error executing fetch pages : %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r accessRepo) getAllPages(c context.Context, db *sqlx.DB) ([]RolePageModel, error) {
|
||||
var result []RolePageModel
|
||||
|
||||
query := queryUtils.DynamicQuery{
|
||||
From: TBL_ROLE_PAGES,
|
||||
Fields: []queryUtils.SelectField{
|
||||
{Expression: "id"},
|
||||
{Expression: "name"},
|
||||
{Expression: "icon"},
|
||||
{Expression: "url"},
|
||||
{Expression: "level"},
|
||||
{Expression: "sort"},
|
||||
{Expression: "parent"},
|
||||
},
|
||||
}
|
||||
|
||||
err := r.queryBuilder.ExecuteQuery(c, db, query, &result)
|
||||
if err != nil {
|
||||
log.Printf("error executing fetch pages : %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// End page functions
|
||||
@@ -0,0 +1,26 @@
|
||||
package access
|
||||
|
||||
type SyncKeycloakRoleRequest struct {
|
||||
KeycloakId string `json:"keycloak_id" binding:"required"`
|
||||
Username string `json:"name" binding:"required"`
|
||||
Email string `json:"email" binding:"required"`
|
||||
Roles []string `json:"client_role"`
|
||||
}
|
||||
|
||||
type UpsertAccessPermissionRequest struct {
|
||||
Name string `json:"namaHakAkses"`
|
||||
Status string `json:"status"`
|
||||
Pages []string `json:"pages"`
|
||||
}
|
||||
|
||||
type QueryListUserRole struct {
|
||||
Search string `form:"search"`
|
||||
Limit int `form:"limit,default=10"`
|
||||
Offset int `form:"offset,default=0"`
|
||||
}
|
||||
|
||||
type QueryListRolePermission struct {
|
||||
Search string `form:"search"`
|
||||
Limit int `form:"limit,default=10"`
|
||||
Offset int `form:"offset,default=0"`
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package access
|
||||
|
||||
import "antrian-operasi/internal/shared"
|
||||
|
||||
type AvailableMenuChildResponse struct {
|
||||
Title string `json:"title"`
|
||||
Icon string `json:"icon"`
|
||||
To string `json:"to"`
|
||||
Children []*AvailableMenuChildResponse `json:"children"`
|
||||
}
|
||||
|
||||
type AvailableMenuResponse struct {
|
||||
ID string `json:"id"`
|
||||
Header string `json:"header"`
|
||||
Children []*AvailableMenuChildResponse `json:"children"`
|
||||
}
|
||||
|
||||
func MapMenuModelToResponse(pages []RolePageModel) []AvailableMenuResponse {
|
||||
pageMap := make(map[string]*AvailableMenuChildResponse)
|
||||
|
||||
var result []AvailableMenuResponse
|
||||
|
||||
for _, p := range pages {
|
||||
pageMap[p.ID] = &AvailableMenuChildResponse{
|
||||
Title: p.Name,
|
||||
Icon: p.Icon.String,
|
||||
To: p.Url.String,
|
||||
}
|
||||
|
||||
if p.ParentId.String != "" {
|
||||
pageMap[p.ParentId.String].Children = append(pageMap[p.ParentId.String].Children, pageMap[p.ID])
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range pages {
|
||||
if p.ParentId.String == "" {
|
||||
result = append(result, AvailableMenuResponse{
|
||||
ID: p.ID,
|
||||
Header: p.Name,
|
||||
Children: pageMap[p.ID].Children,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
type UserRoleResponse struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Email string `json:"email"`
|
||||
HakAkses []string `json:"hak_akses"`
|
||||
}
|
||||
|
||||
type ListUserRolePaginateResponse struct {
|
||||
Data []UserRoleResponse
|
||||
Paging shared.PaginationInfo
|
||||
}
|
||||
|
||||
type ListRolePermissionPaginateResponse struct {
|
||||
Data []RolePermissionModel
|
||||
Paging shared.PaginationInfo
|
||||
}
|
||||
|
||||
type AccessPage struct {
|
||||
ID string `json:"id"`
|
||||
Page string `json:"page"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ParentId *string `json:"parent_id"`
|
||||
}
|
||||
type DetailRolePageResponse struct {
|
||||
ID string `json:"id" db:"id"`
|
||||
Name string `json:"name" db:"name"`
|
||||
Status bool `json:"status" db:"is_active"`
|
||||
AccessPage []AccessPage `json:"access_page"`
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package access
|
||||
|
||||
import (
|
||||
"antrian-operasi/internal/database"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterRoutes(r *gin.RouterGroup, dbService database.Service) {
|
||||
accessRepo := NewRepository(dbService)
|
||||
accessHandler := NewAccessHandler(accessRepo)
|
||||
|
||||
r.POST("/sync-keycloak-role", accessHandler.SyncKeycloakRole)
|
||||
r.GET("/eligible-menu", accessHandler.GetPageByKeycloakId)
|
||||
r.GET("/list-user", accessHandler.ListUserRole)
|
||||
|
||||
r.GET("/role-permission", accessHandler.ListRolePageSettings)
|
||||
r.GET("/role-permission/:id", accessHandler.DetailRolePageSettings)
|
||||
}
|
||||
@@ -58,23 +58,24 @@ type DokterOperasiModel struct {
|
||||
}
|
||||
|
||||
type DetailPasienOperasi struct {
|
||||
ID string `db:"id" json:"id"`
|
||||
TglDaftar time.Time `db:"tanggal_daftar"`
|
||||
TglSelesai *time.Time `db:"tanggal_selesai"`
|
||||
TglLahir *time.Time `db:"tanggal_lahir"`
|
||||
Umur *string `db:"umur"`
|
||||
Alamat *string `db:"alamat"`
|
||||
NoKtp *string `db:"no_ktp"`
|
||||
NoRekamMedis *string `db:"no_rekam_medis"`
|
||||
NamaPasien *string `db:"nama_pasien"`
|
||||
IdSpesialis int `db:"id_spesialis"`
|
||||
IdSubSpesialis int `db:"id_sub_spesialis"`
|
||||
IdKategori int `db:"id_kategori"`
|
||||
Spesialis *string `db:"spesialis"`
|
||||
SubSpesialis *string `db:"subspesialis"`
|
||||
Kategori *string `db:"kategori"`
|
||||
StatusOperasi string `db:"status_operasi"`
|
||||
JenisKelamin *string `db:"jenis_kelamin"`
|
||||
Keterangan *string `db:"keterangan"`
|
||||
RencanaOperasi *string `db:"rencana_operasi"`
|
||||
ID string `db:"id" json:"id"`
|
||||
TglDaftar time.Time `db:"tanggal_daftar"`
|
||||
TglSelesai *time.Time `db:"tanggal_selesai"`
|
||||
TglLahir *time.Time `db:"tanggal_lahir"`
|
||||
Umur *string `db:"umur"`
|
||||
Alamat *string `db:"alamat"`
|
||||
NoKtp *string `db:"no_ktp"`
|
||||
NoRekamMedis *string `db:"no_rekam_medis"`
|
||||
NamaPasien *string `db:"nama_pasien"`
|
||||
IdSpesialis int `db:"id_spesialis"`
|
||||
IdSubSpesialis int `db:"id_sub_spesialis"`
|
||||
IdKategori int `db:"id_kategori"`
|
||||
Spesialis *string `db:"spesialis"`
|
||||
SubSpesialis *string `db:"subspesialis"`
|
||||
Kategori *string `db:"kategori"`
|
||||
StatusOperasi string `db:"status_operasi"`
|
||||
JenisKelamin *string `db:"jenis_kelamin"`
|
||||
Keterangan *string `db:"keterangan"`
|
||||
RencanaOperasi *string `db:"rencana_operasi"`
|
||||
KeteranganStatusPasien *string `db:"keterangan_status_pasien"`
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func NewRepository(dbService database.Service) IAntrianOperasiRepository {
|
||||
"id", "status", "date_created", "date_updated", "\"No_rekam_medis\"", "\"No_KTP\"", "\"Nama_pasien\"",
|
||||
"\"Jenis_kelamin\"", "\"Tanggal_lahir\"", "\"Umur\"", "\"Alamat\"", "\"Tanggal_daftar\"",
|
||||
"\"Kategori_operasi\"", "\"Rencana_operasi\"", "\"Status_operasi\"", "\"Nomor\"",
|
||||
"\"Spesialis\"", "\"Sub_spesialis\"", "\"Keterangan\"",
|
||||
"\"Spesialis\"", "\"Sub_spesialis\"", "\"Keterangan\"", "\"Keterangan_status_pasien\"",
|
||||
"\"Nomor_spesialis\"", "\"Nomor_sub_spesialis\"",
|
||||
"\"Nomor_telepon\"", "\"Tanggal_selesai_operasi\"",
|
||||
"\"FK_pasien_operasi_telepon_pasien_operasi_ID\"", "FK_pasien_operasi_telepon_pasien_operasi_ID",
|
||||
@@ -308,7 +308,7 @@ func (r antrianOperasiRepo) CreateAntrianOperasi(c context.Context, req CreatePa
|
||||
"id", "status", "date_created", "\"No_rekam_medis\"", "\"No_KTP\"", "\"Nama_pasien\"",
|
||||
"\"Jenis_kelamin\"", "\"Tanggal_lahir\"", "\"Umur\"", "\"Alamat\"", "\"Tanggal_daftar\"",
|
||||
"\"Kategori_operasi\"", "\"Rencana_operasi\"", "\"Status_operasi\"", "\"Nomor\"",
|
||||
"\"Spesialis\"", "\"Sub_spesialis\"", "\"Keterangan\"",
|
||||
"\"Spesialis\"", "\"Sub_spesialis\"", "\"Keterangan\"", "\"Keterangan_status_pasien\"",
|
||||
"\"Nomor_spesialis\"", "\"Nomor_sub_spesialis\"",
|
||||
}, Values: []interface{}{
|
||||
idAntrian,
|
||||
@@ -329,6 +329,7 @@ func (r antrianOperasiRepo) CreateAntrianOperasi(c context.Context, req CreatePa
|
||||
req.RencanaOperasiData.Spesialis,
|
||||
req.RencanaOperasiData.SubSpesialis,
|
||||
req.RencanaOperasiData.Keterangan,
|
||||
req.StatusPasienData.KeteranganStatus,
|
||||
req.RencanaOperasiData.Spesialis,
|
||||
req.RencanaOperasiData.SubSpesialis,
|
||||
},
|
||||
@@ -580,6 +581,8 @@ func (r antrianOperasiRepo) GetAntrianOperasiById(c context.Context, id string)
|
||||
{Expression: "dpo.Sub_spesialis", Alias: "id_sub_spesialis"},
|
||||
{Expression: "dpo.Kategori_operasi", Alias: "id_kategori"},
|
||||
{Expression: "dpo.Keterangan", Alias: "keterangan"},
|
||||
{Expression: "dpo.Keterangan_status_pasien", Alias: "keterangan_status_pasien"},
|
||||
{Expression: "dpo.Rencana_operasi", Alias: "rencana_operasi"},
|
||||
{Expression: "ds.Spesialis", Alias: "spesialis"},
|
||||
{Expression: "dss.Subspesialis", Alias: "subspesialis"},
|
||||
{Expression: "dko.Kategori", Alias: "kategori"},
|
||||
@@ -773,14 +776,14 @@ func (r antrianOperasiRepo) UpdateAntrianOperasi(c context.Context, id string, r
|
||||
Columns: []string{
|
||||
"date_updated", "\"No_rekam_medis\"", "\"No_KTP\"", "\"Nama_pasien\"", "\"Jenis_kelamin\"",
|
||||
"\"Tanggal_lahir\"", "\"Umur\"", "\"Alamat\"", "\"Kategori_operasi\"",
|
||||
"\"Rencana_operasi\"", "\"Keterangan\"",
|
||||
"\"Status_operasi\"", "\"Spesialis\"", "\"Sub_spesialis\"",
|
||||
"\"Rencana_operasi\"", "\"Keterangan\"", "\"Keterangan_status_pasien\"",
|
||||
"\"Status_operasi\"", "\"Spesialis\"", "\"Sub_spesialis\"", "\"Tanggal_daftar\"",
|
||||
},
|
||||
Values: []interface{}{
|
||||
time.Now(), req.FormData.NoRekamMedis, req.FormData.NoKtp, req.FormData.NamaPasien, req.FormData.JenisKelamin,
|
||||
req.FormData.TglLahir, req.FormData.Umur, req.FormData.Alamat, req.RencanaOperasiData.KategoriOperasi,
|
||||
req.RencanaOperasiData.RencanaOperasi, req.RencanaOperasiData.Keterangan,
|
||||
req.StatusPasienData.StatusOperasi, req.RencanaOperasiData.Spesialis, req.RencanaOperasiData.SubSpesialis,
|
||||
req.RencanaOperasiData.RencanaOperasi, req.RencanaOperasiData.Keterangan, req.StatusPasienData.KeteranganStatus,
|
||||
req.StatusPasienData.StatusOperasi, req.RencanaOperasiData.Spesialis, req.RencanaOperasiData.SubSpesialis, req.RencanaOperasiData.TanggalDaftar,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -842,7 +845,7 @@ func (r antrianOperasiRepo) UpdateStatusAntrianOperasi(c context.Context, id str
|
||||
// Update main table
|
||||
updateMainQuery := queryUtils.UpdateData{
|
||||
Columns: []string{
|
||||
"date_updated", "\"Keterangan\"", "\"Status_operasi\"",
|
||||
"date_updated", "\"Keterangan_status_pasien\"", "\"Status_operasi\"",
|
||||
},
|
||||
Values: []interface{}{
|
||||
time.Now(), req.KeteranganStatus, req.StatusOperasi,
|
||||
|
||||
@@ -39,9 +39,9 @@ func (model DetailPasienOperasiResultQuery) MapToResponse() DetailPasienOperasiR
|
||||
}
|
||||
result.FormData = FormDataRequest{
|
||||
NoRekamMedis: handleStringPointer(model.ResultMain.NoRekamMedis),
|
||||
NoKtp: *model.ResultMain.NoKtp,
|
||||
NamaPasien: *model.ResultMain.NamaPasien,
|
||||
JenisKelamin: *model.ResultMain.JenisKelamin,
|
||||
NoKtp: handleStringPointer(model.ResultMain.NoKtp),
|
||||
NamaPasien: handleStringPointer(model.ResultMain.NamaPasien),
|
||||
JenisKelamin: handleStringPointer(model.ResultMain.JenisKelamin),
|
||||
TglLahir: &tglLahir,
|
||||
Umur: model.ResultMain.Umur,
|
||||
Alamat: model.ResultMain.Alamat,
|
||||
@@ -92,7 +92,7 @@ func (model DetailPasienOperasiResultQuery) MapToResponse() DetailPasienOperasiR
|
||||
result.StatusPasienData = StatusPasienRequest{
|
||||
TglSelesai: model.ResultMain.TglSelesai,
|
||||
StatusOperasi: model.ResultMain.StatusOperasi,
|
||||
KeteranganStatus: model.ResultMain.Keterangan,
|
||||
KeteranganStatus: model.ResultMain.KeteranganStatusPasien,
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package keycloak
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"antrian-operasi/internal/shared"
|
||||
baseResponse "antrian-operasi/internal/shared"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type KeycloakHandler struct {
|
||||
service IKeycloakService
|
||||
}
|
||||
|
||||
func NewKeycloakHandler(service IKeycloakService) KeycloakHandler {
|
||||
return KeycloakHandler{service}
|
||||
}
|
||||
|
||||
// GetTokenByRefreshCode godoc
|
||||
// @Summary Requesting new token to keycloak using refresh token
|
||||
// @Tags Keycloak
|
||||
// @Param body body RefreshTokenRequest true "Valid Refresh Token"
|
||||
// @Success 200 {object} shared.BaseResponse
|
||||
// @Failure 500 {object} shared.BaseErrorResponse
|
||||
// @Router /keycloak/refresh-token [post]
|
||||
func (h KeycloakHandler) GetTokenByRefreshCode(c *gin.Context) {
|
||||
var req RefreshTokenRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(400, shared.BaseErrorResponse{
|
||||
Success: false,
|
||||
Code: 400,
|
||||
Message: "error bind json",
|
||||
Errors: shared.ValidationError(err),
|
||||
})
|
||||
return
|
||||
}
|
||||
resp, err := h.service.FetchTokenUsingRefreshToken(c, req.RefreshToken)
|
||||
|
||||
if err != nil {
|
||||
errorResponse := baseResponse.BaseErrorResponse{
|
||||
Success: false,
|
||||
Code: 400,
|
||||
Message: err.Error(),
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, errorResponse)
|
||||
return
|
||||
}
|
||||
|
||||
response := baseResponse.ToBaseResponse(
|
||||
resp,
|
||||
true,
|
||||
200,
|
||||
"success refreshing token")
|
||||
|
||||
c.JSON(http.StatusOK, response)
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package keycloak
|
||||
|
||||
type RefreshTokenRequest struct {
|
||||
RefreshToken string `json:"refresh_token" binding:"required"`
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package keycloak
|
||||
|
||||
type TokenErrorResponse struct {
|
||||
Error string `json:"error"`
|
||||
ErrorDescription string `json:"error_description"`
|
||||
}
|
||||
|
||||
type TokenResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
RefreshExpiresIn int `json:"refresh_expires_in"`
|
||||
TokenType string `json:"token_type"`
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package keycloak
|
||||
|
||||
import (
|
||||
"antrian-operasi/internal/config"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterRoutes(r *gin.RouterGroup, cfg config.KeycloakConfig) {
|
||||
keycloakService := NewKeycloakService(cfg)
|
||||
keycloakHandler := NewKeycloakHandler(keycloakService)
|
||||
|
||||
r.POST("/refresh-token", keycloakHandler.GetTokenByRefreshCode)
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package keycloak
|
||||
|
||||
import (
|
||||
"antrian-operasi/internal/config"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type IKeycloakService interface {
|
||||
FetchTokenUsingRefreshToken(c context.Context, refreshToken string) (*TokenResponse, error)
|
||||
}
|
||||
|
||||
type KeycloakService struct {
|
||||
config config.KeycloakConfig
|
||||
}
|
||||
|
||||
func NewKeycloakService(cfg config.KeycloakConfig) IKeycloakService {
|
||||
return KeycloakService{cfg}
|
||||
}
|
||||
|
||||
func (s KeycloakService) FetchTokenUsingRefreshToken(c context.Context, refreshToken string) (*TokenResponse, error) {
|
||||
refreshTokenUrl := s.config.BaseUrl + "/realms/" + s.config.Realm + "/protocol/openid-connect/token"
|
||||
bodyRequest := url.Values{}
|
||||
bodyRequest.Set("grant_type", "refresh_token")
|
||||
bodyRequest.Set("client_id", s.config.Audience)
|
||||
bodyRequest.Set("client_secret", s.config.SecretKey)
|
||||
bodyRequest.Set("refresh_token", refreshToken)
|
||||
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequestWithContext(c, http.MethodPost, refreshTokenUrl, strings.NewReader(bodyRequest.Encode()))
|
||||
if err != nil {
|
||||
log.Printf("error request token %s", err)
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Printf("error response %s", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
var errResp TokenErrorResponse
|
||||
json.NewDecoder(resp.Body).Decode(&errResp)
|
||||
|
||||
return nil, fmt.Errorf("Keycloak error : %s - %s", errResp.Error, errResp.ErrorDescription)
|
||||
}
|
||||
|
||||
var tokenResp TokenResponse
|
||||
err = json.NewDecoder(resp.Body).Decode(&tokenResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tokenResp, nil
|
||||
}
|
||||
@@ -3,8 +3,10 @@ package routes
|
||||
import (
|
||||
"antrian-operasi/internal/config"
|
||||
"antrian-operasi/internal/database"
|
||||
"antrian-operasi/internal/domain/access"
|
||||
antrianoperasi "antrian-operasi/internal/domain/antrian_operasi"
|
||||
"antrian-operasi/internal/domain/dashboard"
|
||||
"antrian-operasi/internal/domain/keycloak"
|
||||
"antrian-operasi/internal/domain/reference/diagnosa"
|
||||
"antrian-operasi/internal/domain/reference/dokter"
|
||||
"antrian-operasi/internal/domain/reference/kategori"
|
||||
@@ -40,13 +42,17 @@ func RegisterRoutes(cfg *config.Config, dbService database.Service) *gin.Engine
|
||||
log.Fatalf("Unable to initiate keycloak auth")
|
||||
}
|
||||
|
||||
api := router.Group("/api", authKeycloak)
|
||||
api := router.Group("/api")
|
||||
|
||||
antrian := api.Group("/antrian-operasi")
|
||||
acc := api.Group("/access", authKeycloak)
|
||||
{
|
||||
access.RegisterRoutes(acc, dbService)
|
||||
}
|
||||
antrian := api.Group("/antrian-operasi", authKeycloak)
|
||||
{
|
||||
antrianoperasi.RegisterRoutes(antrian, dbService)
|
||||
}
|
||||
reference := api.Group("/reference")
|
||||
reference := api.Group("/reference", authKeycloak)
|
||||
{
|
||||
kategori.RegisterRoutes(reference, dbService)
|
||||
spesialis.RegisterRoutes(reference, dbService)
|
||||
@@ -55,10 +61,14 @@ func RegisterRoutes(cfg *config.Config, dbService database.Service) *gin.Engine
|
||||
diagnosa.RegisterRoutes(reference, dbService)
|
||||
tindakan.RegisterRoutes(reference, dbService)
|
||||
}
|
||||
dboard := api.Group("dashboard")
|
||||
dboard := api.Group("dashboard", authKeycloak)
|
||||
{
|
||||
dashboard.RegisterRoutes(dboard, dbService)
|
||||
}
|
||||
kc := api.Group("/keycloak")
|
||||
{
|
||||
keycloak.RegisterRoutes(kc, cfg.Keycloak)
|
||||
}
|
||||
|
||||
return router
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"antrian-operasi/internal/config"
|
||||
"antrian-operasi/internal/database"
|
||||
utils "antrian-operasi/internal/utils/query"
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const DB_ANTRIAN_OPERASI = "db_role_access"
|
||||
const TBL_ROLE_PAGE = "role_pages"
|
||||
|
||||
var dbService database.Service
|
||||
|
||||
func main() {
|
||||
cfg := config.LoadConfig()
|
||||
dbService = database.New(cfg)
|
||||
|
||||
ctx := context.Background()
|
||||
err := seedRolePages(ctx, dbService)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer dbService.Close()
|
||||
}
|
||||
|
||||
func seedRolePages(c context.Context, db database.Service) error {
|
||||
dbconn, err := db.GetSQLXDB(DB_ANTRIAN_OPERASI)
|
||||
if err != nil {
|
||||
log.Fatal("unable to connect database antrian operasi")
|
||||
return err
|
||||
}
|
||||
|
||||
qb := utils.NewQueryBuilder(utils.DBTypePostgreSQL).SetAllowedColumns([]string{
|
||||
"id", "name", "icon", "url", "level", "sort", "parent",
|
||||
}).SetSecurityOptions(false, 100)
|
||||
|
||||
idParentDashboard := uuid.New().String()
|
||||
idParentAntrean := uuid.New().String()
|
||||
idParentSettings := uuid.New().String()
|
||||
|
||||
insertPageQuery := utils.InsertBulkData{
|
||||
Columns: []string{
|
||||
"id", "name", "icon", "url", "level", "sort", "parent",
|
||||
},
|
||||
Values: [][]interface{}{
|
||||
{idParentDashboard, "Dashboard", nil, nil, 1, 1, nil},
|
||||
{uuid.New().String(), "Dashboard", "widget-add-line-duotone", "/dashboard", 2, 1, idParentDashboard},
|
||||
{idParentAntrean, "Antrean", nil, nil, 1, 2, nil},
|
||||
{uuid.New().String(), "Semua", "list-check-line-duotone", "/antrean/all", 2, 1, idParentAntrean},
|
||||
{uuid.New().String(), "Kategori", "layers-minimalistic-line-duotone", "/antrean/list-kategori", 2, 2, idParentAntrean},
|
||||
{uuid.New().String(), "Spesialis", "users-group-rounded-line-duotone", "/antrean/list-spesialis", 2, 3, idParentAntrean},
|
||||
{idParentSettings, "Pengaturan", nil, nil, 1, 3, nil},
|
||||
{uuid.New().String(), "Hak Akses", "shield-user-line-duotone", "/setting/hak-akses", 2, 1, idParentSettings},
|
||||
{uuid.New().String(), "User", "user-id-line-duotone", "/setting/user", 2, 2, idParentSettings},
|
||||
},
|
||||
}
|
||||
|
||||
sql, args, err := qb.BuildBulkInsertQuery(TBL_ROLE_PAGE, insertPageQuery)
|
||||
if err != nil {
|
||||
log.Fatalf("fail creating query seed role pages, %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println(sql, args)
|
||||
|
||||
tx, err := dbconn.BeginTx(c, nil)
|
||||
if err != nil {
|
||||
log.Fatalf("fail starting transaction seed role pages, %v", err)
|
||||
return err
|
||||
}
|
||||
_, err = tx.ExecContext(c, sql, args...)
|
||||
if err != nil {
|
||||
log.Fatalf("fail executing seed role pages query, %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -77,4 +77,13 @@ Project ini menggunakan autentikasi dengan token dari keycloak. Untuk kebutuhan
|
||||
..
|
||||
..
|
||||
KEYCLOAK_IS_ENABLE=false
|
||||
```
|
||||
|
||||
## Seed Data
|
||||
Project ini menggunakan seed data untuk integrasi dengan component di frontend.
|
||||
```bash
|
||||
// masuk ke root project
|
||||
cd <project_name>
|
||||
|
||||
go run ./migrations/seeder.go
|
||||
```
|
||||
Reference in New Issue
Block a user