Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.hackerrank.corebanking.controller;

import com.hackerrank.corebanking.dto.GroupMembershipDto;
import com.hackerrank.corebanking.dto.GroupRoleAssignmentDto;
import com.hackerrank.corebanking.dto.UserGroupDto;
import com.hackerrank.corebanking.service.UserGroupService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Set;

@RestController
@RequestMapping("/api/core-banking/groups")
@CrossOrigin(originPatterns = "*", maxAge = 3600, allowCredentials = "false")
public class UserGroupController {

private final UserGroupService userGroupService;

@Autowired
public UserGroupController(UserGroupService userGroupService) {
this.userGroupService = userGroupService;
}

@PostMapping
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<UserGroupDto> createGroup(@Valid @RequestBody UserGroupDto groupDto) {
UserGroupDto createdGroup = userGroupService.createGroup(groupDto);
return ResponseEntity.status(HttpStatus.CREATED).body(createdGroup);
}


@GetMapping
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Page<UserGroupDto>> getAllGroups(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size,
@RequestParam(defaultValue = "name") String sortBy,
@RequestParam(defaultValue = "asc") String sortDir) {

Sort sort = sortDir.equalsIgnoreCase("desc") ?
Sort.by(sortBy).descending() :
Sort.by(sortBy).ascending();

Pageable pageable = PageRequest.of(page, size, sort);
Page<UserGroupDto> groups = userGroupService.getAllGroups(pageable);

return ResponseEntity.ok(groups);
}

@GetMapping("/{groupId}")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<UserGroupDto> getGroupById(@PathVariable Long groupId) {
UserGroupDto group = userGroupService.getGroupById(groupId);
return ResponseEntity.ok(group);
}

@PutMapping("/{groupId}")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<UserGroupDto> updateGroup(
@PathVariable Long groupId,
@Valid @RequestBody UserGroupDto groupDto) {
UserGroupDto updatedGroup = userGroupService.updateGroup(groupId, groupDto);
return ResponseEntity.ok(updatedGroup);
}

@DeleteMapping("/{groupId}")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Void> deleteGroup(@PathVariable Long groupId) {
userGroupService.deleteGroup(groupId);
return ResponseEntity.noContent().build();
}

@PostMapping("/members")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Void> addUsersToGroup(@Valid @RequestBody GroupMembershipDto membershipDto) {
userGroupService.addUsersToGroup(membershipDto);
return ResponseEntity.ok().build();
}

@DeleteMapping("/members")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Void> removeUsersFromGroup(@Valid @RequestBody GroupMembershipDto membershipDto) {
userGroupService.removeUsersFromGroup(membershipDto);
return ResponseEntity.ok().build();
}

@PostMapping("/roles")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Void> assignRolesToGroup(@Valid @RequestBody GroupRoleAssignmentDto roleAssignmentDto) {
userGroupService.assignRolesToGroup(roleAssignmentDto);
return ResponseEntity.ok().build();
}

@DeleteMapping("/roles")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Void> removeRolesFromGroup(@Valid @RequestBody GroupRoleAssignmentDto roleAssignmentDto) {
userGroupService.removeRolesFromGroup(roleAssignmentDto);
return ResponseEntity.ok().build();
}

@GetMapping("/user/{userId}")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<List<UserGroupDto>> getGroupsForUser(@PathVariable Long userId) {
List<UserGroupDto> groups = userGroupService.getGroupsForUser(userId);
return ResponseEntity.ok(groups);
}

@GetMapping("/user/{userId}/permissions")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Set<String>> getAllPermissionsForUser(@PathVariable Long userId) {
Set<String> permissions = userGroupService.getAllPermissionsForUser(userId);
return ResponseEntity.ok(permissions);
}

@GetMapping("/user/{userId}/permissions/{permission}")
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<Boolean> hasPermission(
@PathVariable Long userId,
@PathVariable String permission) {
boolean hasPermission = userGroupService.hasPermission(userId, permission);
return ResponseEntity.ok(hasPermission);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.hackerrank.corebanking.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.time.LocalDateTime;

@JsonIgnoreProperties(ignoreUnknown = true)
public class ErrorResponseDto {

private int status;
private String error;
private String message;
private String path;
private LocalDateTime timestamp;

public ErrorResponseDto() {}

public ErrorResponseDto(int status, String error, String message, String path, LocalDateTime timestamp) {
this.status = status;
this.error = error;
this.message = message;
this.path = path;
this.timestamp = timestamp;
}

public int getStatus() { return status; }
public void setStatus(int status) { this.status = status; }

public String getError() { return error; }
public void setError(String error) { this.error = error; }

public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }

public String getPath() { return path; }
public void setPath(String path) { this.path = path; }

public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }

public static ErrorResponseDto of(int status, String error, String message, String path) {
ErrorResponseDto response = new ErrorResponseDto();
response.setStatus(status);
response.setError(error);
response.setMessage(message);
response.setPath(path);
response.setTimestamp(LocalDateTime.now());
return response;
}

public static ErrorResponseDto badRequest(String message, String path) {
return of(400, "Bad Request", message, path);
}

public static ErrorResponseDto forbidden(String message, String path) {
return of(403, "Forbidden", message, path);
}

public static ErrorResponseDto notFound(String message, String path) {
return of(404, "Not Found", message, path);
}

public static ErrorResponseDto conflict(String message, String path) {
return of(409, "Conflict", message, path);
}

public static ErrorResponseDto internalServerError(String message, String path) {
return of(500, "Internal Server Error", message, path);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.hackerrank.corebanking.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;

import jakarta.validation.constraints.NotNull;
import java.util.Set;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Builder
@ToString
@JsonIgnoreProperties(ignoreUnknown = true)
public class GroupMembershipDto {

@NotNull(message = "Group ID is required")
private Long groupId;

@NotNull(message = "User IDs are required")
private Set<Long> userIds;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.hackerrank.corebanking.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;

import jakarta.validation.constraints.NotNull;
import java.util.Set;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Builder
@ToString
@JsonIgnoreProperties(ignoreUnknown = true)
public class GroupRoleAssignmentDto {

@NotNull(message = "Group ID is required")
private Long groupId;

@NotNull(message = "Role IDs are required")
private Set<Long> roleIds;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.hackerrank.corebanking.dto;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.util.Date;
import java.util.Set;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Builder
@ToString
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserGroupDto {

private Long id;

@NotBlank(message = "Group name is required")
@Size(min = 2, max = 100, message = "Group name must be between 2 and 100 characters")
private String name;

@Size(max = 500, message = "Description cannot exceed 500 characters")
private String description;

private String groupType;

private Date createdAt;

private Date updatedAt;

private boolean deleted;

private Date deletedAt;

private Set<Long> memberIds;

private Set<Long> roleIds;

private Integer memberCount;

private Integer roleCount;
}
Loading