From 254d6ae810946ae9e499952df862b9e2e5ac392a Mon Sep 17 00:00:00 2001 From: Adisak Date: Thu, 2 Oct 2025 11:19:14 +0700 Subject: [PATCH 1/5] =?UTF-8?q?sort=20=E0=B8=9B=E0=B8=A3=E0=B8=B0=E0=B9=80?= =?UTF-8?q?=E0=B8=A1=E0=B8=B4=E0=B8=99=E0=B8=9C=E0=B8=A5=E0=B8=81=E0=B8=B2?= =?UTF-8?q?=E0=B8=A3=E0=B8=9B=E0=B8=8F=E0=B8=B4=E0=B8=9A=E0=B8=B1=E0=B8=95?= =?UTF-8?q?=E0=B8=B4=E0=B8=A3=E0=B8=B2=E0=B8=8A=E0=B8=81=E0=B8=B2=E0=B8=A3?= =?UTF-8?q?=E0=B8=A3=E0=B8=B0=E0=B8=94=E0=B8=B1=E0=B8=9A=E0=B8=9A=E0=B8=B8?= =?UTF-8?q?=E0=B8=84=E0=B8=84=E0=B8=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/KpiPeriodController.ts | 44 ++++++++++--- .../KpiUserDevelopmentController.ts | 45 ++++++++++++- .../KpiUserEvaluationController.ts | 63 +++++++++++++++++-- 3 files changed, 135 insertions(+), 17 deletions(-) diff --git a/src/controllers/KpiPeriodController.ts b/src/controllers/KpiPeriodController.ts index 3de8a72..d141f96 100644 --- a/src/controllers/KpiPeriodController.ts +++ b/src/controllers/KpiPeriodController.ts @@ -235,20 +235,32 @@ export class kpiPeriodController extends Controller { @Query("pageSize") pageSize: number = 10, @Query("year") year?: number, @Query("keyword") keyword?: string, + @Query("sortBy") sortBy?: string, + @Query("descending") descending?: boolean, ) { await new permission().PermissionList(request, "SYS_KPI_ROUND"); - const [kpiPeriod, total] = await AppDataSource.getRepository(KpiPeriod) + let query = await AppDataSource.getRepository(KpiPeriod) .createQueryBuilder("kpiPeriod") .andWhere( year !== 0 && year != null && year != undefined ? "kpiPeriod.year = :year" : "1=1", { year: year }, ) - .orderBy("kpiPeriod.year", "DESC") - .addOrderBy("kpiPeriod.durationKPI", "DESC") - .addOrderBy("kpiPeriod.startDate", "DESC") - .skip((page - 1) * pageSize) - .take(pageSize) - .getManyAndCount(); + + if (sortBy) { + query = query.orderBy( + `kpiPeriod.${sortBy}`, + descending ? "DESC" : "ASC" + ); + }else{ + query = query.orderBy("kpiPeriod.year", "DESC") + .addOrderBy("kpiPeriod.durationKPI", "DESC") + .addOrderBy("kpiPeriod.startDate", "DESC") + } + + const [kpiPeriod, total] = await query + .skip((page - 1) * pageSize) + .take(pageSize) + .getManyAndCount(); return new HttpSuccess({ data: kpiPeriod, total }); } @@ -290,15 +302,27 @@ export class kpiPeriodController extends Controller { @Query("pageSize") pageSize: number = 10, @Query("year") year?: number, @Query("keyword") keyword?: string, + @Query("sortBy") sortBy?: string, + @Query("descending") descending?: boolean, ) { - const [kpiPeriod, total] = await AppDataSource.getRepository(KpiPeriod) + let query = await AppDataSource.getRepository(KpiPeriod) .createQueryBuilder("kpiPeriod") .andWhere( year !== 0 && year != null && year != undefined ? "kpiPeriod.year = :year" : "1=1", { year: year }, ) - .orderBy("kpiPeriod.year", "DESC") - .addOrderBy("kpiPeriod.createdAt", "DESC") + + if (sortBy) { + query = query.orderBy( + `developmentRequest.${sortBy}`, + descending ? "DESC" : "ASC" + ); + }else{ + query = query.orderBy("kpiPeriod.year", "DESC") + .addOrderBy("kpiPeriod.createdAt", "DESC") + } + + const [kpiPeriod, total] = await query .skip((page - 1) * pageSize) .take(pageSize) .getManyAndCount(); diff --git a/src/controllers/KpiUserDevelopmentController.ts b/src/controllers/KpiUserDevelopmentController.ts index 8f8a2fe..5512e8f 100644 --- a/src/controllers/KpiUserDevelopmentController.ts +++ b/src/controllers/KpiUserDevelopmentController.ts @@ -360,6 +360,8 @@ export class KpiUserDevelopmentController extends Controller { // results?: string | null; // reqedit?: string | null; // evaluating?: boolean | null; + sortBy?: string; + descending?: boolean; }, ) { // await new permission().PermissionList(request, "SYS_RESULT"); @@ -372,7 +374,7 @@ export class KpiUserDevelopmentController extends Controller { _data = x; }) .catch((x) => {}); - const [kpiUserDevelopment, total] = await AppDataSource.getRepository(KpiUserDevelopment) + let query = await AppDataSource.getRepository(KpiUserDevelopment) .createQueryBuilder("kpiUserDevelopment") .leftJoinAndSelect("kpiUserDevelopment.kpiUserEvaluation", "kpiUserEvaluation") .leftJoinAndSelect("kpiUserEvaluation.kpiPeriod", "kpiPeriod") @@ -476,7 +478,46 @@ export class KpiUserDevelopmentController extends Controller { }); }), ) - .orderBy("kpiUserDevelopment.createdAt", "ASC") + + if (requestBody.sortBy) { + if(requestBody.sortBy === "developmentName"){ + query = query.orderBy( + `kpiUserDevelopment.name`, + requestBody.descending ? "DESC" : "ASC" + ); + }else if (requestBody.sortBy === "organization"){ + query = query + .orderBy(`kpiUserEvaluation.child4`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.child3`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.child2`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.child1`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.org`, requestBody.descending ? "DESC" : "ASC"); + }else if(requestBody.sortBy === "firstname"){ + query = query.orderBy( + `kpiUserEvaluation.firstName`, + requestBody.descending ? "DESC" : "ASC" + ); + }else if(requestBody.sortBy === "lastname"){ + query = query.orderBy( + `kpiUserEvaluation.lastName`, + requestBody.descending ? "DESC" : "ASC" + ); + }else if(requestBody.sortBy === "root"){ + query = query.orderBy( + `kpiUserEvaluation.org`, + requestBody.descending ? "DESC" : "ASC" + ); + }else{ + query = query.orderBy( + `kpiUserEvaluation.${requestBody.sortBy}`, + requestBody.descending ? "DESC" : "ASC" + ); + } + }else{ + query = query.orderBy("kpiUserDevelopment.createdAt", "ASC") + } + + const [kpiUserDevelopment, total] = await query .skip((requestBody.page - 1) * requestBody.pageSize) .take(requestBody.pageSize) .getManyAndCount(); diff --git a/src/controllers/KpiUserEvaluationController.ts b/src/controllers/KpiUserEvaluationController.ts index e78a8ec..61f9f74 100644 --- a/src/controllers/KpiUserEvaluationController.ts +++ b/src/controllers/KpiUserEvaluationController.ts @@ -241,6 +241,8 @@ export class KpiUserEvaluationController extends Controller { results?: string | null; reqedit?: string | null; evaluating?: boolean | null; + sortBy?: string; + descending?: boolean; }, ) { // await new permission().PermissionList(request, "SYS_RESULT"); @@ -253,7 +255,7 @@ export class KpiUserEvaluationController extends Controller { _data = x; }) .catch((x) => {}); - const [kpiUserEvaluation, total] = await AppDataSource.getRepository(KpiUserEvaluation) + let query = await AppDataSource.getRepository(KpiUserEvaluation) .createQueryBuilder("kpiUserEvaluation") .andWhere( _data.root != undefined && _data.root != null @@ -385,7 +387,32 @@ export class KpiUserEvaluationController extends Controller { }); }), ) - .orderBy("kpiUserEvaluation.createdAt", "DESC") + + if (requestBody.sortBy) { + if(requestBody.sortBy === "root"){ + query = query.orderBy( + `kpiUserEvaluation.org`, + requestBody.descending ? "DESC" : "ASC" + ); + }else if(requestBody.sortBy === "organization"){ + query = query + .orderBy(`kpiUserEvaluation.child4`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.child3`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.child2`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.child1`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.org`, requestBody.descending ? "DESC" : "ASC"); + }else{ + query = query.orderBy( + `kpiUserEvaluation.${requestBody.sortBy}`, + requestBody.descending ? "DESC" : "ASC" + ); + } + }else{ + query = query.orderBy("kpiPeriod.year", "DESC") + .addOrderBy("kpiUserEvaluation.createdAt", "DESC") + } + + const [kpiUserEvaluation, total] = await query .skip((requestBody.page - 1) * requestBody.pageSize) .take(requestBody.pageSize) .getManyAndCount(); @@ -441,6 +468,8 @@ export class KpiUserEvaluationController extends Controller { keyword?: string; status?: string | null; results?: string | null; + sortBy?: string; + descending?: boolean; }, ) { let _data = await new permission().PermissionOrgList(request, "SYS_KPI_LIST"); @@ -452,7 +481,7 @@ export class KpiUserEvaluationController extends Controller { .catch((x) => {}); let conditionFullName = "CONCAT(kpiUserEvaluation.prefix, kpiUserEvaluation.firstName, ' ', kpiUserEvaluation.lastName) LIKE :keyword"; - const [kpiUserEvaluation, total] = await AppDataSource.getRepository(KpiUserEvaluation) + let query = await AppDataSource.getRepository(KpiUserEvaluation) .createQueryBuilder("kpiUserEvaluation") .leftJoinAndSelect("kpiUserEvaluation.kpiPeriod", "kpiPeriod") .andWhere( @@ -564,8 +593,32 @@ export class KpiUserEvaluationController extends Controller { child4: _data.child4, }, ) - .orderBy("kpiPeriod.year", "DESC") - .addOrderBy("kpiUserEvaluation.createdAt", "DESC") + + if (requestBody.sortBy) { + if(requestBody.sortBy === "root"){ + query = query.orderBy( + `kpiUserEvaluation.org`, + requestBody.descending ? "DESC" : "ASC" + ); + }else if(requestBody.sortBy === "organization"){ + query = query + .orderBy(`kpiUserEvaluation.child4`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.child3`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.child2`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.child1`, requestBody.descending ? "DESC" : "ASC") + .addOrderBy(`kpiUserEvaluation.org`, requestBody.descending ? "DESC" : "ASC"); + }else{ + query = query.orderBy( + `kpiUserEvaluation.${requestBody.sortBy}`, + requestBody.descending ? "DESC" : "ASC" + ); + } + }else{ + query = query.orderBy("kpiPeriod.year", "DESC") + .addOrderBy("kpiUserEvaluation.createdAt", "DESC") + } + + const [kpiUserEvaluation, total] = await query .skip((requestBody.page - 1) * requestBody.pageSize) .take(requestBody.pageSize) .getManyAndCount(); From 1a402f4647dd0dae4b2d7c6bc23cb36a7a87444d Mon Sep 17 00:00:00 2001 From: Adisak Date: Thu, 2 Oct 2025 15:26:36 +0700 Subject: [PATCH 2/5] revert /api/v1/kpi/period --- src/controllers/KpiPeriodController.ts | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/controllers/KpiPeriodController.ts b/src/controllers/KpiPeriodController.ts index d141f96..43a03ab 100644 --- a/src/controllers/KpiPeriodController.ts +++ b/src/controllers/KpiPeriodController.ts @@ -302,27 +302,15 @@ export class kpiPeriodController extends Controller { @Query("pageSize") pageSize: number = 10, @Query("year") year?: number, @Query("keyword") keyword?: string, - @Query("sortBy") sortBy?: string, - @Query("descending") descending?: boolean, ) { - let query = await AppDataSource.getRepository(KpiPeriod) + const [kpiPeriod,total] = await AppDataSource.getRepository(KpiPeriod) .createQueryBuilder("kpiPeriod") .andWhere( year !== 0 && year != null && year != undefined ? "kpiPeriod.year = :year" : "1=1", { year: year }, ) - - if (sortBy) { - query = query.orderBy( - `developmentRequest.${sortBy}`, - descending ? "DESC" : "ASC" - ); - }else{ - query = query.orderBy("kpiPeriod.year", "DESC") - .addOrderBy("kpiPeriod.createdAt", "DESC") - } - - const [kpiPeriod, total] = await query + .orderBy("kpiPeriod.year", "DESC") + .addOrderBy("kpiPeriod.createdAt", "DESC") .skip((page - 1) * pageSize) .take(pageSize) .getManyAndCount(); From f6485d46074d899c6cff634bbb578ffddf8c8a7e Mon Sep 17 00:00:00 2001 From: Adisak Date: Thu, 2 Oct 2025 15:38:17 +0700 Subject: [PATCH 3/5] fix --- src/controllers/KpiUserEvaluationController.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/controllers/KpiUserEvaluationController.ts b/src/controllers/KpiUserEvaluationController.ts index 61f9f74..b311bae 100644 --- a/src/controllers/KpiUserEvaluationController.ts +++ b/src/controllers/KpiUserEvaluationController.ts @@ -408,8 +408,7 @@ export class KpiUserEvaluationController extends Controller { ); } }else{ - query = query.orderBy("kpiPeriod.year", "DESC") - .addOrderBy("kpiUserEvaluation.createdAt", "DESC") + query = query.orderBy("kpiUserEvaluation.createdAt", "DESC") } const [kpiUserEvaluation, total] = await query From 53bab9a0c74d2a55f0496cf4bb48f4c98c564004 Mon Sep 17 00:00:00 2001 From: Harid Promsri <52228846+Harid-999@users.noreply.github.com> Date: Mon, 6 Oct 2025 18:08:29 +0700 Subject: [PATCH 4/5] Task/#1839 (#21) * no message * discord-notify.yml --------- Co-authored-by: harid --- .forgejo/workflows/build.yml | 50 ++++++++++++++++++++++++++++ .github/workflows/discord-notify.yml | 22 ++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 .forgejo/workflows/build.yml create mode 100644 .github/workflows/discord-notify.yml diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml new file mode 100644 index 0000000..c4746ff --- /dev/null +++ b/.forgejo/workflows/build.yml @@ -0,0 +1,50 @@ +# /.forgejo/workflows/build.yml +name: Build + +on: + push: + tags: + - "v[0-9]+.[0-9]+.[0-9]+" + - "v[0-9]+.[0-9]+.[0-9]+*" + workflow_dispatch: + +env: + REGISTRY: ${{ vars.CONTAINER_REGISTRY }} + REGISTRY_USERNAME: ${{ vars.CONTAINER_REGISTRY_USERNAME }} + REGISTRY_PASSWORD: ${{ secrets.CONTAINER_REGISTRY_PASSWORD }} + CONTAINER_IMAGE_NAME: ${{ vars.CONTAINER_REGISTRY }}/${{ vars.CONTAINER_IMAGE_OWNER }}/${{ vars.CONTAINER_IMAGE_NAME }} + IMAGE_VERSION: build + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + config-inline: | + [registry."${{ env.REGISTRY }}"] + ca=["/etc/ssl/certs/ca-certificates.crt"] + - name: Tag Version + run: | + if [[ "${{ github.event_name }}" == "push" ]]; then + echo "IMAGE_VERSION=${{ github.ref_name }}" | sed 's/v//g' >> $GITHUB_ENV + else + echo "IMAGE_VERSION=${{ env.IMAGE_VERSION }}-${{ github.run_number }}" >> $GITHUB_ENV + fi + - name: Login in to registry + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ env.REGISTRY_USERNAME }} + password: ${{ env.REGISTRY_PASSWORD }} + - name: Build and push docker image + uses: docker/build-push-action@v3 + with: + platforms: linux/amd64 + context: . + file: ./docker/Dockerfile + tags: ${{ env.CONTAINER_IMAGE_NAME }}:latest,${{ env.CONTAINER_IMAGE_NAME }}:${{ env.IMAGE_VERSION }} + push: true \ No newline at end of file diff --git a/.github/workflows/discord-notify.yml b/.github/workflows/discord-notify.yml new file mode 100644 index 0000000..ce4ee51 --- /dev/null +++ b/.github/workflows/discord-notify.yml @@ -0,0 +1,22 @@ +name: Discord PR Notify + +on: + pull_request: + types: [opened] + +jobs: + discord: + runs-on: ubuntu-latest + steps: + - name: Send Discord + run: | + curl -X POST "${{ secrets.DISCORD_WEBHOOK_PULLREQUEST }}" \ + -H "Content-Type: application/json" \ + -d '{ + "embeds": [{ + "title": "šŸ”” **Service:** ${{ github.repository }}", + "description": "šŸ‘¤ **Author:** ${{ github.event.pull_request.user.login }}\n🌿 **Branch:** ${{ github.event.pull_request.head.ref }} → ${{ github.event.pull_request.base.ref }}\nšŸ“¦ **Pull Request:** [#${{ github.event.pull_request.number }} - ${{ github.event.pull_request.title }}](${{ github.event.pull_request.html_url }})", + "color": 5814783, + "timestamp": "${{ github.event.pull_request.created_at }}" + }] + }' From 63fe730a04d2cbcbeabbbe77da13c52ad9e059d7 Mon Sep 17 00:00:00 2001 From: Harid Promsri <52228846+Harid-999@users.noreply.github.com> Date: Tue, 21 Oct 2025 14:43:10 +0700 Subject: [PATCH 5/5] Issue/#1880 (#22) * no message * fix log * Revert "fix log" This reverts commit 0f391a764d00af41bbd124beda74da3bee2f0b2a. * fix log --------- Co-authored-by: harid --- src/interfaces/permission.ts | 84 +++++++++++++----------------------- 1 file changed, 31 insertions(+), 53 deletions(-) diff --git a/src/interfaces/permission.ts b/src/interfaces/permission.ts index cfe76e6..6ff8977 100644 --- a/src/interfaces/permission.ts +++ b/src/interfaces/permission.ts @@ -184,61 +184,39 @@ class CheckAuth { }); } public async checkOrg(token: any, keycloakId: string) { - try { - // Validate required environment variables - const REDIS_HOST = process.env.REDIS_HOST; - const REDIS_PORT = process.env.REDIS_PORT ? Number(process.env.REDIS_PORT) : 6379; + const redisClient = await this.redis.createClient({ + host: process.env.REDIS_HOST, + port: process.env.REDIS_PORT, + }) + const getAsync = promisify(redisClient.get).bind(redisClient) + try { + let reply = await getAsync("org_" + keycloakId) + if (reply != null) { + reply = JSON.parse(reply) + } else { + if (!keycloakId) throw new Error("No KeycloakId provided") + const x = await new CallAPI().GetData( + { + headers: { authorization: token }, + }, + `/org/permission/checkOrg/${keycloakId}`, + false + ) - if (!REDIS_HOST) { - throw new Error("REDIS_HOST is not set in environment variables"); - } + const data = { + orgRootId: x.orgRootId, + orgChild1Id: x.orgChild1Id, + orgChild2Id: x.orgChild2Id, + orgChild3Id: x.orgChild3Id, + orgChild4Id: x.orgChild4Id, + } - console.log(`[REDIS] Connecting to Redis at ${REDIS_HOST}:${REDIS_PORT}`); - - // Create Redis client - const redisClient = this.redis.createClient({ - socket: { - host: REDIS_HOST, - port: REDIS_PORT, - }, - }); - - redisClient.on("error", (err: any) => { - console.error("[REDIS] Connection error:", err.message); - }); - - await redisClient.connect(); - console.log("[REDIS] Connected successfully!"); - - const getAsync = promisify(redisClient.get).bind(redisClient); - - let reply = await getAsync("org_" + keycloakId); - if (reply != null) { - reply = JSON.parse(reply); - } else { - if (!keycloakId) throw new Error("No KeycloakId provided"); - const x = await new CallAPI().GetData( - { - headers: { authorization: token }, - }, - `/org/permission/checkOrg/${keycloakId}`, - false, - ); - - const data = { - orgRootId: x.orgRootId, - orgChild1Id: x.orgChild1Id, - orgChild2Id: x.orgChild2Id, - orgChild3Id: x.orgChild3Id, - orgChild4Id: x.orgChild4Id, - }; - - return data; - } - } catch (error) { - console.error("Error calling API:", error); - throw error; - } + return data + } + } catch (error) { + console.error("Error calling API:", error) + throw error + } } public async PermissionCreate(req: RequestWithUser, system: string) { return await this.Permission(req, system, "CREATE");