Skip to content

Commit

Permalink
Refactoring the logic related to the button to update active user pro…
Browse files Browse the repository at this point in the history
…files in ootb

Implement loadAvailableProfiles in general.controller.js and getAvailableOotbActiveProfiles in groupingsService to call api in ui and store the available data in .availableProfiles

Add ootb.active.user.profiles.json that contains multiple profiles information

Apply ng-repeat with the values from scope.availableProfiles that contains the profiles from api call

Add isOotb() function to check current spring boot active profile and apply to the menubar.html

Add tests for loadAvailableProfiles and getAvailableOotbActiveProfiles in general.controller.test.js and groupings.service.test.js

Enhance the Builder class functions in the User class (access folder)

Refactor the file inputstream function in OotbActiveUserProfileService

Implement getAvailableProfiles function test in the controller test, add @Mockbean OotbActiveUserProfileService and mock the map that contains the ootb active profiles

Complete adding multiple ootb active profiles into the users map dynamically from json file with null safe and wrong path of file error

Fix cadacy code style

Fix general controller test to check gs.getAvailableOotbActiveProfiles
  • Loading branch information
gitCarrot committed Jun 19, 2024
1 parent 188bfd4 commit ecc2581
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package edu.hawaii.its.api.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -13,12 +14,10 @@
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

Expand All @@ -27,7 +26,6 @@
import edu.hawaii.its.groupings.access.UserContextService;
import edu.hawaii.its.groupings.configuration.OotbStaticUserAuthenticationFilter;
import edu.hawaii.its.groupings.service.OotbActiveUserProfileService;
import edu.hawaii.its.groupings.util.JsonUtil;

@RestController
@RequestMapping("/api/groupings/ootb")
Expand Down Expand Up @@ -60,6 +58,11 @@ public OotbRestController() {
* the overrides file. Gets the active profiles and only runs the tests the
* active profile relies on the API.
*/
@GetMapping("/availableProfiles")
public ResponseEntity<List<String>> getAvailableProfiles() {
List<String> profiles = new ArrayList<>(ootbActiveUserProfileService.getUsers().keySet());
return ResponseEntity.ok(profiles);
}

@PostMapping(value = "/{activeProfile}")
public ResponseEntity<String> updateActiveDefaultUser(@PathVariable String activeProfile) {
Expand Down
23 changes: 19 additions & 4 deletions src/main/java/edu/hawaii/its/groupings/access/User.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package edu.hawaii.its.groupings.access;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
Expand All @@ -13,6 +16,10 @@ public class User extends org.springframework.security.core.userdetails.User {
private String uhUuid;
private UhAttributes attributes;

public User(){
super("", "", null);
}

public User(String uid, String uhUuid, Collection<GrantedAuthority> authorities) {
super(uid, "", authorities);
setUhUuid(uhUuid);
Expand All @@ -22,7 +29,7 @@ public User(String uid, Collection<GrantedAuthority> authorities) {
super(uid, "", authorities);
}

private User(Builder builder) {
public User(Builder builder) {
super(builder.uid, "", builder.authorities);
this.uhUuid = builder.uhUuid;
this.attributes = new UhAttributes(builder.attributes);
Expand Down Expand Up @@ -74,7 +81,7 @@ public String toString() {
public static class Builder {
private final String uid;
private String uhUuid;
private Collection<GrantedAuthority> authorities;
private final Collection<GrantedAuthority> authorities = new ArrayList<>();
private final Map<String, Object> attributes = new HashMap<>();

public Builder(String uid) {
Expand All @@ -86,8 +93,16 @@ public Builder uhUuid(String uhUuid) {
return this;
}

public Builder authorities(Collection<GrantedAuthority> authorities) {
this.authorities = authorities;
public Builder addAuthorities(String authority) {
this.authorities.add(new SimpleGrantedAuthority(authority));
return this;
}

public Builder addAuthorities(List<String> authorities) {
List<GrantedAuthority> grantedAuthorities = authorities.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
this.authorities.addAll(grantedAuthorities);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,6 @@ public boolean isDefault() {
return isProfileActive("default");
}

public boolean isOotb() { return isProfileActive("ootb"); }

}
Original file line number Diff line number Diff line change
@@ -1,51 +1,64 @@
package edu.hawaii.its.groupings.service;

import java.util.HashMap;
import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.security.core.authority.AuthorityUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import edu.hawaii.its.groupings.access.User;

@Service
public class OotbActiveUserProfileService implements UserDetailsService {
private final Map<String, User> users = new HashMap<>();
private static final Log logger = LogFactory.getLog(OotbActiveUserProfileService.class);
private final Map<String, User> users = new LinkedHashMap<>();

public OotbActiveUserProfileService() {
initUsers();
}

private void initUsers() {
// Initialize member with uid "member0123"
users.put("MEMBER", new User.Builder("member0123") // UID is clearly the first parameter in the constructor
.uhUuid("11111111")
.authorities(AuthorityUtils.createAuthorityList("ROLE_UH", "ROLE_OOTB"))
.addAttribute("cn", "MEMBER")
.addAttribute("mail", "[email protected]")
.addAttribute("givenName", "DefaultMember")
.build());

// Initialize owner with uid "owner0123"
users.put("OWNER", new User.Builder("owner0123")
.uhUuid("22222222")
.authorities(AuthorityUtils.createAuthorityList("ROLE_UH", "ROLE_OWNER", "ROLE_OOTB"))
.addAttribute("cn", "OWNER")
.addAttribute("mail", "[email protected]")
.addAttribute("givenName", "OwnerUser")
.build());

// Initialize admin with uid "admin0123"
users.put("ADMIN", new User.Builder("admin0123")
.uhUuid("33333333")
.authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN", "ROLE_UH", "ROLE_OWNER", "ROLE_OOTB"))
.addAttribute("cn", "ADMIN")
.addAttribute("mail", "[email protected]")
.addAttribute("givenName", "AdminUser")
.build());
try {
mapFromJsonFile("ootb.active.user.profiles.json").forEach((key, userData) -> {
users.put(key, createUserFromMap(userData));
});
} catch (IOException e) {
logger.error("Error while initiating active user profiles from a json file: ", e);
}
}

private Map<String, Map<String, Object>> mapFromJsonFile(String filepath) throws IOException {
File file = new ClassPathResource(filepath).getFile();
ObjectMapper objectMapper = new ObjectMapper();

// Map<ootb active profile type, Map<profile property, property's value>>
return objectMapper.readValue(file, new TypeReference<>() {});
}

private User createUserFromMap(Map<String, Object> userData) {
String uid = (String) userData.get("uid");
String uhUuid = (String) userData.get("uhUuid");
List<String> roles = (List<String>) userData.get("authorities");
Map<String, String> attributes = (Map<String, String>) userData.get("attributes");

User.Builder builder = new User.Builder(uid)
.uhUuid(uhUuid)
.addAuthorities(roles);

attributes.forEach(builder::addAttribute);

return builder.build();
}

@Override
Expand Down
32 changes: 32 additions & 0 deletions src/main/resources/ootb.active.user.profiles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"MEMBER": {
"uid": "member0123",
"uhUuid": "11111111",
"authorities": ["ROLE_UH"],
"attributes": {
"cn": "MEMBER",
"mail": "[email protected]",
"givenName": "DefaultMember"
}
},
"OWNER": {
"uid": "owner0123",
"uhUuid": "22222222",
"authorities": ["ROLE_UH", "ROLE_OWNER"],
"attributes": {
"cn": "OWNER",
"mail": "[email protected]",
"givenName": "OwnerUser"
}
},
"ADMIN": {
"uid": "admin0123",
"uhUuid": "33333333",
"authorities": ["ROLE_ADMIN", "ROLE_UH", "ROLE_OWNER"],
"attributes": {
"cn": "ADMIN",
"mail": "[email protected]",
"givenName": "AdminUser"
}
}
}
15 changes: 15 additions & 0 deletions src/main/resources/static/javascript/mainApp/general.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
$scope.showGroupingPathColumn = JSON.parse(localStorage.getItem("showPathColumn") ?? false);

$scope.ootbActiveUser = "";
$scope.availableProfiles = [];

angular.extend(this, $controller("TableJsController", { $scope }));

Expand Down Expand Up @@ -268,6 +269,20 @@
$("[data-content='copy']").popover();
};

/**
* Get available ootb active profiles that defined in ootb.active.user.profiles.json
*/
$scope.loadAvailableProfiles = () => {
groupingsService.getAvailableOotbActiveProfiles(
(data) => {
$scope.availableProfiles = data;
},
(res) => {
$scope.resStatus = res.status;
}
);
};

/**
* Updates the active user profile, clears cache by reloading the page with a cache-busting URL.
* @param profile - the type of profile to switch to ('MEMBER', 'OWNER', 'ADMIN')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@
dataProvider.loadData(endpoint, onSuccess, onError);
},

/**
* Get a list of available ootb active profiles.
*/
getAvailableOotbActiveProfiles(onSuccess, onError) {
let endpoint = BASE_URL + "ootb/availableProfiles";
dataProvider.loadData(endpoint, onSuccess, onError);
},

/**
* Update data harness bean with OotbActiveProfile
* @param profile {String}
Expand Down
9 changes: 4 additions & 5 deletions src/main/resources/templates/menubar.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<a class="btn btn-primary btn-v-align login" th:href="@{/login}">Login
<i class="fas fa-sign-in-alt" aria-hidden="false"></i></a>
</li>
<li class="nav-item" sec:authorize="isAuthenticated() and !hasAuthority('ROLE_OOTB')">
<li class="nav-item" sec:authorize="isAuthenticated()" th:if="${[email protected]()}">
<form action="/logout" th:action="@{/logout}" method="post">
<div class="dropdown-divider d-block d-lg-none pb-3"></div>
<button class="btn btn-outline-secondary btn-v-align text-nowrap" type="submit">Logout (<span
Expand All @@ -59,15 +59,14 @@
</button>
</form>
</li>
<li class="nav-item dropdown" sec:authorize="isAuthenticated() and hasAuthority('ROLE_OOTB')">
<li class="nav-item dropdown" sec:authorize="isAuthenticated()" th:if="${@realm.isOotb()}" ng-click="loadAvailableProfiles()">
<a class="btn btn-outline-secondary btn-v-align text-nowrap dropdown-toggle" href="#" id="navbarDropdownMenuLink2" role="button"
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Logout (<span sec:authentication="name" id="name"></span>)
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<a class="dropdown-item" href="login" ng-click="updateActiveUserProfile('MEMBER')">Member</a>
<a class="dropdown-item" href="login" ng-click="updateActiveUserProfile('OWNER')">Owner</a>
<a class="dropdown-item" href="login" ng-click="updateActiveUserProfile('ADMIN')">Admin</a>
<a class="dropdown-item" href="login" ng-repeat="profile in availableProfiles"
ng-click="updateActiveUserProfile(profile)">{{profile}}</a>
</div>
</li>
</ul>
Expand Down
Loading

0 comments on commit ecc2581

Please sign in to comment.