Merge branch 'develop' into adiDev
This commit is contained in:
commit
f8c0d7a2e9
6 changed files with 1303 additions and 191 deletions
|
|
@ -10,3 +10,9 @@ DB_PORT=3306
|
|||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
DB_NAME=dev
|
||||
|
||||
KC_URL=http://192.168.1.50:8080
|
||||
KC_REALM=dev
|
||||
KC_SERVICE_ACCOUNT_CLIENT_ID=dev-service
|
||||
KC_SERVICE_ACCOUNT_SECRET=
|
||||
MANAGEMENT_ROLE=storage_management
|
||||
|
|
@ -19,39 +19,13 @@ import { AppDataSource } from "../database/data-source";
|
|||
import HttpSuccess from "../interfaces/http-success";
|
||||
import HttpStatus from "../interfaces/http-status";
|
||||
import HttpError from "../interfaces/http-error";
|
||||
import {
|
||||
Profile,
|
||||
CreateProfile,
|
||||
UpdateProfile,
|
||||
ProfileHistory,
|
||||
CreateProfileAllFields,
|
||||
} from "../entities/Profile";
|
||||
import { RequestWithUser } from "../middlewares/user";
|
||||
import { Profile } from "../entities/Profile";
|
||||
import { Brackets, IsNull, Like, Not } from "typeorm";
|
||||
import { OrgRevision } from "../entities/OrgRevision";
|
||||
import { PosMaster } from "../entities/PosMaster";
|
||||
import { PosLevel } from "../entities/PosLevel";
|
||||
import { PosType } from "../entities/PosType";
|
||||
import {
|
||||
calculateAge,
|
||||
calculateRetireDate,
|
||||
calculateRetireLaw,
|
||||
calculateRetireYear,
|
||||
} from "../interfaces/utils";
|
||||
import { RequestWithUser } from "../middlewares/user";
|
||||
import { Position } from "../entities/Position";
|
||||
import { OrgRoot } from "../entities/OrgRoot";
|
||||
import { ProfileEmployee } from "../entities/ProfileEmployee";
|
||||
import { Province } from "../entities/Province";
|
||||
import { District } from "../entities/District";
|
||||
import { SubDistrict } from "../entities/SubDistrict";
|
||||
import { ProfileCertificate } from "../entities/ProfileCertificate";
|
||||
import { ProfileTraining } from "../entities/ProfileTraining";
|
||||
import { ProfileDiscipline } from "../entities/ProfileDiscipline";
|
||||
import { ProfileEducation } from "../entities/ProfileEducation";
|
||||
import { ProfileSalary } from "../entities/ProfileSalary";
|
||||
import { ProfileFamilyCouple } from "../entities/ProfileFamilyCouple";
|
||||
import { ProfileFamilyMother } from "../entities/ProfileFamilyMother";
|
||||
import { ProfileFamilyFather } from "../entities/ProfileFamilyFather";
|
||||
import Extension from "../interfaces/extension";
|
||||
import { Position } from "../entities/Position";
|
||||
|
||||
@Route("api/v1/org/dotnet")
|
||||
@Tags("Dotnet")
|
||||
|
|
@ -62,25 +36,10 @@ import Extension from "../interfaces/extension";
|
|||
)
|
||||
@SuccessResponse(HttpStatus.OK, "สำเร็จ")
|
||||
export class OrganizationDotnetController extends Controller {
|
||||
private orgRootRepo = AppDataSource.getRepository(OrgRoot);
|
||||
private orgRevisionRepo = AppDataSource.getRepository(OrgRevision);
|
||||
private posMasterRepo = AppDataSource.getRepository(PosMaster);
|
||||
private profileRepo = AppDataSource.getRepository(Profile);
|
||||
private profileEmpRepo = AppDataSource.getRepository(ProfileEmployee);
|
||||
private profileHistoryRepo = AppDataSource.getRepository(ProfileHistory);
|
||||
private posLevelRepo = AppDataSource.getRepository(PosLevel);
|
||||
private posTypeRepo = AppDataSource.getRepository(PosType);
|
||||
private positionRepository = AppDataSource.getRepository(Position);
|
||||
private provinceRepository = AppDataSource.getRepository(Province);
|
||||
private districtRepository = AppDataSource.getRepository(District);
|
||||
private subDistrict = AppDataSource.getRepository(SubDistrict);
|
||||
private certificateRepository = AppDataSource.getRepository(ProfileCertificate);
|
||||
private profileFamilyCoupleRepository = AppDataSource.getRepository(ProfileFamilyCouple);
|
||||
private profileFamilyMotherRepository = AppDataSource.getRepository(ProfileFamilyMother);
|
||||
private profileFamilyFatherRepository = AppDataSource.getRepository(ProfileFamilyFather);
|
||||
private trainingRepository = AppDataSource.getRepository(ProfileTraining);
|
||||
private disciplineRepository = AppDataSource.getRepository(ProfileDiscipline);
|
||||
private educationRepository = AppDataSource.getRepository(ProfileEducation);
|
||||
private salaryRepository = AppDataSource.getRepository(ProfileSalary);
|
||||
|
||||
/**
|
||||
* 1. API Search Profile
|
||||
|
|
@ -89,7 +48,7 @@ export class OrganizationDotnetController extends Controller {
|
|||
*
|
||||
*/
|
||||
@Post("search")
|
||||
public async searchProfile(
|
||||
public async SearchProfile(
|
||||
@Body()
|
||||
body: {
|
||||
citizenId?: string | null;
|
||||
|
|
@ -118,71 +77,435 @@ export class OrganizationDotnetController extends Controller {
|
|||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const profiles = await queryBuilder.getMany();
|
||||
|
||||
if (!profiles.length) {
|
||||
throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบข้อมูลโปรไฟล์");
|
||||
}
|
||||
|
||||
const formattedProfiles = profiles.map((profile) => ({
|
||||
avatar: profile.avatar,
|
||||
avatarName: profile.avatarName,
|
||||
rank: profile.rank,
|
||||
prefix: profile.prefix,
|
||||
firstName: profile.firstName,
|
||||
lastName: profile.lastName,
|
||||
citizenId: profile.citizenId,
|
||||
position: profile.position,
|
||||
posLevelId: profile.posLevelId,
|
||||
posLevelName: profile.posLevel.posLevelName,
|
||||
posTypeId: profile.posTypeId,
|
||||
posTypeName: profile.posType.posTypeName,
|
||||
email: profile.email,
|
||||
phone: profile.phone,
|
||||
keycloak: profile.keycloak,
|
||||
isProbation: profile.isProbation,
|
||||
isLeave: profile.isLeave,
|
||||
leaveReason: profile.leaveReason,
|
||||
dateRetire: profile.dateRetire,
|
||||
dateAppoint: profile.dateAppoint,
|
||||
dateRetireLaw: profile.dateRetireLaw,
|
||||
dateStart: profile.dateStart,
|
||||
govAgeAbsent: profile.govAgeAbsent,
|
||||
govAgePlus: profile.govAgePlus,
|
||||
birthDate: profile.birthDate,
|
||||
reasonSameDate: profile.reasonSameDate,
|
||||
ethnicity: profile.ethnicity,
|
||||
telephoneNumber: profile.telephoneNumber,
|
||||
nationality: profile.nationality,
|
||||
gender: profile.gender,
|
||||
relationship: profile.relationship,
|
||||
religion: profile.religion,
|
||||
bloodGroup: profile.bloodGroup,
|
||||
}));
|
||||
|
||||
return new HttpSuccess(formattedProfiles);
|
||||
const profiles = await queryBuilder.getMany();
|
||||
return new HttpSuccess(profiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 6. Search Employee
|
||||
*
|
||||
* @summary 6. Search Employee
|
||||
*
|
||||
*/
|
||||
@Post("search-employee")
|
||||
public async SearchProfileEmployee(
|
||||
@Body()
|
||||
body: {
|
||||
citizenId?: string | null;
|
||||
firstName?: string | null;
|
||||
lastName?: string | null;
|
||||
},
|
||||
) {
|
||||
const profileRepository = AppDataSource.getRepository(ProfileEmployee);
|
||||
const queryBuilder = profileRepository
|
||||
.createQueryBuilder("profile")
|
||||
.leftJoinAndSelect("profile.posLevel", "posLevel")
|
||||
.leftJoinAndSelect("profile.posType", "posType");
|
||||
|
||||
if (body.citizenId || body.firstName || body.lastName) {
|
||||
queryBuilder.where(
|
||||
new Brackets((qb) => {
|
||||
if (body.citizenId) {
|
||||
qb.orWhere("profile.citizenId LIKE :citizenId", { citizenId: `%${body.citizenId}%` });
|
||||
}
|
||||
if (body.firstName) {
|
||||
qb.orWhere("profile.firstName LIKE :firstName", { firstName: `%${body.firstName}%` });
|
||||
}
|
||||
if (body.lastName) {
|
||||
qb.orWhere("profile.lastName LIKE :lastName", { lastName: `%${body.lastName}%` });
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
const profileEmp = await queryBuilder.getMany();
|
||||
return new HttpSuccess(profileEmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 2. API ข้อมูลหน่วยงานตามโครงสร้าง
|
||||
*
|
||||
* @summary 2. API ข้อมูลหน่วยงานตามโครงสร้าง
|
||||
*
|
||||
* @param {string} id Id หน่วยงาน
|
||||
*/
|
||||
@Get("org/{id}")
|
||||
async GetOrganizationById(@Path() id: string) {
|
||||
const orgRoot = await this.orgRootRepo.findOne({
|
||||
where: { id: id },
|
||||
});
|
||||
if (!orgRoot) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
|
||||
return new HttpSuccess(orgRoot);
|
||||
}
|
||||
|
||||
@Get("agency/{id}")
|
||||
async GetOrgAgencyById(@Path() id: string) {
|
||||
const orgRoot = await this.orgRootRepo.findOne({
|
||||
where: { id: id },
|
||||
});
|
||||
if (!orgRoot) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
|
||||
return new HttpSuccess(orgRoot);
|
||||
}
|
||||
|
||||
@Get("go-agency/{id}")
|
||||
async GetOrgGoAgencyById(@Path() id: string) {
|
||||
const orgRoot = await this.orgRootRepo.findOne({
|
||||
where: { id: id },
|
||||
});
|
||||
if (!orgRoot) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
|
||||
return new HttpSuccess(orgRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* 3. API Get Profile จาก keycloak id
|
||||
*
|
||||
* @summary 3. API Get Profile จาก keycloak id
|
||||
*
|
||||
* @param {string} keycloakId Id keycloak
|
||||
*/
|
||||
@Get("keycloak/{id}")
|
||||
async getProfileByKeycloakId(@Path() id: string) {
|
||||
@Get("keycloak/{keycloakId}")
|
||||
async GetProfileByKeycloakIdAsync(@Path() keycloakId: string) {
|
||||
const profile = await this.profileRepo.findOne({
|
||||
relations: {
|
||||
posLevel: true,
|
||||
posType: true,
|
||||
profileSalary: true
|
||||
},
|
||||
where: { keycloak: id },
|
||||
where: { keycloak: keycloakId },
|
||||
order:{
|
||||
profileSalary:{
|
||||
date: "DESC"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
|
||||
|
||||
const mapProfile = {
|
||||
id: profile.id,
|
||||
avatar: profile.avatar,
|
||||
avatarName: profile.avatarName,
|
||||
rank: profile.rank,
|
||||
prefix: profile.prefix,
|
||||
firstName: profile.firstName,
|
||||
lastName: profile.lastName,
|
||||
citizenId: profile.citizenId,
|
||||
position: profile.position,
|
||||
posLevelId: profile.posLevelId,
|
||||
email: profile.email,
|
||||
phone: profile.phone,
|
||||
keycloak: profile.keycloak,
|
||||
isProbation: profile.isProbation,
|
||||
isLeave: profile.isLeave,
|
||||
leaveReason: profile.leaveReason,
|
||||
dateRetire: profile.dateRetire,
|
||||
dateAppoint: profile.dateAppoint,
|
||||
dateRetireLaw: profile.dateRetireLaw,
|
||||
dateStart: profile.dateStart,
|
||||
govAgeAbsent: profile.govAgeAbsent,
|
||||
govAgePlus: profile.govAgePlus,
|
||||
birthDate: profile.birthDate,
|
||||
reasonSameDate: profile.reasonSameDate,
|
||||
telephoneNumber: profile.telephoneNumber,
|
||||
nationality: profile.nationality,
|
||||
gender: profile.gender,
|
||||
relationship: profile.relationship,
|
||||
religion: profile.religion,
|
||||
bloodGroup: profile.bloodGroup,
|
||||
registrationAddress: profile.registrationAddress,
|
||||
registrationProvinceId: profile.registrationProvinceId,
|
||||
registrationDistrictId: profile.registrationDistrictId,
|
||||
registrationSubDistrictId: profile.registrationSubDistrictId,
|
||||
registrationZipCode: profile.registrationZipCode,
|
||||
currentAddress: profile.currentAddress,
|
||||
currentProvinceId: profile.currentProvinceId,
|
||||
currentSubDistrictId: profile.currentSubDistrictId,
|
||||
currentZipCode: profile.currentZipCode,
|
||||
dutyTimeId: profile.dutyTimeId,
|
||||
dutyTimeEffectiveDate: profile.dutyTimeEffectiveDate,
|
||||
posLevel: profile.posLevel? profile.posLevel : null,
|
||||
posType: profile.posType? profile.posType : null,
|
||||
profileSalary: profile.profileSalary.length > 0
|
||||
? profile.profileSalary[0]
|
||||
: null
|
||||
}
|
||||
|
||||
return new HttpSuccess(mapProfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 7.1 Get ข้อมูล GetUserFullName
|
||||
*
|
||||
* @summary 7.1 Get ข้อมูล GetUserFullName
|
||||
*
|
||||
* @param {string} keycloakId Id keycloak
|
||||
*/
|
||||
@Get("user-fullname/{keycloakId}")
|
||||
async GetUserFullName(@Path() keycloakId: string) {
|
||||
const profile = await this.profileRepo.findOne({
|
||||
where: { keycloak: keycloakId },
|
||||
select: ["prefix", "firstName", "lastName"]
|
||||
});
|
||||
if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
|
||||
const fullName = profile? `${profile.prefix}${profile.firstName} ${profile.lastName}` : "-";
|
||||
return new HttpSuccess(fullName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 7.2 Get ข้อมูล GetUserOCId
|
||||
*
|
||||
* @summary 7.2 Get ข้อมูล GetUserOCId
|
||||
*
|
||||
* @param {string} keycloakId Id keycloak
|
||||
*/
|
||||
@Get("user-oc/{keycloakId}")
|
||||
async getProfileByKeycloak(@Path() keycloakId: string) {
|
||||
const profile = await this.profileRepo.findOne({
|
||||
where: { keycloak: keycloakId },
|
||||
relations: ["posLevel", "posType", "current_holders", "current_holders.orgRoot"],
|
||||
});
|
||||
if (!profile) {
|
||||
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลบุคคลนี้ในระบบ");
|
||||
}
|
||||
|
||||
const orgRevisionPublish = await this.orgRevisionRepo
|
||||
.createQueryBuilder("orgRevision")
|
||||
.where("orgRevision.orgRevisionIsDraft = false")
|
||||
.andWhere("orgRevision.orgRevisionIsCurrent = true")
|
||||
.getOne();
|
||||
if (!orgRevisionPublish) {
|
||||
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบแบบร่างโครงสร้าง");
|
||||
}
|
||||
|
||||
const root =
|
||||
profile.current_holders == null ||
|
||||
profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgRoot == null
|
||||
? null
|
||||
: profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgRoot;
|
||||
|
||||
const _profile: any = {
|
||||
profileId: profile.id,
|
||||
prefix: profile.prefix,
|
||||
rank: profile.rank,
|
||||
avatar: profile.avatar,
|
||||
avatarName: profile.avatarName,
|
||||
firstName: profile.firstName,
|
||||
lastName: profile.lastName,
|
||||
citizenId: profile.citizenId,
|
||||
birthDate: profile.birthDate,
|
||||
position: profile.position,
|
||||
rootId: root == null ? null : root.id,
|
||||
root: root == null ? null : root.orgRootName,
|
||||
rootShortName: root == null ? null : root.orgRootShortName,
|
||||
};
|
||||
return new HttpSuccess(profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 7.3 Get ข้อมูล GetUserOCId (all node)
|
||||
*
|
||||
* @summary 7.3 Get ข้อมูล GetUserOCId (all node)
|
||||
*
|
||||
* @param {string} keycloakId Id keycloak
|
||||
*/
|
||||
@Get("user-oc-all/{keycloakId}")
|
||||
async getAllProfileByKeycloak(@Path() keycloakId: string) {
|
||||
const profile = await this.profileRepo.findOne({
|
||||
where: { keycloak: keycloakId },
|
||||
relations: [
|
||||
"profileSalary",
|
||||
"profileEducations",
|
||||
"current_holders",
|
||||
"current_holders.orgRoot",
|
||||
"current_holders.orgChild1",
|
||||
"current_holders.orgChild2",
|
||||
"current_holders.orgChild3",
|
||||
"current_holders.orgChild4",
|
||||
],
|
||||
});
|
||||
if (!profile) {
|
||||
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลบุคคลนี้ในระบบ");
|
||||
}
|
||||
|
||||
const orgRevisionPublish = await this.orgRevisionRepo
|
||||
.createQueryBuilder("orgRevision")
|
||||
.where("orgRevision.orgRevisionIsDraft = false")
|
||||
.andWhere("orgRevision.orgRevisionIsCurrent = true")
|
||||
.getOne();
|
||||
if (!orgRevisionPublish) {
|
||||
throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบแบบร่างโครงสร้าง");
|
||||
}
|
||||
|
||||
const posMaster =
|
||||
profile.current_holders == null ||
|
||||
profile.current_holders.length == 0 ||
|
||||
profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id) == null
|
||||
? null
|
||||
: profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id);
|
||||
|
||||
const root =
|
||||
profile.current_holders == null ||
|
||||
profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgRoot == null
|
||||
? null
|
||||
: profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgRoot;
|
||||
|
||||
const child1 =
|
||||
profile.current_holders == null ||
|
||||
profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgChild1 ==
|
||||
null
|
||||
? null
|
||||
: profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgChild1;
|
||||
|
||||
const child2 =
|
||||
profile.current_holders == null ||
|
||||
profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgChild2 ==
|
||||
null
|
||||
? null
|
||||
: profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgChild2;
|
||||
|
||||
const child3 =
|
||||
profile.current_holders == null ||
|
||||
profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgChild3 ==
|
||||
null
|
||||
? null
|
||||
: profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgChild3;
|
||||
|
||||
const child4 =
|
||||
profile.current_holders == null ||
|
||||
profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgChild4 ==
|
||||
null
|
||||
? null
|
||||
: profile.current_holders.find((x) => x.orgRevisionId == orgRevisionPublish.id)?.orgChild4;
|
||||
|
||||
const position = await this.positionRepository.findOne({
|
||||
relations: ["posExecutive"],
|
||||
where: {
|
||||
posMasterId: posMaster?.id,
|
||||
},
|
||||
});
|
||||
|
||||
const _profile: any = {
|
||||
profileId: profile.id,
|
||||
prefix: profile.prefix,
|
||||
rank: profile.rank,
|
||||
avatar: profile.avatar,
|
||||
avatarName: profile.avatarName,
|
||||
firstName: profile.firstName,
|
||||
lastName: profile.lastName,
|
||||
citizenId: profile.citizenId,
|
||||
birthDate: profile.birthDate,
|
||||
position: profile.position,
|
||||
posMaster: posMaster == null ? null : posMaster.posMasterNo,
|
||||
posMasterNo: posMaster == null ? null : posMaster.posMasterNo,
|
||||
posLevelName: profile.posLevel == null ? null : profile.posLevel.posLevelName,
|
||||
posLevelRank: profile.posLevel == null ? null : profile.posLevel.posLevelRank,
|
||||
posLevelId: profile.posLevel == null ? null : profile.posLevel.id,
|
||||
posTypeName: profile.posType == null ? null : profile.posType.posTypeName,
|
||||
posTypeRank: profile.posType == null ? null : profile.posType.posTypeRank,
|
||||
posTypeId: profile.posType == null ? null : profile.posType.id,
|
||||
posExecutiveName:
|
||||
position == null || position.posExecutive == null
|
||||
? null
|
||||
: position.posExecutive.posExecutiveName,
|
||||
posExecutivePriority:
|
||||
position == null || position.posExecutive == null
|
||||
? null
|
||||
: position.posExecutive.posExecutivePriority,
|
||||
posExecutiveId:
|
||||
position == null || position.posExecutive == null ? null : position.posExecutive.id,
|
||||
rootId: root == null ? null : root.id,
|
||||
root: root == null ? null : root.orgRootName,
|
||||
rootShortName: root == null ? null : root.orgRootShortName,
|
||||
child1Id: child1 == null ? null : child1.id,
|
||||
child1: child1 == null ? null : child1.orgChild1Name,
|
||||
child1ShortName: child1 == null ? null : child1.orgChild1ShortName,
|
||||
child2Id: child2 == null ? null : child2.id,
|
||||
child2: child2 == null ? null : child2.orgChild2Name,
|
||||
child2ShortName: child2 == null ? null : child2.orgChild2ShortName,
|
||||
child3Id: child3 == null ? null : child3.id,
|
||||
child3: child3 == null ? null : child3.orgChild3Name,
|
||||
child3ShortName: child3 == null ? null : child3.orgChild3ShortName,
|
||||
child4Id: child4 == null ? null : child4.id,
|
||||
child4: child4 == null ? null : child4.orgChild4Name,
|
||||
child4ShortName: child4 == null ? null : child4.orgChild4ShortName,
|
||||
node: null,
|
||||
nodeId: null,
|
||||
};
|
||||
|
||||
if (_profile.child4Id != null) {
|
||||
_profile.node = 4;
|
||||
_profile.nodeId = _profile.child4Id;
|
||||
} else if (_profile.child3Id != null) {
|
||||
_profile.node = 3;
|
||||
_profile.nodeId = _profile.child3Id;
|
||||
} else if (_profile.child2Id != null) {
|
||||
_profile.node = 2;
|
||||
_profile.nodeId = _profile.child2Id;
|
||||
} else if (_profile.child1Id != null) {
|
||||
_profile.node = 1;
|
||||
_profile.nodeId = _profile.child1Id;
|
||||
} else if (_profile.rootId != null) {
|
||||
_profile.node = 0;
|
||||
_profile.nodeId = _profile.rootId;
|
||||
}
|
||||
return new HttpSuccess(_profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 8. หา root OC Id
|
||||
*
|
||||
* @summary 8. หา root OC Id
|
||||
*
|
||||
* @param {string} ocId Id หน่วยงาน
|
||||
*/
|
||||
@Get("root-oc/{ocId}")
|
||||
async GetRootOcId(@Path() ocId: string) {
|
||||
const orgRoot = await this.orgRootRepo.findOne({
|
||||
where: { id: ocId },
|
||||
});
|
||||
if (!orgRoot) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
|
||||
const root = orgRoot? orgRoot.id : "";
|
||||
return new HttpSuccess(root);
|
||||
}
|
||||
|
||||
/**
|
||||
* 5. เอารายชื่อคนที่มีการ ,map keycloak id แล้ว
|
||||
*
|
||||
* @summary 5. เอารายชื่อคนที่มีการ ,map keycloak id แล้ว
|
||||
*
|
||||
*/
|
||||
@Get("keycloak")
|
||||
async GetProfileWithKeycloak() {
|
||||
const profile = await this.profileRepo.find({
|
||||
where: { keycloak: Not(IsNull()) || Not(""), },
|
||||
});
|
||||
return new HttpSuccess(profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 4. API Update รอบการลงเวลา ในตาราง profile
|
||||
*
|
||||
* @summary 4. API Update รอบการลงเวลา ในตาราง profile
|
||||
*
|
||||
*/
|
||||
@Put("update-dutytime")
|
||||
async UpdateDutyTimeAsync(
|
||||
@Request() req: RequestWithUser,
|
||||
@Body() body: {
|
||||
profileId: string;
|
||||
roundId: string;
|
||||
effectiveDate: Date;
|
||||
}
|
||||
) {
|
||||
const profile = await this.profileRepo.findOne({
|
||||
where: { id: body.profileId },
|
||||
});
|
||||
if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
|
||||
Object.assign(profile, body);
|
||||
profile.dutyTimeId = body.roundId;
|
||||
profile.dutyTimeEffectiveDate = body.effectiveDate;
|
||||
profile.lastUpdateUserId = req.user.sub;
|
||||
profile.lastUpdateFullName = req.user.name;
|
||||
await this.profileRepo.save(profile);
|
||||
return new HttpSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -301,92 +301,104 @@ export class ProfileController extends Controller {
|
|||
const _child3 = child3 ? `${child3.orgChild3Name}/` : "";
|
||||
const _child4 = child4 ? `${child4.orgChild4Name}/` : "";
|
||||
|
||||
const profile = {
|
||||
CitizenId: profiles?.citizenId ?? null,
|
||||
Prefix: profiles?.prefix != null ? profiles.prefix : "",
|
||||
FirstName: profiles?.firstName != null ? profiles.firstName : "",
|
||||
LastName: profiles?.lastName != null ? profiles.lastName : "",
|
||||
FullName: `${profiles?.prefix} ${profiles?.firstName} ${profiles?.lastName}`,
|
||||
BirthDay: profiles?.birthDate ? new Date(profiles.birthDate).getDate() : null,
|
||||
BirthDayText:
|
||||
profiles.birthDate != null
|
||||
const Profile = [
|
||||
{
|
||||
CitizenId:
|
||||
profiles.citizenId != null ? Extension.ToThaiNumber(profiles.citizenId.toString()) : "",
|
||||
Prefix: profiles?.prefix != null ? profiles.prefix : "",
|
||||
FirstName: profiles?.firstName != null ? profiles.firstName : "",
|
||||
LastName: profiles?.lastName != null ? profiles.lastName : "",
|
||||
FullName: `${profiles?.prefix} ${profiles?.firstName} ${profiles?.lastName}`,
|
||||
BirthDay: profiles?.birthDate
|
||||
? Extension.ToThaiNumber(new Date(profiles.birthDate).getDate().toString())
|
||||
: null,
|
||||
BirthDayText:
|
||||
profiles.birthDate != null
|
||||
? Extension.ToThaiNumber(Extension.ToThaiShortDate(profiles.birthDate).toString())
|
||||
: "",
|
||||
BirthMonth: profiles?.birthDate
|
||||
? Extension.ToThaiNumber(new Date(profiles.birthDate).getMonth() + (1).toString())
|
||||
: null, // Months are zero-based
|
||||
BirthYear: profiles?.birthDate
|
||||
? Extension.ToThaiNumber(new Date(profiles.birthDate).getFullYear().toString())
|
||||
: null,
|
||||
BirthYearText:
|
||||
profiles.birthDate != null
|
||||
? Extension.ToThaiNumber(Extension.ToThaiShortDate(profiles.birthDate).toString())
|
||||
: "",
|
||||
Address: "",
|
||||
District: "",
|
||||
Area: "",
|
||||
Province: "",
|
||||
Telephone: profiles?.telephoneNumber ?? null,
|
||||
CoupleLastNameOld: profileFamilyCouple?.coupleLastNameOld ?? null,
|
||||
CouplePrefix: profileFamilyCouple?.couplePrefix ?? "",
|
||||
CoupleFullName:
|
||||
profileFamilyCouple?.couplePrefix ||
|
||||
profileFamilyCouple?.coupleFirstName ||
|
||||
profileFamilyCouple?.coupleLastNameOld
|
||||
? `${profileFamilyCouple?.couplePrefix ?? ""} ${profileFamilyCouple?.coupleFirstName ?? ""} ${profileFamilyCouple?.coupleLastNameOld ?? ""}`.trim()
|
||||
: null,
|
||||
FatherPrefix: profileFamilyFather?.fatherPrefix ?? "",
|
||||
FatherFullName:
|
||||
profileFamilyFather?.fatherPrefix ||
|
||||
profileFamilyFather?.fatherFirstName ||
|
||||
profileFamilyFather?.fatherLastName
|
||||
? `${profileFamilyFather?.fatherPrefix ?? ""} ${profileFamilyFather?.fatherFirstName ?? ""} ${profileFamilyFather?.fatherLastName ?? ""}`.trim()
|
||||
: null,
|
||||
MotherPrefix: profileFamilyMother?.motherPrefix ?? "",
|
||||
MotherFullName:
|
||||
profileFamilyMother?.motherPrefix ||
|
||||
profileFamilyMother?.motherFirstName ||
|
||||
profileFamilyMother?.motherLastName
|
||||
? `${profileFamilyMother?.motherPrefix ?? ""} ${profileFamilyMother?.motherFirstName ?? ""} ${profileFamilyMother?.motherLastName ?? ""}`.trim()
|
||||
: null,
|
||||
OcFullPath: `${_child4}${_child3}${_child2}${_child1}${_root}`,
|
||||
Division: "",
|
||||
Institute: "",
|
||||
StartDate: profiles?.dateStart,
|
||||
AppointDate: profiles?.dateAppoint,
|
||||
BirthDate: profiles?.birthDate
|
||||
? Extension.ToThaiNumber(Extension.ToThaiShortDate(profiles.birthDate))
|
||||
: "",
|
||||
BirthMonth: profiles?.birthDate ? new Date(profiles.birthDate).getMonth() + 1 : null, // Months are zero-based
|
||||
BirthYear: profiles?.birthDate ? new Date(profiles.birthDate).getFullYear() : null,
|
||||
BirthYearText:
|
||||
profiles.birthDate != null
|
||||
? Extension.ToThaiNumber(Extension.ToThaiShortDate(profiles.birthDate))
|
||||
: "",
|
||||
Address: "",
|
||||
District: "",
|
||||
Area: "",
|
||||
Province: "",
|
||||
Telephone: profiles?.telephoneNumber ?? null,
|
||||
CoupleLastNameOld: profileFamilyCouple?.coupleLastNameOld ?? null,
|
||||
CouplePrefix:
|
||||
profileFamilyCouple?.couplePrefix != null ? profileFamilyCouple.couplePrefix : "",
|
||||
CoupleFullName:
|
||||
profileFamilyCouple?.couplePrefix ||
|
||||
profileFamilyCouple?.coupleFirstName ||
|
||||
profileFamilyCouple?.coupleLastNameOld
|
||||
? `${profileFamilyCouple?.couplePrefix ?? ""} ${profileFamilyCouple?.coupleFirstName ?? ""} ${profileFamilyCouple?.coupleLastNameOld ?? ""}`.trim()
|
||||
: null,
|
||||
FatherPrefix:
|
||||
profileFamilyFather?.fatherPrefix != null ? profileFamilyFather.fatherPrefix : "",
|
||||
FatherFullName:
|
||||
profileFamilyFather?.fatherPrefix ||
|
||||
profileFamilyFather?.fatherFirstName ||
|
||||
profileFamilyFather?.fatherLastName
|
||||
? `${profileFamilyFather?.fatherPrefix ?? ""} ${profileFamilyFather?.fatherFirstName ?? ""} ${profileFamilyFather?.fatherLastName ?? ""}`.trim()
|
||||
: null,
|
||||
MotherPrefix:
|
||||
profileFamilyMother?.motherPrefix != null ? profileFamilyMother.motherPrefix : "",
|
||||
MotherFullName:
|
||||
profileFamilyMother?.motherPrefix ||
|
||||
profileFamilyMother?.motherFirstName ||
|
||||
profileFamilyMother?.motherLastName
|
||||
? `${profileFamilyMother?.motherPrefix ?? ""} ${profileFamilyMother?.motherFirstName ?? ""} ${profileFamilyMother?.motherLastName ?? ""}`.trim()
|
||||
: null,
|
||||
OcFullPath: `${_child4}${_child3}${_child2}${_child1}${_root}`,
|
||||
Division: "",
|
||||
Institute: "",
|
||||
StartDate: profiles?.dateStart,
|
||||
AppointDate: profiles?.dateAppoint,
|
||||
BirthDate: profiles?.birthDate ? Extension.ToThaiShortDate(profiles.birthDate) : null,
|
||||
RetireDate: profiles?.dateRetireLaw,
|
||||
AvatarId: profiles?.avatar ?? null,
|
||||
};
|
||||
RetireDate:
|
||||
profiles.dateRetireLaw != null
|
||||
? Extension.ToThaiNumber(profiles.dateRetireLaw.toString())
|
||||
: "",
|
||||
// AvatarId: profiles?.avatar ?? null,
|
||||
},
|
||||
];
|
||||
|
||||
const certs = await this.certificateRepository.find({
|
||||
where: { profileId: id },
|
||||
select: ["certificateType", "issuer", "certificateNo", "issueDate"],
|
||||
});
|
||||
const cert = certs.map((item) => ({
|
||||
const Cert = certs.map((item) => ({
|
||||
CertificateType: item.certificateType ?? null,
|
||||
Issuer: item.issuer ?? null,
|
||||
CertificateNo: item.certificateNo ?? null,
|
||||
IssueDate: Extension.ToThaiShortDate(item.issueDate) ?? null,
|
||||
CertificateNo: Extension.ToThaiNumber(item.certificateNo) ?? null,
|
||||
IssueDate: Extension.ToThaiNumber(Extension.ToThaiShortDate(item.issueDate)) ?? null,
|
||||
}));
|
||||
const trainings = await this.trainingRepository.find({
|
||||
select: ["startDate", "endDate", "place", "department"],
|
||||
where: { profileId: id },
|
||||
});
|
||||
const training = trainings.map((item) => ({
|
||||
institute: item.department ?? null,
|
||||
start: Extension.ToThaiShortDate(item.startDate) ?? null,
|
||||
end: Extension.ToThaiShortDate(item.endDate) ?? null,
|
||||
level: "",
|
||||
degree: "",
|
||||
field: item.place ?? null,
|
||||
const Training = trainings.map((item) => ({
|
||||
Institute: item.department ?? null,
|
||||
Start: Extension.ToThaiNumber(Extension.ToThaiShortDate(item.startDate).toString()) ?? null,
|
||||
End: Extension.ToThaiNumber(Extension.ToThaiShortDate(item.endDate).toString()) ?? null,
|
||||
Level: "",
|
||||
Degree: "",
|
||||
Field: item.place ?? null,
|
||||
}));
|
||||
|
||||
const disciplines = await this.disciplineRepository.find({
|
||||
select: ["refCommandDate", "refCommandNo", "detail"],
|
||||
where: { profileId: id },
|
||||
});
|
||||
const discipline = disciplines.map((item) => ({
|
||||
DisciplineYear: new Date(item.refCommandDate).getFullYear() ?? null,
|
||||
const Discipline = disciplines.map((item) => ({
|
||||
DisciplineYear:
|
||||
Extension.ToThaiNumber(new Date(item.refCommandDate).getFullYear().toString()) ?? null,
|
||||
DisciplineDetail: item.detail ?? null,
|
||||
RefNo: item.refCommandNo ?? null,
|
||||
}));
|
||||
|
|
@ -395,10 +407,10 @@ export class ProfileController extends Controller {
|
|||
select: ["startDate", "endDate", "educationLevel", "degree", "field", "institute"],
|
||||
where: { profileId: id },
|
||||
});
|
||||
const education = educations.map((item) => ({
|
||||
const Education = educations.map((item) => ({
|
||||
Institute: item.institute ?? null,
|
||||
Start: new Date(item.startDate).getFullYear() ?? null,
|
||||
End: new Date(item.endDate).getFullYear() ?? null,
|
||||
Start: Extension.ToThaiNumber(new Date(item.startDate).getFullYear().toString()) ?? null,
|
||||
End: Extension.ToThaiNumber(new Date(item.endDate).getFullYear().toString()) ?? null,
|
||||
Level: item.educationLevel ?? null,
|
||||
Degree: item.degree ?? null,
|
||||
Field: item.field ?? null,
|
||||
|
|
@ -416,25 +428,29 @@ export class ProfileController extends Controller {
|
|||
where: { profileId: id },
|
||||
});
|
||||
|
||||
const salary = salarys.map((item) => ({
|
||||
SalaryDate: Extension.ToThaiShortDate(item.date) ?? null,
|
||||
const Salary = salarys.map((item) => ({
|
||||
SalaryDate: Extension.ToThaiNumber(Extension.ToThaiShortDate(item.date)) ?? null,
|
||||
Position: item.position ?? null,
|
||||
PosNo: item.posNo ?? null,
|
||||
Salary: "",
|
||||
Rank: item.positionLevel ?? null,
|
||||
RefAll: item.refCommandNo ?? null,
|
||||
PositionType: item.positionType ?? null,
|
||||
PositionLevel: item.positionLevel ?? null,
|
||||
PositionAmount: item.positionSalaryAmount ?? null,
|
||||
PositionAmount:
|
||||
item.positionSalaryAmount == null
|
||||
? null
|
||||
: Extension.ToThaiNumber(item.positionSalaryAmount.toString()),
|
||||
FullName: `${profiles?.prefix} ${profiles?.firstName} ${profiles?.lastName}`,
|
||||
OcFullPath: `${_child4}${_child3}${_child2}${_child1}${_root}`,
|
||||
}));
|
||||
return new HttpSuccess({
|
||||
profile,
|
||||
cert,
|
||||
training,
|
||||
discipline,
|
||||
education,
|
||||
salary,
|
||||
Profile,
|
||||
Cert,
|
||||
Training,
|
||||
Discipline,
|
||||
Education,
|
||||
Salary,
|
||||
});
|
||||
}
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -314,22 +314,24 @@ export class ProfileEmployeeController extends Controller {
|
|||
const _child3 = child3 ? `${child3.orgChild3Name}/` : "";
|
||||
const _child4 = child4 ? `${child4.orgChild4Name}/` : "";
|
||||
|
||||
const profile = {
|
||||
const Profile = {
|
||||
CitizenId: profiles?.citizenId ?? null,
|
||||
Prefix: profiles?.prefix != null ? profiles.prefix : "",
|
||||
FirstName: profiles?.firstName != null ? profiles.firstName : "",
|
||||
LastName: profiles?.lastName != null ? profiles.lastName : "",
|
||||
FullName: `${profiles?.prefix} ${profiles?.firstName} ${profiles?.lastName}`,
|
||||
BirthDay: profiles?.birthDate ? new Date(profiles.birthDate).getDate() : null,
|
||||
BirthDay: profiles?.birthDate ? new Date(profiles.birthDate).getDate().toString() : null,
|
||||
BirthDayText:
|
||||
profiles.birthDate != null
|
||||
? Extension.ToThaiNumber(Extension.ToThaiShortDate(profiles.birthDate))
|
||||
? Extension.ToThaiNumber(Extension.ToThaiShortDate(profiles.birthDate).toString())
|
||||
: "",
|
||||
BirthMonth: profiles?.birthDate ? new Date(profiles.birthDate).getMonth() + 1 : null, // Months are zero-based
|
||||
BirthYear: profiles?.birthDate ? new Date(profiles.birthDate).getFullYear() : null,
|
||||
BirthMonth: profiles?.birthDate
|
||||
? new Date(profiles.birthDate).getMonth() + (1).toString()
|
||||
: null, // Months are zero-based
|
||||
BirthYear: profiles?.birthDate ? new Date(profiles.birthDate).getFullYear().toString() : null,
|
||||
BirthYearText:
|
||||
profiles.birthDate != null
|
||||
? Extension.ToThaiNumber(Extension.ToThaiShortDate(profiles.birthDate))
|
||||
? Extension.ToThaiNumber(Extension.ToThaiShortDate(profiles.birthDate).toString())
|
||||
: "",
|
||||
Address: "",
|
||||
District: "",
|
||||
|
|
@ -368,14 +370,14 @@ export class ProfileEmployeeController extends Controller {
|
|||
AppointDate: profiles?.dateAppoint,
|
||||
BirthDate: profiles?.birthDate ? Extension.ToThaiShortDate(profiles.birthDate) : null,
|
||||
RetireDate: profiles?.dateRetireLaw,
|
||||
AvatarId: profiles?.avatar ?? null,
|
||||
// AvatarId: profiles?.avatar ?? null,
|
||||
};
|
||||
|
||||
const certs = await this.certificateRepository.find({
|
||||
where: { profileEmployeeId: id },
|
||||
select: ["certificateType", "issuer", "certificateNo", "issueDate"],
|
||||
});
|
||||
const cert = certs.map((item) => ({
|
||||
const Cert = certs.map((item) => ({
|
||||
CertificateType: item.certificateType ?? null,
|
||||
Issuer: item.issuer ?? null,
|
||||
CertificateNo: item.certificateNo ?? null,
|
||||
|
|
@ -385,10 +387,10 @@ export class ProfileEmployeeController extends Controller {
|
|||
select: ["startDate", "endDate", "place", "department"],
|
||||
where: { profileEmployeeId: id },
|
||||
});
|
||||
const training = trainings.map((item) => ({
|
||||
const Training = trainings.map((item) => ({
|
||||
institute: item.department ?? null,
|
||||
start: Extension.ToThaiShortDate(item.startDate) ?? null,
|
||||
end: Extension.ToThaiShortDate(item.endDate) ?? null,
|
||||
start: Extension.ToThaiShortDate(item.startDate).toString() ?? null,
|
||||
end: Extension.ToThaiShortDate(item.endDate).toString() ?? null,
|
||||
level: "",
|
||||
degree: "",
|
||||
field: item.place ?? null,
|
||||
|
|
@ -398,8 +400,8 @@ export class ProfileEmployeeController extends Controller {
|
|||
select: ["refCommandDate", "refCommandNo", "detail"],
|
||||
where: { profileEmployeeId: id },
|
||||
});
|
||||
const discipline = disciplines.map((item) => ({
|
||||
DisciplineYear: new Date(item.refCommandDate).getFullYear() ?? null,
|
||||
const Discipline = disciplines.map((item) => ({
|
||||
DisciplineYear: new Date(item.refCommandDate).getFullYear().toString() ?? null,
|
||||
DisciplineDetail: item.detail ?? null,
|
||||
RefNo: item.refCommandNo ?? null,
|
||||
}));
|
||||
|
|
@ -408,10 +410,10 @@ export class ProfileEmployeeController extends Controller {
|
|||
select: ["startDate", "endDate", "educationLevel", "degree", "field", "institute"],
|
||||
where: { profileEmployeeId: id },
|
||||
});
|
||||
const education = educations.map((item) => ({
|
||||
const Education = educations.map((item) => ({
|
||||
Institute: item.institute ?? null,
|
||||
Start: new Date(item.startDate).getFullYear() ?? null,
|
||||
End: new Date(item.endDate).getFullYear() ?? null,
|
||||
Start: new Date(item.startDate).getFullYear().toString() ?? null,
|
||||
End: new Date(item.endDate).getFullYear().toString() ?? null,
|
||||
Level: item.educationLevel ?? null,
|
||||
Degree: item.degree ?? null,
|
||||
Field: item.field ?? null,
|
||||
|
|
@ -429,11 +431,12 @@ export class ProfileEmployeeController extends Controller {
|
|||
where: { profileEmployeeId: id },
|
||||
});
|
||||
|
||||
const salary = salarys.map((item) => ({
|
||||
const Salary = salarys.map((item) => ({
|
||||
SalaryDate: Extension.ToThaiShortDate(item.date) ?? null,
|
||||
Position: item.position ?? null,
|
||||
PosNo: item.posNo ?? null,
|
||||
Salary: "",
|
||||
Rank: item.positionLevel ?? null,
|
||||
RefAll: item.refCommandNo ?? null,
|
||||
PositionType: item.positionType ?? null,
|
||||
PositionLevel: item.positionLevel ?? null,
|
||||
|
|
@ -441,7 +444,7 @@ export class ProfileEmployeeController extends Controller {
|
|||
FullName: `${profiles?.prefix} ${profiles?.firstName} ${profiles?.lastName}`,
|
||||
OcFullPath: `${_child4}${_child3}${_child2}${_child1}${_root}`,
|
||||
}));
|
||||
return new HttpSuccess({ profile, cert, training, discipline, education, salary });
|
||||
return new HttpSuccess({ Profile, Cert, Training, Discipline, Education, Salary });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
224
src/controllers/UserController.ts
Normal file
224
src/controllers/UserController.ts
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Path,
|
||||
Post,
|
||||
Put,
|
||||
Query,
|
||||
Request,
|
||||
Route,
|
||||
Security,
|
||||
Tags,
|
||||
} from "tsoa";
|
||||
import {
|
||||
addUserGroup,
|
||||
addUserRoles,
|
||||
createGroup,
|
||||
createUser,
|
||||
deleteGroup,
|
||||
deleteUser,
|
||||
editUser,
|
||||
getGroups,
|
||||
getRoles,
|
||||
getUser,
|
||||
getUserGroups,
|
||||
getUserList,
|
||||
removeUserGroup,
|
||||
removeUserRoles,
|
||||
} from "../keycloak";
|
||||
// import * as io from "../lib/websocket";
|
||||
// import elasticsearch from "../elasticsearch";
|
||||
// import { StorageFolder } from "../interfaces/storage-fs";
|
||||
|
||||
// if (!process.env.MINIO_BUCKET) throw Error("Default MinIO bucket must be specified.");
|
||||
// if (!process.env.ELASTICSEARCH_INDEX) throw Error("Default ElasticSearch index must be specified.");
|
||||
|
||||
// const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX;
|
||||
|
||||
function stripLeadingSlash(str: string) {
|
||||
return str.replace(/^\//, "");
|
||||
}
|
||||
|
||||
@Route("keycloak")
|
||||
@Tags("Single-Sign On")
|
||||
@Security("bearerAuth")
|
||||
export class KeycloakController extends Controller {
|
||||
@Get("user/{id}")
|
||||
async getUser(@Path() id: string) {
|
||||
return await getUser(id);
|
||||
}
|
||||
|
||||
@Post("user")
|
||||
@Security("bearerAuth", ["system", "admin"])
|
||||
async createUser(
|
||||
@Request() request: { user: { sub: string; preferred_username: string } },
|
||||
@Body()
|
||||
body: {
|
||||
username: string;
|
||||
password: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
email?: string;
|
||||
},
|
||||
) {
|
||||
const userId = await createUser(body.username, body.password, {
|
||||
firstName: body.firstName,
|
||||
lastName: body.lastName,
|
||||
email: body.email,
|
||||
requiredActions: ["UPDATE_PASSWORD"],
|
||||
});
|
||||
|
||||
if (typeof userId !== "string") {
|
||||
throw new Error("ไม่สามารถติดต่อกับระบบจัดการผู้ใช้งานได้");
|
||||
}
|
||||
|
||||
const now = new Date().toISOString();
|
||||
const folderData: any = {
|
||||
pathname: stripLeadingSlash(`${body.username.trim()}/`),
|
||||
path: "",
|
||||
name: body.username.trim(),
|
||||
hidden: false,
|
||||
permissionGroup: [],
|
||||
permissionUser: [],
|
||||
permissionOther: {
|
||||
create: false,
|
||||
read: false,
|
||||
update: false,
|
||||
delete: false,
|
||||
perm: false,
|
||||
},
|
||||
favourite: false,
|
||||
color: "default",
|
||||
type: "folder",
|
||||
owner: body.username,
|
||||
ownerId: userId,
|
||||
createdAt: now,
|
||||
createdBy: request.user.preferred_username,
|
||||
createdByUserId: request.user.sub,
|
||||
updatedAt: now,
|
||||
updatedBy: request.user.preferred_username,
|
||||
updatedByUserId: request.user.sub,
|
||||
};
|
||||
|
||||
// await elasticsearch.index({
|
||||
// index: DEFAULT_INDEX!,
|
||||
// document: folderData,
|
||||
// refresh: "wait_for",
|
||||
// });
|
||||
|
||||
// io.getInstance()?.emit("FolderCreate", folderData);
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
@Put("user/{userId}")
|
||||
async editUser(
|
||||
@Path() userId: string,
|
||||
@Body()
|
||||
body: {
|
||||
username?: string;
|
||||
password?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
email?: string;
|
||||
},
|
||||
) {
|
||||
return await editUser(userId, body);
|
||||
}
|
||||
|
||||
@Delete("user/{userId}")
|
||||
async deleteUser(@Path() userId: string) {
|
||||
const result = await deleteUser(userId);
|
||||
if (!result) throw new Error("Failed. Cannot delete userId.");
|
||||
}
|
||||
// @Security("bearerAuth", ["system", "admin"])
|
||||
|
||||
|
||||
@Get("role")
|
||||
async getRole() {
|
||||
const role = await getRoles();
|
||||
if (Array.isArray(role))
|
||||
return role.filter(
|
||||
(a) =>
|
||||
!["uma_authorization", "offline_access", "default-roles"].some((b) => a.name.includes(b)),
|
||||
);
|
||||
throw new Error("Failed. Cannot get role.");
|
||||
}
|
||||
|
||||
@Post("{userId}/role")
|
||||
async addRole(@Path() userId: string, @Body() body: { role: string[] }) {
|
||||
const list = await getRoles();
|
||||
|
||||
if (!Array.isArray(list)) throw new Error("Failed. Cannot get role(s) data from the server.");
|
||||
|
||||
const result = await addUserRoles(
|
||||
userId,
|
||||
list.filter((v) => body.role.includes(v.id)),
|
||||
);
|
||||
|
||||
if (!result) throw new Error("Failed. Cannot set user's role.");
|
||||
}
|
||||
|
||||
@Delete("{userId}/role/{roleId}")
|
||||
async deleteRole(@Path() userId: string, @Path() roleId: string) {
|
||||
const list = await getRoles();
|
||||
|
||||
if (!Array.isArray(list)) throw new Error("Failed. Cannot get role(s) data from the server.");
|
||||
|
||||
const result = await removeUserRoles(
|
||||
userId,
|
||||
list.filter((v) => roleId === v.id),
|
||||
);
|
||||
if (!result) throw new Error("Failed. Cannot remove user's role.");
|
||||
}
|
||||
|
||||
@Get("user")
|
||||
async getUserList(@Query() search = "") {
|
||||
const result = await getUserList(search);
|
||||
|
||||
if (Array.isArray(result)) {
|
||||
return result;
|
||||
}
|
||||
throw new Error("Failed. Cannot get user list.");
|
||||
}
|
||||
|
||||
@Get("group")
|
||||
async getGroup() {
|
||||
const group = await getGroups();
|
||||
if (Array.isArray(group)) return group;
|
||||
throw new Error("Failed. Cannot get group.");
|
||||
}
|
||||
|
||||
@Post("group")
|
||||
async createGroup(@Body() body: { name: string }) {
|
||||
const result = await createGroup(body.name);
|
||||
if (!result) throw new Error("Failed. Cannot create group.");
|
||||
}
|
||||
|
||||
@Delete("group/{groupId}")
|
||||
async deleteGroup(@Path() groupId: string) {
|
||||
const result = await deleteGroup(groupId);
|
||||
if (!result) throw new Error("Failed. Cannot delete group.");
|
||||
}
|
||||
|
||||
@Get("user/{userId}/group")
|
||||
async getUserGroup(@Path() userId: string) {
|
||||
const result = await getUserGroups(userId);
|
||||
if (!result) throw new Error("Failed. Cannot list group to user.");
|
||||
return result;
|
||||
}
|
||||
|
||||
@Post("user/{userId}/group/{groupId}")
|
||||
async addUserGroup(@Path() userId: string, @Path() groupId: string) {
|
||||
const result = await addUserGroup(userId, groupId);
|
||||
if (!result) throw new Error("Failed. Cannot assign group to user.");
|
||||
}
|
||||
|
||||
@Delete("user/{userId}/group/{groupId}")
|
||||
async removeUserGroup(@Path() userId: string, @Path() groupId: string) {
|
||||
const result = await removeUserGroup(userId, groupId);
|
||||
if (!result) throw new Error("Failed. Cannot remove group to user.");
|
||||
}
|
||||
}
|
||||
540
src/keycloak/index.ts
Normal file
540
src/keycloak/index.ts
Normal file
|
|
@ -0,0 +1,540 @@
|
|||
import { DecodedJwt, createDecoder } from "fast-jwt";
|
||||
|
||||
const KC_URL = process.env.KC_URL;
|
||||
const KC_REALM = process.env.KC_REALM;
|
||||
const KC_CLIENT_ID = process.env.KC_SERVICE_ACCOUNT_CLIENT_ID;
|
||||
const KC_SECRET = process.env.KC_SERVICE_ACCOUNT_SECRET;
|
||||
|
||||
console.log(process.env.KC_URL);
|
||||
|
||||
let token: string | null = null;
|
||||
let decoded: DecodedJwt | null = null;
|
||||
|
||||
const jwtDecode = createDecoder({ complete: true });
|
||||
|
||||
/**
|
||||
* Check if token is expired or will expire in 30 seconds
|
||||
* @returns true if expire or can't get exp, false otherwise
|
||||
*/
|
||||
export function isTokenExpired(token: string, beforeExpire: number = 30) {
|
||||
decoded = jwtDecode(token);
|
||||
|
||||
if (decoded && decoded.payload.exp) {
|
||||
return Date.now() / 1000 >= decoded.payload.exp - beforeExpire;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get token from keycloak if needed
|
||||
*/
|
||||
export async function getToken() {
|
||||
if (!KC_CLIENT_ID || !KC_SECRET) {
|
||||
throw new Error("KC_CLIENT_ID and KC_SECRET are required to used this feature.");
|
||||
}
|
||||
|
||||
if (token && !isTokenExpired(token)) return token;
|
||||
|
||||
const body = new URLSearchParams();
|
||||
|
||||
body.append("client_id", KC_CLIENT_ID);
|
||||
body.append("client_secret", KC_SECRET);
|
||||
body.append("grant_type", "client_credentials");
|
||||
|
||||
const res = await fetch(`${KC_URL}/realms/${KC_REALM}/protocol/openid-connect/token`, {
|
||||
method: "POST",
|
||||
body: body,
|
||||
}).catch((e) => console.error(e));
|
||||
|
||||
if (!res) {
|
||||
throw new Error("Cannot get token from keycloak.");
|
||||
}
|
||||
|
||||
const data = (await res.json()) as any;
|
||||
|
||||
if (data && data.access_token) {
|
||||
token = data.access_token;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create keycloak user by given username and password with roles
|
||||
*
|
||||
* Client must have permission to manage realm's user
|
||||
*
|
||||
* @returns user uuid or true if success, false otherwise.
|
||||
*/
|
||||
export async function createUser(username: string, password: string, opts?: Record<string, any>) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/users`, {
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
credentials: [{ type: "password", value: password }],
|
||||
username,
|
||||
...opts,
|
||||
}),
|
||||
}).catch((e) => console.log("Keycloak Error: ", e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
const path = res.headers.get("Location");
|
||||
const id = path?.split("/").at(-1);
|
||||
return id || true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get keycloak user by uuid
|
||||
*
|
||||
* Client must have permission to manage realm's user
|
||||
*
|
||||
* @returns user if success, false otherwise.
|
||||
*/
|
||||
export async function getUser(userId: string) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/users/${userId}`, {
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
}).catch((e) => console.log("Keycloak Error: ", e));
|
||||
if (!res) return false;
|
||||
if (!res.ok) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get keycloak user list
|
||||
*
|
||||
* Client must have permission to manage realm's user
|
||||
*
|
||||
* @returns user list if success, false otherwise.
|
||||
*/
|
||||
export async function getUserList(search = "") {
|
||||
const res = await fetch(
|
||||
`${KC_URL}/admin/realms/${KC_REALM}/users`.concat(!!search ? `?search=${search}` : ""),
|
||||
{
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
},
|
||||
).catch((e) => console.log("Keycloak Error: ", e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
return ((await res.json()) as any[]).map((v: Record<string, string>) => ({
|
||||
id: v.id,
|
||||
username: v.username,
|
||||
firstName: v.firstName,
|
||||
lastName: v.lastName,
|
||||
email: v.email,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update keycloak user by uuid
|
||||
*
|
||||
* Client must have permission to manage realm's user
|
||||
*
|
||||
* @returns user uuid or true if success, false otherwise.
|
||||
*/
|
||||
export async function editUser(userId: string, opts: Record<string, any>) {
|
||||
const { password, ...rest } = opts;
|
||||
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/users/${userId}`, {
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
enabled: true,
|
||||
credentials: (password && [{ type: "password", value: opts?.password }]) || undefined,
|
||||
...rest,
|
||||
}),
|
||||
}).catch((e) => console.log("Keycloak Error: ", e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
const path = res.headers.get("Location");
|
||||
const id = path?.split("/").at(-1);
|
||||
return id || true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete keycloak user by uuid
|
||||
*
|
||||
* Client must have permission to manage realm's user
|
||||
*
|
||||
* @returns user true if success, false otherwise.
|
||||
*/
|
||||
export async function deleteUser(userId: string) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/users/${userId}`, {
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
method: "DELETE",
|
||||
}).catch((e) => console.log("Keycloak Error: ", e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get roles list or specific role data
|
||||
*
|
||||
* Client must have permission to get realms roles
|
||||
*
|
||||
* @returns role's info (array if not specify name) if success, null if not found, false otherwise.
|
||||
*/
|
||||
export async function getRoles(name?: string) {
|
||||
const res = await fetch(
|
||||
`${KC_URL}/admin/realms/${KC_REALM}/roles`.concat((name && `/${name}`) || ""),
|
||||
{
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
},
|
||||
},
|
||||
).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok && res.status !== 404) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
if (res.status === 404) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = (await res.json()) as any;
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return data.map((v: Record<string, string>) => ({ id: v.id, name: v.name }));
|
||||
}
|
||||
|
||||
return {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get roles list of user
|
||||
*
|
||||
* Client must have permission to get realms roles
|
||||
*
|
||||
* @returns role's info (array if not specify name) if success, null if not found, false otherwise.
|
||||
*/
|
||||
export async function getUserRoles(userId: string) {
|
||||
const res = await fetch(
|
||||
`${KC_URL}/admin/realms/${KC_REALM}/users/${userId}/role-mappings/realm`,
|
||||
{
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
},
|
||||
},
|
||||
).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok && res.status !== 404) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
if (res.status === 404) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = (await res.json()) as any;
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return data.map((v: Record<string, string>) => ({ id: v.id, name: v.name }));
|
||||
}
|
||||
|
||||
return {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign role to user
|
||||
*
|
||||
* Client must have permission to manage realm's user roles
|
||||
*
|
||||
* @returns true if success, false otherwise.
|
||||
*/
|
||||
export async function addUserRoles(userId: string, roles: { id: string; name: string }[]) {
|
||||
const res = await fetch(
|
||||
`${KC_URL}/admin/realms/${KC_REALM}/users/${userId}/role-mappings/realm`,
|
||||
{
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
method: "POST",
|
||||
body: JSON.stringify(roles),
|
||||
},
|
||||
).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove role from user
|
||||
*
|
||||
* Client must have permission to manage realm's user roles
|
||||
*
|
||||
* @returns true if success, false otherwise.
|
||||
*/
|
||||
export async function removeUserRoles(userId: string, roles: { id: string; name: string }[]) {
|
||||
const res = await fetch(
|
||||
`${KC_URL}/admin/realms/${KC_REALM}/users/${userId}/role-mappings/realm`,
|
||||
{
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
method: "DELETE",
|
||||
body: JSON.stringify(roles),
|
||||
},
|
||||
).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get group list or specific group data
|
||||
*
|
||||
* Client must have permission to manage realms group
|
||||
*
|
||||
* @returns group's info (array if not specify name) if success, null if not found, false otherwise.
|
||||
*/
|
||||
export async function getGroups(id?: string) {
|
||||
const res = await fetch(
|
||||
`${KC_URL}/admin/realms/${KC_REALM}/groups`.concat((id && `/${id}`) || ""),
|
||||
{
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
},
|
||||
},
|
||||
).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok && res.status !== 404) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
if (res.status === 404) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = (await res.json()) as any;
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return data.map((v: Record<string, string>) => ({ id: v.id, name: v.name }));
|
||||
}
|
||||
|
||||
return {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create group
|
||||
*
|
||||
* Client must have permission to manage realms group
|
||||
*
|
||||
* @returns true if success, false otherwise.
|
||||
*/
|
||||
export async function createGroup(name: string) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/groups`, {
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name }),
|
||||
}).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok && res.status !== 404) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit group
|
||||
*
|
||||
* Client must have permission to manage realms group
|
||||
*
|
||||
* @returns true if success, false otherwise.
|
||||
*/
|
||||
export async function editGroup(id: string, name: string) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/groups/${id}`, {
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
"content-type": `application/json`,
|
||||
},
|
||||
method: "PUT",
|
||||
body: JSON.stringify({ name }),
|
||||
}).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok && res.status !== 404) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete group
|
||||
*
|
||||
* Client must have permission to manage realms group
|
||||
*
|
||||
* @returns true if success, false otherwise.
|
||||
*/
|
||||
export async function deleteGroup(id: string) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/groups/${id}`, {
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
},
|
||||
method: "DELETE",
|
||||
}).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok && res.status !== 404) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get group list or specific group data
|
||||
*
|
||||
* Client must have permission to manage realms group
|
||||
*
|
||||
* @returns group's info (array if not specify name) if success, null if not found, false otherwise.
|
||||
*/
|
||||
export async function getUserGroups(userId?: string) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/users/${userId}/groups`, {
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
},
|
||||
}).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok && res.status !== 404) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
if (res.status === 404) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = (await res.json()) as any;
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return data.map((v: Record<string, string>) => ({ id: v.id, name: v.name }));
|
||||
}
|
||||
|
||||
return {
|
||||
id: data.id,
|
||||
name: data.name,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Add group to user
|
||||
*
|
||||
* Client must have permission to manage user group
|
||||
*
|
||||
* @returns true if success, false otherwise.
|
||||
*/
|
||||
export async function addUserGroup(userId: string, groupId: string) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/users/${userId}/groups/${groupId}`, {
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
},
|
||||
method: "PUT",
|
||||
}).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok && res.status !== 404) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete group from user
|
||||
*
|
||||
* Client must have permission to manage user group
|
||||
*
|
||||
* @returns true if success, false otherwise.
|
||||
*/
|
||||
export async function removeUserGroup(userId: string, groupId: string) {
|
||||
const res = await fetch(`${KC_URL}/admin/realms/${KC_REALM}/users/${userId}/groups/${groupId}`, {
|
||||
// prettier-ignore
|
||||
headers: {
|
||||
"authorization": `Bearer ${await getToken()}`,
|
||||
},
|
||||
method: "PUT",
|
||||
}).catch((e) => console.log(e));
|
||||
|
||||
if (!res) return false;
|
||||
if (!res.ok && res.status !== 404) {
|
||||
return Boolean(console.error("Keycloak Error Response: ", await res.json()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue