From 941a72a7c6fe41d7b7b4c83f603d1279a567c5ba Mon Sep 17 00:00:00 2001 From: "vluk@2fi-solutions.com.hk" Date: Wed, 14 Jan 2026 16:06:39 +0800 Subject: [PATCH] added import of user auth --- .../common/internalSetup/usersSetup.kt | 147 ++++++++++++------ .../modules/user/entity/UserRepository.java | 40 +++++ 2 files changed, 138 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/ffii/fpsms/modules/common/internalSetup/usersSetup.kt b/src/main/java/com/ffii/fpsms/modules/common/internalSetup/usersSetup.kt index b7d1c2c..436c0e2 100644 --- a/src/main/java/com/ffii/fpsms/modules/common/internalSetup/usersSetup.kt +++ b/src/main/java/com/ffii/fpsms/modules/common/internalSetup/usersSetup.kt @@ -7,16 +7,14 @@ import org.apache.poi.ss.usermodel.Sheet import org.apache.poi.ss.usermodel.Workbook import org.apache.poi.xssf.usermodel.XSSFWorkbook import org.springframework.stereotype.Component -import java.io.File -import java.io.FileInputStream -import java.io.IOException -import com.ffii.fpsms.modules.user.entity.User -import com.ffii.fpsms.modules.user.entity.UserRepository import org.springframework.beans.factory.annotation.Autowired import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.transaction.annotation.Transactional - - +import com.ffii.fpsms.modules.user.entity.User +import com.ffii.fpsms.modules.user.entity.UserRepository +import java.io.File +import java.io.FileInputStream +import java.io.IOException @Component open class UsersSetup { @@ -30,13 +28,13 @@ open class UsersSetup { data class UserData( val staffNo: String, val name: String, - val title: String + val title: String, + val authorityCodes: Set ) @Transactional(rollbackFor = [Exception::class]) open fun importExcelFromLocal(filePath: String): Int { val file = File(filePath) - if (!file.exists()) { throw IOException("File not found: $filePath") } @@ -48,62 +46,113 @@ open class UsersSetup { val sheet: Sheet = workbook.getSheetAt(0) val userDataList = mutableListOf() - for (rowIndex in 1..sheet.lastRowNum) { - val row: Row? = sheet.getRow(rowIndex) - if (row != null) { - val staffNoCell: Cell? = row.getCell(1) // Column B - val nameCell: Cell? = row.getCell(2) // Column C - val titleCell: Cell? = row.getCell(3) // Column D - - val staffNo = if (staffNoCell != null) { - ExcelUtils.getStringValue(staffNoCell).trim() - } else { - "" + // ──────────────────────────────────────────────── + // Read header row (index 1) → map column index to authority code + // ──────────────────────────────────────────────── + val headerRow = sheet.getRow(1) ?: throw IllegalStateException("Header row (index 1) not found") + val columnToAuthority = mutableMapOf() + + for (col in 6..30) { // adjust upper limit if more columns exist + val cell = headerRow.getCell(col) + if (cell != null) { + val headerValue = ExcelUtils.getStringValue(cell).trim() + if (headerValue.isNotEmpty()) { + val authCode = headerValue.uppercase() // normalize to uppercase + columnToAuthority[col] = authCode } + } + } - val name = if (nameCell != null) { - ExcelUtils.getStringValue(nameCell).trim() - } else { - "" - } + println("Detected ${columnToAuthority.size} authority columns from header row:") + columnToAuthority.forEach { (col, code) -> + println(" Column $col → Authority code: '$code'") + } + println("") - val title = if (titleCell != null) { - ExcelUtils.getStringValue(titleCell).trim() + // ──────────────────────────────────────────────── + // Process data rows (starting from row index 2) + // ──────────────────────────────────────────────── + for (rowIndex in 2..sheet.lastRowNum) { + val row = sheet.getRow(rowIndex) ?: continue + + val staffNo = ExcelUtils.getStringValue(row.getCell(1)).trim() + if (staffNo.isEmpty()) continue + + val name = ExcelUtils.getStringValue(row.getCell(2)).trim() + val title = ExcelUtils.getStringValue(row.getCell(3)).trim() + + val authorityCodes = mutableSetOf() + + println("=== Processing row ${rowIndex + 1} (staffNo: $staffNo, name: $name) ===") + + // Header-based columns + columnToAuthority.forEach { (colIndex, authCode) -> + val cell = row.getCell(colIndex) + val rawValue = if (cell == null) "" else ExcelUtils.getStringValue(cell) + val value = rawValue.trim() + + println(" Col $colIndex | Raw: '${rawValue.take(40).replace("\n", "\\n")}' | Trimmed: '$value' | Len: ${value.length}") + + val isNotBlank = value.isNotBlank() + println(" → non-blank? $isNotBlank") + + if (isNotBlank) { + println(" → ADDING: $authCode") + authorityCodes.add(authCode) } else { - "" + println(" → skipped (empty/blank)") } + } - if (staffNo.isNotEmpty()) { - userDataList.add(UserData(staffNo, name, title)) - } + println(" Final collected authorities: ${authorityCodes.joinToString(", ") { "'$it'" }}") + println("=== End of row ${rowIndex + 1} ===\n") + + if (authorityCodes.isNotEmpty() || name.isNotEmpty() || title.isNotEmpty()) { + userDataList.add(UserData(staffNo, name, title, authorityCodes)) } } - // Create users in database + // ──────────────────────────────────────────────── + // Create users + assign authorities + // ──────────────────────────────────────────────── var createdCount = 0 - for (userData in userDataList) { - // Check if username (staffNo) already exists - val existingUser = userRepository.findByUsernameAndDeletedFalse(userData.staffNo) - - if (existingUser.isEmpty) { - val user = User() - user.username = userData.staffNo - user.password = passwordEncoder.encode("Pings2026!") - user.locked = false - user.name = userData.name - user.title = userData.title - user.lotusNotesUser = false - user.staffNo = userData.staffNo - - userRepository.save(user) - createdCount++ + + for (data in userDataList) { + val existing = userRepository.findByUsernameAndDeletedFalse(data.staffNo) + if (existing.isPresent) { + println("SKIP - User already exists: ${data.staffNo}") + continue + } + + val user = User().apply { + username = data.staffNo + password = passwordEncoder.encode("Pings2026!") + locked = false + this.name = data.name + this.title = data.title + lotusNotesUser = false + staffNo = data.staffNo + } + + val savedUser = userRepository.save(user) + createdCount++ + + println("CREATED user: ${data.staffNo} → ID = ${savedUser.id}") + + data.authorityCodes.forEach { code -> + println(" → Assigning authority: '$code'") + userRepository.assignAuthorityByCodeIfNotExists(savedUser.id!!, code) } + + println("") } + println("Import finished. Created $createdCount new users.") return createdCount + } finally { workbook.close() } } } -} +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/user/entity/UserRepository.java b/src/main/java/com/ffii/fpsms/modules/user/entity/UserRepository.java index 3b2d573..51d7b02 100644 --- a/src/main/java/com/ffii/fpsms/modules/user/entity/UserRepository.java +++ b/src/main/java/com/ffii/fpsms/modules/user/entity/UserRepository.java @@ -3,6 +3,8 @@ package com.ffii.fpsms.modules.user.entity; import java.util.List; import java.util.Optional; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import com.ffii.core.support.AbstractRepository; @@ -17,4 +19,42 @@ public interface UserRepository extends AbstractRepository { List findUserComboByTitleNotNullAndDepartmentNotNullAndNameNotNullAndDeletedFalse(); Optional findByStaffNo(@Param("staffNo") String staffNo); + + @Modifying + @Query(value = """ + INSERT INTO user_authority (userID, authId) + SELECT :userId, a.id + FROM authority a + WHERE a.authority = :code + AND NOT EXISTS ( + SELECT 1 + FROM user_authority ua + WHERE ua.userID = :userId + AND ua.authId = a.id + ) + LIMIT 1 + """, nativeQuery = true) + void assignAuthorityByCodeIfNotExists( + @Param("userId") Long userId, + @Param("code") String code + ); + + // Optional: batch version (if you want to assign many at once) + @Modifying + @Query(value = """ + INSERT INTO user_authority (userID, authId) + SELECT :userId, a.id + FROM authority a + WHERE a.authority IN :codes + AND NOT EXISTS ( + SELECT 1 + FROM user_authority ua + WHERE ua.userID = :userId + AND ua.authId = a.id + ) + """, nativeQuery = true) + void assignAuthoritiesByCodesIfNotExists( + @Param("userId") Long userId, + @Param("codes") List codes + ); }