Skip to content

Commit

Permalink
Start for #587
Browse files Browse the repository at this point in the history
  • Loading branch information
oharsta committed Dec 23, 2024
1 parent f6d0b91 commit dfb7fbc
Show file tree
Hide file tree
Showing 61 changed files with 5,282 additions and 157 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import myconext.manage.Manage;
import myconext.model.User;
import myconext.repository.UserRepository;
import org.apache.commons.lang3.stream.Streams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.AuthenticationManager;
Expand All @@ -28,6 +29,7 @@ public class ShibbolethPreAuthenticatedProcessingFilter extends AbstractPreAuthe
public static final String SHIB_EMAIL = "Shib-InetOrgPerson-mail";
public static final String SHIB_UID = "uid";
public static final String SHIB_SCHAC_HOME_ORGANIZATION = "schacHomeOrganization";
public static final String SHIB_MEMBERSHIPS = "is-member-of";

private final UserRepository userRepository;
private final Manage serviceProviderResolver;
Expand All @@ -51,6 +53,9 @@ protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
String email = getHeader(SHIB_EMAIL, request);
String givenName = getHeader(SHIB_GIVEN_NAME, request);
String familyName = getHeader(SHIB_SUR_NAME, request);
Streams.of(getHeader(SHIB_MEMBERSHIPS, request).split(";"))
.map(String::trim)
.toList();

boolean valid = Stream.of(uid, schacHomeOrganization, email, givenName, familyName).allMatch(StringUtils::hasText);
if (!valid) {
Expand Down
15 changes: 12 additions & 3 deletions servicedesk-gui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@
"dependencies": {
"@surfnet/sds": "^0.0.120",
"react": "^19.0.0",
"react-dom": "^19.0.0"
"react-dom": "^19.0.0",
"react-router-dom": "7.1.0",
"react-select": "^5.9.0",
"react-tooltip": "^5.28.0",
"dompurify": "^3.2.3",
"i18n-js": "^4.5.1",
"isomorphic-dompurify": "^2.19.0",
"zustand": "^5.0.2"
},
"devDependencies": {
"@eslint/js": "^9.17.0",
Expand All @@ -25,6 +32,8 @@
"eslint-plugin-react-refresh": "^0.4.16",
"globals": "^15.14.0",
"sass": "^1.83.0",
"vite": "^6.0.4"
}
"vite": "^6.0.4",
"http-proxy-middleware": "^3.0.3"
},
"proxy": "http://127.0.0.1:8888/"
}
42 changes: 0 additions & 42 deletions servicedesk-gui/src/App.css

This file was deleted.

100 changes: 69 additions & 31 deletions servicedesk-gui/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,73 @@
import {useState} from 'react'
import {useEffect, useState} from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'

function App() {
const [count, setCount] = useState(0)
import './App.scss'
import {useNavigate} from "react-router-dom";
import {useAppStore} from "./stores/AppStore.js";
import {configuration, csrf, me} from "./api/index.js";

return (
<>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.jsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
)
}
export const App = () => {

const [loading, setLoading] = useState(true);
const navigate = useNavigate();
const {user} = useAppStore(state => state);

useEffect(() => {
setLoading(true);
csrf().then(token => {
useAppStore.setState(() => ({csrfToken: token.token}));
configuration()
.then(res => {
useAppStore.setState(() => ({config: res}));
if (!res.authenticated) {
if (!res.name) {
const direction = window.location.pathname + window.location.search;
localStorage.setItem("location", direction);
} else if (!isEmpty(res.missingAttributes)) {
setLoading(false);
navigate("/missingAttributes");
return;
}
const pathname = localStorage.getItem("location") || window.location.pathname;
const isInvitationAcceptFlow = window.location.pathname.startsWith("/invitation/accept");
if (res.name && !pathname.startsWith("/invitation/accept") && !isInvitationAcceptFlow) {
setLoading(false);
navigate("/deadend");
} else if (pathname === "/" || pathname.startsWith("/login") || pathname.startsWith("/invitation/accept") || isInvitationAcceptFlow) {
setLoading(false);
navigate(isInvitationAcceptFlow ? (window.location.pathname + window.location.search) : pathname);
} else {
//Bookmarked URL's trigger a direct login and skip the landing page
login(res);
}
} else {
me()
.then(res => {
useAppStore.setState(() => ({user: res, authenticated: true}));
setLoading(false);
const location = localStorage.getItem("location") || window.location.pathname + window.location.search;
const newLocation = location.startsWith("/login") ? "/home" : location;
localStorage.removeItem("location");
navigate(newLocation);
});
}
})
.catch(() => {
setLoading(false);
navigate("/deadend");
})
})
}, [reload, impersonator]); // eslint-disable-line react-hooks/exhaustive-deps

export default App
if (loading) {
return <Loader/>
}


return (
<>
<span>TODO</span>
<span>Routes -> with login</span>
</>
)
}
Empty file added servicedesk-gui/src/App.scss
Empty file.
30 changes: 30 additions & 0 deletions servicedesk-gui/src/__tests__/locale/en.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import en from "../../locale/en";
import nl from "../../locale/nl";

expect.extend({
toContainKey(translation, key) {
return {
message: () => `Expected ${key} to be present in ${JSON.stringify(translation)}`,
pass: (translation !== undefined && translation[key] !== undefined)
};
},
});

test("All translations exists in all bundles", () => {
const contains = (translation, translationToVerify, keyCollection, parents) => {
Object.keys(translation).forEach(key => {
expect(translationToVerify).toContainKey(key);
const value = translation[key];
keyCollection.push(parents + key);
if (typeof value === "object") {
contains(value, translationToVerify[key], keyCollection, parents + key + ".")
}
});
};
const keyCollectionEN = [];
contains(en, nl, keyCollectionEN, '');
const keyCollectionNL = [];
contains(nl, en, keyCollectionNL, '');
const positionalMismatches = keyCollectionEN.filter((item, index) => keyCollectionNL[index] !== item);
expect(positionalMismatches).toEqual([])
});
11 changes: 11 additions & 0 deletions servicedesk-gui/src/__tests__/stores/AppStore.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {useAppStore} from "../../stores/AppStore";

test("Store outside functional component", () => {
const csrfToken = useAppStore.getState().csrfToken;
expect(csrfToken).toBeNull();

useAppStore.setState({csrfToken: "test"});

const updatedCsrfToken = useAppStore.getState().csrfToken;
expect(updatedCsrfToken).toEqual("test");
});
33 changes: 33 additions & 0 deletions servicedesk-gui/src/__tests__/utils/Manage.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {mergeProvidersProvisioningsRoles, reduceApplicationFromUserRoles} from "../../utils/Manage";
import applications from "./applications.json";
import roles from "./roles.json";
import userRoles from "./userRoles.json";

test("mergeProvidersProvisioningsRoles", () => {
const results = mergeProvidersProvisioningsRoles(applications.providers, applications.provisionings, roles);
expect(results.length).toEqual(6);
});

test("reduceApplicationFromUserRoles", () => {
const results = reduceApplicationFromUserRoles(userRoles, "en");
const applicationNames = results.map(app => app.applicationName);
//Sorting alphabetically on applicationName
expect(applicationNames).toEqual([
"Calendar EN (SURF bv)",
"Research EN (SURF bv)",
"Research EN (SURF bv)",
"Wiki EN (SURF bv)",
"Wiki EN (SURF bv)",
"Wiki EN (SURF bv)"
]);
const roleNames = results
.filter(app => app.applicationName.startsWith("Wiki"))
.map(app => app.roleName);
//Sub-sorting alphabetically on roleName
expect(roleNames).toEqual([
"Wiki 1 Role",
"Wiki 2 Role",
"Wiki Another Role (3) - Calendar (1)"
]);
});

12 changes: 12 additions & 0 deletions servicedesk-gui/src/__tests__/utils/Pagination.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {defaultPagination, paginationQueryParams} from "../../utils/Pagination";

test("paginationQueryParams defaults", () => {
const page = defaultPagination("desc", "DESC");
const queryParams = paginationQueryParams(page, {custom: "val"});
expect(queryParams).toEqual("custom=val&pageNumber=0&pageSize=10&sort=desc&sortDirection=DESC&");
});

test("paginationQueryParams empty", () => {
const queryParams = paginationQueryParams({});
expect(queryParams).toEqual("");
});
Loading

0 comments on commit dfb7fbc

Please sign in to comment.