Skip to content

Commit

Permalink
Do not return already accepted invitations
Browse files Browse the repository at this point in the history
  • Loading branch information
oharsta committed Oct 20, 2023
1 parent 5798f01 commit a8e458d
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 57 deletions.
16 changes: 10 additions & 6 deletions client/src/pages/Invitation.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ export const Invitation = ({authenticated}) => {
invitationByHash(hashParam)
.then(res => {
setInvitation(res);
if (res.status !== "OPEN") {
localStorage.removeItem("location");
navigate("/");
return;
}
const reloaded = performance.getEntriesByType("navigation").map(entry => entry.type).includes("reload");
const mayAccept = localStorage.getItem(MAY_ACCEPT);
if (mayAccept && config.name && !reloaded) {
Expand Down Expand Up @@ -78,7 +73,16 @@ export const Invitation = ({authenticated}) => {
})
.catch(e => {
localStorage.removeItem(MAY_ACCEPT);
navigate(e.response?.status === 404 ? "/404" : "/profile");
const status = e.response?.status;
if (status === 409) {
if (config.authenticated) {
navigate(`/`);
} else {
login(config);
}
} else {
navigate("/404");
}
})
//Prevent in dev mode an accidental acceptance of an invitation
return () => localStorage.removeItem(MAY_ACCEPT);
Expand Down
3 changes: 3 additions & 0 deletions server/src/main/java/access/api/InvitationController.java
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ public ResponseEntity<Map<String, Integer>> resendInvitation(@PathVariable("id")
@GetMapping("public")
public ResponseEntity<Invitation> getInvitation(@RequestParam("hash") String hash) {
Invitation invitation = invitationRepository.findByHash(hash).orElseThrow(NotFoundException::new);
if (!invitation.getStatus().equals(Status.OPEN)) {
throw new InvitationStatusException();
}
manage.deriveRemoteApplications(invitation.getRoles().stream().map(InvitationRole::getRole).toList());
return ResponseEntity.ok(invitation);
}
Expand Down
16 changes: 16 additions & 0 deletions server/src/test/java/access/api/InvitationControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import access.AbstractTest;
import access.AccessCookieFilter;
import access.exception.NotFoundException;
import access.manage.EntityType;
import access.model.*;
import com.fasterxml.jackson.core.JsonProcessingException;
Expand Down Expand Up @@ -43,6 +44,21 @@ void getInvitation() throws JsonProcessingException {
.get("metaDataFields")).get("name:en"));
}

@Test
void getInvitationAlreadyAccepted() {
Invitation invitation = invitationRepository.findByHash(Authority.GUEST.name()).orElseThrow(NotFoundException::new);
invitation.setStatus(Status.ACCEPTED);
invitationRepository.save(invitation);
given()
.when()
.accept(ContentType.JSON)
.contentType(ContentType.JSON)
.queryParam("hash", Authority.GUEST.name())
.get("/api/v1/invitations/public")
.then()
.statusCode(409);
}

@Test
void newInvitation() throws Exception {
AccessCookieFilter accessCookieFilter = openIDConnectFlow("/api/v1/users/login", MANAGE_SUB);
Expand Down
101 changes: 50 additions & 51 deletions welcome/src/pages/Invitation.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,66 +43,65 @@ export const Invitation = ({authenticated}) => {
useAppStore.setState(() => ({
invitation: res
}));
const status = res.status;
if (status !== "OPEN") {
navigate(`/profile`);
} else {
const mayAccept = localStorage.getItem(MAY_ACCEPT);
if (mayAccept && config.name) {
acceptInvitation(hashParam, res.id)
.then(res=> {
localStorage.removeItem(MAY_ACCEPT);
me()
.then(userWithRoles => {
useAppStore.setState(() => ({
user: userWithRoles,
authenticated: true
}));
const inviteRedeemUrlQueryParam = res.inviteRedeemUrl ? `&inviteRedeemUrl=${encodeURIComponent(res.inviteRedeemUrl)}` : "";
localStorage.removeItem("location");
navigate(`/proceed?hash=${hashParam}${inviteRedeemUrlQueryParam}`);
})
})
.catch(e => {
setLoading(false);
if (e.response && e.response.status === 412) {
setConfirmation({
cancel: null,
action: () => logout().then(() => login(config, true, hashParam)),
warning: false,
error: true,
question: I18n.t("invitationAccept.emailMismatch", {
email: res.email,
userEmail: user.email
}),
confirmationHeader: I18n.t("confirmationDialog.error"),
confirmationTxt: I18n.t("invitationAccept.login")
});
localStorage.setItem(MAY_ACCEPT, "true");
setConfirmationOpen(true);
} else {
localStorage.removeItem(MAY_ACCEPT);
handleError(e);
}

const mayAccept = localStorage.getItem(MAY_ACCEPT);
if (mayAccept && config.name) {
acceptInvitation(hashParam, res.id)
.then(res => {
localStorage.removeItem(MAY_ACCEPT);
me()
.then(userWithRoles => {
useAppStore.setState(() => ({
user: userWithRoles,
authenticated: true
}));
const inviteRedeemUrlQueryParam = res.inviteRedeemUrl ? `&inviteRedeemUrl=${encodeURIComponent(res.inviteRedeemUrl)}` : "";
localStorage.removeItem("location");
navigate(`/proceed?hash=${hashParam}${inviteRedeemUrlQueryParam}`);
})
})
.catch(e => {
setLoading(false);
if (e.response && e.response.status === 412) {
setConfirmation({
cancel: null,
action: () => logout().then(() => login(config, true, hashParam)),
warning: false,
error: true,
question: I18n.t("invitationAccept.emailMismatch", {
email: res.email,
userEmail: user.email
}),
confirmationHeader: I18n.t("confirmationDialog.error"),
confirmationTxt: I18n.t("invitationAccept.login")
});
localStorage.setItem(MAY_ACCEPT, "true");
setConfirmationOpen(true);
} else {
localStorage.removeItem(MAY_ACCEPT);
handleError(e);
}
)
} else {
localStorage.setItem(MAY_ACCEPT, "true");
setExpired(new Date() > new Date(res.expiryDate * 1000));
setLoading(false);
}

}
)
} else {
localStorage.setItem(MAY_ACCEPT, "true");
setExpired(new Date() > new Date(res.expiryDate * 1000));
setLoading(false);
}
}
)
.catch(e => {
localStorage.removeItem(MAY_ACCEPT);
let path = "/404";
const status = e.response?.status;
if (status === 409) {
path = "/profile";
if (config.authenticated) {
navigate(`/profile`);
} else {
login(config);
}
} else {
navigate("/404");
}
navigate(path);
})
//Prevent in dev mode an accidental acceptance of an invitation
return () => localStorage.removeItem(MAY_ACCEPT);
Expand Down

0 comments on commit a8e458d

Please sign in to comment.