Skip to content

Commit

Permalink
Bugfixes in tests for new Manage API
Browse files Browse the repository at this point in the history
  • Loading branch information
oharsta committed Sep 22, 2023
1 parent e264ca9 commit 8ad39c7
Show file tree
Hide file tree
Showing 17 changed files with 85 additions and 87 deletions.
8 changes: 5 additions & 3 deletions client/src/components/EmailField.scss
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,14 @@ div.email-field {
&.icon {
padding: 8px 14px;
cursor: pointer;
font-size: 14px;
color: var(--sds--color--gray--400);
position: absolute;
right: -8px;
top: -2px;

top: -8px;
svg {
width: 10px;
height: auto;
}
&:hover {
color: var(--sds--color--red--400);
}
Expand Down
14 changes: 14 additions & 0 deletions client/src/icons/network-information.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions client/src/icons/persons.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion client/src/pages/Profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export const Profile = () => {
if (id) {
other(id)
.then(res => {
debugger;
setUser(res);
setLoading(false);
useAppStore.setState({
Expand Down
2 changes: 2 additions & 0 deletions client/src/pages/Role.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {useNavigate, useParams} from "react-router-dom";
import {useAppStore} from "../stores/AppStore";
import {UnitHeader} from "../components/UnitHeader";
import {ReactComponent as UserLogo} from "@surfnet/sds/icons/functional-icons/id-2.svg";
import {ReactComponent as WebsiteIcon} from "../icons/network-information.svg";
import {ReactComponent as PersonIcon} from "../icons/persons.svg";
import {ReactComponent as GuestLogo} from "@surfnet/sds/icons/illustrative-icons/hr.svg";
import {ReactComponent as InvitationLogo} from "@surfnet/sds/icons/functional-icons/id-1.svg";
import {allowedToEditRole, AUTHORITIES, isUserAllowed, urnFromRole} from "../utils/UserRole";
Expand Down
9 changes: 3 additions & 6 deletions server/src/main/java/access/api/InvitationController.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,10 @@ public ResponseEntity<Map<String, Integer>> resendInvitation(@PathVariable("id")
}

@GetMapping("public")
public ResponseEntity<MetaInvitation> getInvitation(@RequestParam("hash") String hash) {
public ResponseEntity<Invitation> getInvitation(@RequestParam("hash") String hash) {
Invitation invitation = invitationRepository.findByHash(hash).orElseThrow(NotFoundException::new);
List<Map<String, Object>> providers = invitation.getRoles().stream()
.map(InvitationRole::getRole)
.map(role -> manage.providerById(role.getManageType(), role.getManageId()))
.toList();
return ResponseEntity.ok(new MetaInvitation(invitation, providers));
manage.deriveRemoteApplications(invitation.getRoles().stream().map(invitationRole -> invitationRole.getRole()).toList());
return ResponseEntity.ok(invitation);
}

@GetMapping("all")
Expand Down
2 changes: 1 addition & 1 deletion server/src/main/java/access/api/UserController.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public ResponseEntity<User> details(@PathVariable("id") Long id, @Parameter(hidd
UserPermissions.assertSuperUser(user);
User other = userRepository.findById(id).orElseThrow(NotFoundException::new);

List<Role> roles = user.getUserRoles().stream().map(UserRole::getRole).toList();
List<Role> roles = other.getUserRoles().stream().map(UserRole::getRole).toList();
manage.deriveRemoteApplications(roles);
return ResponseEntity.ok(other);
}
Expand Down
7 changes: 0 additions & 7 deletions server/src/main/java/access/model/MetaInvitation.java

This file was deleted.

15 changes: 8 additions & 7 deletions server/src/test/java/access/api/InvitationControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,21 @@ class InvitationControllerTest extends AbstractTest {

@Test
void getInvitation() throws JsonProcessingException {
stubForManageProviderById(EntityType.OIDC10_RP, "5");
super.stubForManageProviderByEntityID(EntityType.OIDC10_RP, "https://calendar");

MetaInvitation metaInvitation = given()
Invitation invitation = given()
.when()
.accept(ContentType.JSON)
.contentType(ContentType.JSON)
.queryParam("hash", Authority.GUEST.name())
.get("/api/v1/invitations/public")
.as(MetaInvitation.class);
.as(Invitation.class);

assertEquals("Mail", metaInvitation.invitation().getRoles().iterator().next().getRole().getName());
assertEquals(1, metaInvitation.providers().size());
assertEquals("Calendar EN", ((Map<String, Object>) ((Map<String, Object>) metaInvitation.providers()
.get(0).get("data")).get("metaDataFields")).get("name:en"));
Role role = invitation.getRoles().iterator().next().getRole();
assertEquals("Mail", role.getName());
Map<String, Object> application = role.getApplication();
assertEquals("Calendar EN", ((Map<String, Object>) ((Map<String, Object>) application.get("data"))
.get("metaDataFields")).get("name:en"));
}

@Test
Expand Down
10 changes: 8 additions & 2 deletions server/src/test/java/access/api/UserControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import access.model.Authority;
import access.model.Role;
import access.model.User;
import access.model.UserRole;
import io.restassured.common.mapper.TypeRef;
import io.restassured.http.ContentType;
import io.restassured.http.Header;
Expand All @@ -18,6 +19,7 @@
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static access.Seed.*;
import static com.github.tomakehurst.wiremock.client.WireMock.*;
Expand Down Expand Up @@ -264,7 +266,9 @@ void switchAppToClient() throws Exception {
void other() throws Exception {
AccessCookieFilter accessCookieFilter = openIDConnectFlow("/api/v1/users/login", SUPER_SUB);
Long id = userRepository.findBySubIgnoreCase(INVITER_SUB).get().getId();
stubForManageProviderById(EntityType.OIDC10_RP, "5");

super.stubForManageProviderByEntityID(EntityType.OIDC10_RP, "https://calendar");

User user = given()
.when()
.filter(accessCookieFilter.cookieFilter())
Expand All @@ -273,7 +277,9 @@ void other() throws Exception {
.pathParams("id", id)
.get("/api/v1/users/other/{id}")
.as(User.class);
assertEquals(2, user.getUserRoles().size());
Set<UserRole> userRoles = user.getUserRoles();
assertEquals(2, userRoles.size());
assertEquals(List.of("5", "5"), userRoles.stream().map(userRole -> userRole.getRole().getApplication().get("id")).toList());
}

@Test
Expand Down
7 changes: 0 additions & 7 deletions server/src/test/java/access/api/ValidationControllerTest.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
package access.api;

import access.AbstractTest;
import access.model.Authority;
import access.model.MetaInvitation;
import access.model.Validation;
import io.restassured.common.mapper.TypeRef;
import io.restassured.http.ContentType;
import org.hamcrest.core.IsEqual;
import org.junit.jupiter.api.Test;

import java.util.Map;

import static io.restassured.RestAssured.given;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.jupiter.api.Assertions.*;

class ValidationControllerTest extends AbstractTest {

Expand Down
7 changes: 4 additions & 3 deletions welcome/src/components/RoleCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import I18n from "../locale/I18n";
import {MoreLessText} from "./MoreLessText";
import {Button, Card, CardType, Chip, ChipType} from "@surfnet/sds";

export const RoleCard = ({role, provider, index, isNew = false}) => {
export const RoleCard = ({role, index, isNew = false}) => {

const logo = provider.data.metaDataFields["logo:0:url"];
const application = role.application;
const logo = role.application.data.metaDataFields["logo:0:url"];
const children =
<div key={index} className="user-role">
<Logo src={logo} alt={"provider"} className={"provider"}/>
<section className={"user-role-info"}>
<p>{provider.data.metaDataFields[`name:${I18n.locale}`]} ({provider.data.metaDataFields[`OrganizationName:${I18n.locale}`]})</p>
<p>{application.data.metaDataFields[`name:${I18n.locale}`]} ({application.data.metaDataFields[`OrganizationName:${I18n.locale}`]})</p>
<h3>{role.name}</h3>
<MoreLessText txt={role.description}/>
</section>
Expand Down
7 changes: 3 additions & 4 deletions welcome/src/components/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ import React from "react";
import "./User.scss";
import I18n from "../locale/I18n";
import {isEmpty} from "../utils/Utils";
import {providerInfo} from "../utils/Manage";
import {RoleCard} from "./RoleCard";

export const User = ({user, invitationRoles = []}) => {

const renderUserRole = (userRole, index) => {
const role = userRole.role;
const provider = providerInfo(role.application);
return (
<RoleCard role={role} provider={provider} index={index}/>
<RoleCard role={role} index={index}/>
);
}
const rolesToExclude = invitationRoles.map(invitationRole => invitationRole.role.id);
Expand All @@ -20,7 +18,8 @@ export const User = ({user, invitationRoles = []}) => {
.filter(userRole => !rolesToExclude.includes(userRole.role.id));
return (
<>
{(isEmpty(user.userRoles) && isEmpty(invitationRoles))&& <p className={"span-row "}>{I18n.t("users.noRolesInfo")}</p>}
{(isEmpty(user.userRoles) && isEmpty(invitationRoles)) &&
<p className={"span-row "}>{I18n.t("users.noRolesInfo")}</p>}
{!isEmpty(user.userRoles) &&
<>
{filteredUserRoles
Expand Down
18 changes: 8 additions & 10 deletions welcome/src/pages/Invitation.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const Invitation = ({authenticated}) => {
const navigate = useNavigate();
const {user, config} = useAppStore(state => state);

const [invitationMeta, setInvitationMeta] = useState({});
const [invitation, setInvitation] = useState({});
const [loading, setLoading] = useState(true);
const [expired, setExpired] = useState(false);
const [confirmation, setConfirmation] = useState({});
Expand All @@ -38,18 +38,17 @@ export const Invitation = ({authenticated}) => {
runOnce = true;
invitationByHash(hashParam)
.then(res => {
setInvitationMeta(res);
setInvitation(res);
useAppStore.setState(() => ({
invitationMeta: res
invitation: res
}));
const status = res.invitation.status;
const status = res.status;
if (status !== "OPEN") {
navigate(`/profile`);
} else {
const mayAccept = localStorage.getItem(MAY_ACCEPT);
if (mayAccept && config.name) {
const {invitation} = res;
acceptInvitation(hashParam, invitation.id)
acceptInvitation(hashParam, res.id)
.then(() => {
localStorage.removeItem(MAY_ACCEPT);
me()
Expand All @@ -71,7 +70,7 @@ export const Invitation = ({authenticated}) => {
warning: false,
error: true,
question: I18n.t("invitationAccept.emailMismatch", {
email: res.invitation.email,
email: res.email,
userEmail: user.email
}),
confirmationHeader: I18n.t("confirmationDialog.error"),
Expand All @@ -88,7 +87,7 @@ export const Invitation = ({authenticated}) => {
)
} else {
localStorage.setItem(MAY_ACCEPT, "true");
setExpired(new Date() > new Date(res["invitation"].expiryDate * 1000));
setExpired(new Date() > new Date(res.expiryDate * 1000));
setLoading(false);
}
}
Expand Down Expand Up @@ -134,10 +133,9 @@ export const Invitation = ({authenticated}) => {
}

const renderLoginStep = () => {
const {invitation, providers} = invitationMeta;
let html = DOMPurify.sanitize(I18n.t("invitationAccept.invited", {
type: I18n.t("invitationAccept.role"),
roles: splitListSemantically(invitation.roles.map(role => `<strong>${role.role.name}</strong>${organisationName(role, providers)}`), I18n.t("forms.and")),
roles: splitListSemantically(invitation.roles.map(invitationRole => `<strong>${invitationRole.role.name}</strong>${organisationName(invitationRole)}`), I18n.t("forms.and")),
inviter: invitation.inviter.name,
plural: invitation.roles.length === 1 ? I18n.t("invitationAccept.role") : I18n.t("invitationAccept.roles"),
email: invitation.inviter.email
Expand Down
24 changes: 11 additions & 13 deletions welcome/src/pages/Proceed.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,37 @@ import {User} from "../components/User";

export const Proceed = () => {

const {user, invitationMeta, config} = useAppStore(state => state);
const {user, invitation, config} = useAppStore(state => state);
const [loading, setLoading] = useState(true);
const [reloadedInvitationMeta, setReloadedInvitationMeta] = useState(null);
const [reloadedInvitation, setReloadedInvitation] = useState(null);

useEffect(() => {
if (isEmpty(user)) {
login(config);
} else if (isEmpty(invitationMeta)) {
} else if (isEmpty(invitation)) {
const hashParam = getParameterByName("hash", window.location.search);
invitationByHash(hashParam)
.then(res => {
setReloadedInvitationMeta(res);
setReloadedInvitation(res);
setLoading(false);
})
} else {
setReloadedInvitationMeta(invitationMeta);
setReloadedInvitation(invitation);
setLoading(false);
}
}, [invitationMeta, user, config]);
}, [invitation, user, config]);

const renderInvitationRole = (invitationRole, index, isNew) => {
const role = invitationRole.role;
const provider = role.application || {};
return (
<RoleCard role={role} provider={provider} index={index} isNew={isNew}/>
<RoleCard role={role} index={index} isNew={isNew}/>
);
}

const renderProceedStep = () => {
const {invitation, providers} = reloadedInvitationMeta;
const html = DOMPurify.sanitize(I18n.t("proceed.info", {
plural: invitation.roles.length === 1 ? I18n.t("invitationAccept.role") : I18n.t("invitationAccept.roles"),
roles: splitListSemantically(invitation.roles.map(role => `<strong>${role.role.name}</strong>${organisationName(role, providers)}`), I18n.t("forms.and"))
plural: reloadedInvitation.roles.length === 1 ? I18n.t("invitationAccept.role") : I18n.t("invitationAccept.roles"),
roles: splitListSemantically(reloadedInvitation.roles.map(invitationRole => `<strong>${invitationRole.role.name}</strong>${organisationName(invitationRole)}`), I18n.t("forms.and"))
}));
return (
<>
Expand All @@ -66,14 +64,14 @@ export const Proceed = () => {
<span>{I18n.t("proceed.nextStep")}</span>
</div>
</div>
{invitation.roles.map((invitationRole, index) => renderInvitationRole(invitationRole, index, true))}
{reloadedInvitation.roles.map((invitationRole, index) => renderInvitationRole(invitationRole, index, true))}
<User user={user} invitationRoles={invitation.roles}/>
</section>
</>
)
}

if (loading || isEmpty(reloadedInvitationMeta)) {
if (loading || isEmpty(reloadedInvitation)) {
return <Loader/>
}

Expand Down
2 changes: 1 addition & 1 deletion welcome/src/stores/AppStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const useAppStore = create(set => ({
csrfToken: null,
config: {},
user: {},
invitationMeta: {},
invitation: {},
authenticated: false,
objectRole: "",
flash: {msg: "", className: "hide", type: "info"},
Expand Down
25 changes: 3 additions & 22 deletions welcome/src/utils/Manage.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,4 @@
import {isEmpty} from "./Utils";

export const organisationName = (role, providers) => {
const provider = providers.find(prov => prov.id === role.role.manageId);
return provider ? ` (${provider.data.metaDataFields["OrganizationName:en"]})` : "";
export const organisationName = invitationRole => {
const application = invitationRole.role.application;
return ` (${application.data.metaDataFields["OrganizationName:en"]})`;
}


export const providerInfo = provider => {
if (isEmpty(provider)) {
return {
data: {
metaDataFields: {
"OrganizationName:en": "",
provisioning_type: "",
"name:en": "Unknown in Manage"
}
}
}
}
return provider;
}

0 comments on commit 8ad39c7

Please sign in to comment.