forked from hibobio/hibob-academy-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Phase 2 - Step 4.2: complete FeedbackResource •Implemented API endpoints for get Status, update Status, get Filtered Feedbacks * fix to--> it's cleaner if you do: if (no permission) return * Response resource (#49) * Phase 2 - Step 4: Implement HR Response API •Added FeedbackResponseResource.kt to handle feedback response submissions. •Integrated role and permission checks to ensure authorized access for response submission. * Phase 2 - Step 4: Implement HR Response API •Added FeedbackResponseResource.kt to handle feedback response submissions. •Integrated role and permission checks to ensure authorized access for response submission. * fix to--> it's cleaner if you do: if (no permission) return * Refactored permission validation in RolePermissionValidator to make it less dependent on specific API endpoints. Moved role and permission checks closer to where they are used in resource classes, enhancing maintainability and adhering to clean code principles. (#51) recognize abortWith doesn't work properly
- Loading branch information
Showing
3 changed files
with
123 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
src/main/kotlin/com/hibob/academy/employee_feedback_feature/resource/ResponseResource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.hibob.academy.employee_feedback_feature.resource | ||
|
||
import com.hibob.academy.employee_feedback_feature.dao.EmployeeRole | ||
import com.hibob.academy.employee_feedback_feature.dao.ResponseSubmission | ||
import com.hibob.academy.employee_feedback_feature.service.ResponseService | ||
import com.hibob.academy.employee_feedback_feature.validation.RolePermissionValidator.Companion.extractClaimAsLong | ||
import com.hibob.academy.employee_feedback_feature.validation.RolePermissionValidator.Companion.validatePermissions | ||
import jakarta.ws.rs.Consumes | ||
import jakarta.ws.rs.POST | ||
import jakarta.ws.rs.Path | ||
import jakarta.ws.rs.container.ContainerRequestContext | ||
import jakarta.ws.rs.core.Context | ||
import jakarta.ws.rs.core.MediaType | ||
import jakarta.ws.rs.core.Response | ||
import org.springframework.stereotype.Controller | ||
|
||
@Controller | ||
@Path("/api/response") | ||
class ResponseResource(private val responseService: ResponseService) { | ||
@Path("/submit") | ||
@POST | ||
@Consumes(MediaType.APPLICATION_JSON) | ||
fun submitResponse(@Context requestContext: ContainerRequestContext, newFeedbackResponse: ResponseSubmission): Response { | ||
val companyId = validatePermissions( | ||
requestContext, setOf(EmployeeRole.HR), | ||
"UNAUTHORIZED: You do not have permission to respond to feedbacks" | ||
) | ||
val employeeId = extractClaimAsLong(requestContext, "employeeId") | ||
|
||
val responseId = responseService.submitResponse(newFeedbackResponse, employeeId, companyId) | ||
|
||
return Response.ok("Response submitted successfully, response id: $responseId").build() | ||
} | ||
} |
46 changes: 24 additions & 22 deletions
46
.../kotlin/com/hibob/academy/employee_feedback_feature/validation/RolePermissionValidator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,49 @@ | ||
package com.hibob.academy.employee_feedback_feature.validation | ||
|
||
import com.hibob.academy.employee_feedback_feature.dao.EmployeeRole | ||
import jakarta.ws.rs.BadRequestException | ||
import jakarta.ws.rs.container.ContainerRequestContext | ||
import jakarta.ws.rs.core.Response | ||
|
||
class RolePermissionValidator { | ||
companion object { | ||
fun extractClaimAsLong(requestContext: ContainerRequestContext, claim: String): Long? { | ||
fun extractClaimAsLong(requestContext: ContainerRequestContext, claim: String): Long { | ||
return (requestContext.getProperty(claim) as? Number)?.toLong() ?: run { | ||
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("UNAUTHORIZED: Missing or invalid $claim").build()) | ||
null | ||
|
||
throw BadRequestException("UNAUTHORIZED: Missing or invalid $claim") | ||
} | ||
} | ||
|
||
fun extractRole(requestContext: ContainerRequestContext): EmployeeRole? { | ||
private fun extractRole(requestContext: ContainerRequestContext): EmployeeRole { | ||
return (requestContext.getProperty("role") as? String)?.uppercase()?.let { | ||
try { | ||
EmployeeRole.valueOf(it) | ||
} catch (e: IllegalArgumentException) { | ||
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).entity("UNAUTHORIZED: Invalid role").build()) | ||
null | ||
|
||
throw BadRequestException("UNAUTHORIZED: Invalid role") | ||
} | ||
} ?: run { | ||
requestContext.abortWith( | ||
Response.status(Response.Status.UNAUTHORIZED).entity("UNAUTHORIZED: Missing role").build() | ||
) | ||
null | ||
|
||
throw BadRequestException("UNAUTHORIZED: Missing role") | ||
} | ||
} | ||
enum class Permissions { | ||
VIEW_ALL_FEEDBACKS, | ||
CHANGE_FEEDBACK_STATUS, | ||
RESPONSE_TO_FEEDBACK | ||
} | ||
|
||
fun validatePermissions( | ||
requestContext: ContainerRequestContext, | ||
requiredRoles: Set<EmployeeRole>, | ||
errorMessage: String | ||
): Long { | ||
val companyId = extractClaimAsLong(requestContext, "companyId") | ||
val role = extractRole(requestContext) | ||
|
||
private val rolePermissions = mapOf( | ||
EmployeeRole.HR to setOf(Permissions.VIEW_ALL_FEEDBACKS, Permissions.CHANGE_FEEDBACK_STATUS, Permissions.RESPONSE_TO_FEEDBACK), | ||
EmployeeRole.ADMIN to setOf(Permissions.VIEW_ALL_FEEDBACKS), | ||
) | ||
if (!hasPermission(role, requiredRoles)) { | ||
throw BadRequestException(errorMessage) | ||
} | ||
|
||
return companyId | ||
} | ||
|
||
fun hasPermission(role: EmployeeRole, permission: Permissions): Boolean { | ||
return rolePermissions[role]?.contains(permission) ?: false | ||
private fun hasPermission(role: EmployeeRole, requiredRoles: Set<EmployeeRole>): Boolean { | ||
return requiredRoles.contains(role) | ||
} | ||
} | ||
} |