Skip to content

Commit

Permalink
WIP for performance seed to test pagination and search
Browse files Browse the repository at this point in the history
  • Loading branch information
oharsta committed Nov 19, 2024
1 parent b967aef commit 668600a
Show file tree
Hide file tree
Showing 14 changed files with 308 additions and 23 deletions.
4 changes: 4 additions & 0 deletions client/src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,10 @@ export function expiryUserRoles() {
return fetchJson("/api/v1/system/expiry-user-roles")
}

export function performanceSeed() {
return postPutJson("/api/v1/system/performance-seed", {}, "PUT")
}

export function rolesUnknownInManage() {
return fetchJson("/api/v1/system/unknown-roles")
}
8 changes: 6 additions & 2 deletions client/src/locale/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ const en = {
expiredUserRoles: "User role expirations",
pendingInvitations: "Pending",
allPendingInvitations: "Pending invitations",
acceptedInvitations: "Accepted"
acceptedInvitations: "Accepted",
performanceSeed: "Seed"
},
home: {
access: "SURFconext Invite",
Expand Down Expand Up @@ -498,7 +499,10 @@ const en = {
clear: "Clear",
cronInfo: "Trigger the cron job to cleanup resources like expired user-roles, orphaned users and in-active users",
cronNotificationsInfo: "Trigger the cron job to send notification mails for user-roles that will expire in X days",
noMails: "No notification mails for user-role expirations were send"
noMails: "No notification mails for user-role expirations were send",
performanceSeedInfo: "The performance seed is dummy / generated data to test the performance of the system. It is deleted when you run the tests.",
performanceSeed: "Insert performance seed",
performanceMillis: "Inserted following number in {{millis}} ms"
},
unknownRoles: {
title: "Roles linked to applications unknown in Manage",
Expand Down
7 changes: 5 additions & 2 deletions client/src/locale/nl.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ const nl = {
expiredUserRoles: "User role expirations",
pendingInvitations: "Open",
allPendingInvitations: "Open uitnodigingen",
acceptedInvitations: "Geaccepteerd"
acceptedInvitations: "Geaccepteerd",
performanceSeed: "Seed"
},
home: {
access: "SURFconext Invite",
Expand Down Expand Up @@ -497,7 +498,9 @@ const nl = {
clear: "Clear",
cronInfo: "Roep de cron job aan die resources opruimt, zoals verlopen gebruikersrollen, verweesde gebruikers en inactieve gebruikers",
cronNotificationsInfo: "Roep de cron job aan die notificatie mails verstuurd voor gebruikersrollen die verlopen in X dagen",
noMails: "Geen notificatie mails zijn vertstuurd voor bijna verlopen gebruikersrollen"
noMails: "Geen notificatie mails zijn vertstuurd voor bijna verlopen gebruikersrollen",
performanceSeedInfo: "The performance seed is dummy / generated data to test the performance of the system. It is deleted when you run the tests.",
performanceSeed: "Insert performance seed"
},
unknownRoles: {
title: "Rollen gekoppeld aan applicaties die verwijderd zijn in Manage",
Expand Down
7 changes: 5 additions & 2 deletions client/src/pages/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,18 @@ import {RoleForm} from "./RoleForm";
import {InvitationForm} from "./InvitationForm";
import {isEmpty} from "../utils/Utils";
import {MissingAttributes} from "./MissingAttributes";
import {System} from "./System";
import {Inviter} from "./Inviter";
import {InvitationOverview} from "./InvitationOverview";
import {Application} from "./Application";
import {System} from "./System";


export const App = () => {

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

useEffect(() => {
setLoading(true);
Expand Down Expand Up @@ -107,7 +108,9 @@ export const App = () => {
element={<Invitation authenticated={true}/>}/>
<Route path="login" element={<Login/>}/>
<Route path="refresh-route/:path" element={<RefreshRoute/>}/>
<Route path="system/:tab?" element={<System/>}/>
{(user && user.superUser) &&
<Route path="system/:tab?" element={<System/>}/>
}
<Route path="*" element={<NotFound/>}/>
</Routes>}
{/* <Route path="invitations" element={<Invitation user={user}/>}/>*/}
Expand Down
27 changes: 16 additions & 11 deletions client/src/pages/System.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@ import "./System.scss";
import {Loader} from "@surfnet/sds";
import {useNavigate, useParams} from "react-router-dom";
import {useAppStore} from "../stores/AppStore";
import {ReactComponent as CronLogo} from "@surfnet/sds/icons/illustrative-icons/database-check.svg";
import {ReactComponent as RoleLogo} from "@surfnet/sds/icons/illustrative-icons/hierarchy-2.svg";
import Tabs from "../components/Tabs";
import {Page} from "../components/Page";
import {Cron} from "../tabs/Cron";
import {RolesUnknownInManage} from "../tabs/RolesUnknownInManage";
import {Invitations} from "../tabs/Invitations";
import {ReactComponent as InvitationLogo} from "@surfnet/sds/icons/functional-icons/id-1.svg";
import {ExpiredUserRoles} from "../tabs/ExpiredUserRoles";
import {PerformanceSeed} from "../tabs/PerformanceSeed";


export const System = () => {
const {config} = useAppStore(state => state);
const navigate = useNavigate();
const {tab = "cron"} = useParams();
const [loading, setLoading] = useState(false);
Expand All @@ -34,33 +33,39 @@ export const System = () => {
<Page key="cron"
name="cron"
label={I18n.t("tabs.cron")}
Icon={CronLogo}>
>
<Cron/>
</Page>,
<Page key="invitations"
name="invitations"
label={I18n.t("tabs.invitations")}
Icon={InvitationLogo}>
>
<Invitations standAlone={true}/>
</Page>,
<Page key="unknownRoles"
name="unknownRoles"
label={I18n.t("tabs.unknownRoles")}
Icon={RoleLogo}>
>
<RolesUnknownInManage/>
</Page>,
<Page key="expiredUserRoles"
name="expiredUserRoles"
label={I18n.t("tabs.expiredUserRoles")}
Icon={RoleLogo}>
>
<ExpiredUserRoles/>
</Page>

];
</Page>,
config.performanceSeedAllowed ?
<Page key="seed"
name="seed"
label={I18n.t("tabs.performanceSeed")}
>
<PerformanceSeed/>
</Page> : null
].filter(t => Boolean(t));
setTabs(newTabs);
setLoading(false);
},
[currentTab])
[currentTab, config.performanceSeedAllowed])

const tabChanged = (name) => {
setCurrentTab(name);
Expand Down
2 changes: 1 addition & 1 deletion client/src/pages/System.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import "../styles/vars.scss";
@import "../styles/vars";

.mod-system {
padding-top: 25px;
Expand Down
48 changes: 48 additions & 0 deletions client/src/tabs/PerformanceSeed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, {useState} from "react";
import I18n from "../locale/I18n";
import "./PerformanceSeed.scss";
import {Button, Loader} from "@surfnet/sds";
import {performanceSeed} from "../api";


export const PerformanceSeed = () => {
const [seed, setSeed] = useState(null);
const [millis, setMillis] = useState(0);
const [loading, setLoading] = useState(false);

if (loading) {
return <Loader/>
}

const doPerformanceSeed = () => {
setLoading(true);
setMillis(new Date().getTime())
performanceSeed().then(res => {
setSeed(res);
setLoading(false);
setMillis(new Date().getTime() - millis);
})
}

return (
<div className="mod-performance-seed-container">
<div className="mod-performance-seed">
<div className="actions">
<p>{I18n.t("system.performanceSeedInfo")}</p>
<Button onClick={doPerformanceSeed}
txt={I18n.t("system.performanceSeed")}
/>
</div>
{seed &&
<div className="results">
<p>{I18n.t("system.performanceMillis", {millis: millis})}</p>
<code className="results">
{JSON.stringify(seed, null, 4)}
</code>
</div>}
</div>


</div>)

}
20 changes: 20 additions & 0 deletions client/src/tabs/PerformanceSeed.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@import "../styles/mixins";

.mod-performance-seed-container {
background-color: white;

.mod-performance-seed {
@include page;
padding: 20px 0;

.actions {
display: flex;
gap: 40px;
align-items: center;
}

code.results {
margin-top: 20px;
}
}
}
5 changes: 1 addition & 4 deletions server/src/main/java/access/api/RoleController.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@
public class RoleController implements ApplicationResource {
private static final Log LOG = LogFactory.getLog(RoleController.class);

private final Config config;
private final RoleRepository roleRepository;
@Getter
private final ApplicationRepository applicationRepository;
Expand All @@ -57,14 +56,12 @@ public class RoleController implements ApplicationResource {
private final boolean limitInstitutionAdminRoleVisibility;
private final RoleOperations roleOperations;

public RoleController(Config config,
RoleRepository roleRepository,
public RoleController(RoleRepository roleRepository,
ApplicationRepository applicationRepository,
ApplicationUsageRepository applicationUsageRepository,
Manage manage,
ProvisioningService provisioningService,
@Value("${feature.limit-institution-admin-role-visibility}") boolean limitInstitutionAdminRoleVisibility) {
this.config = config;
this.roleRepository = roleRepository;
this.applicationRepository = applicationRepository;
this.applicationUsageRepository = applicationUsageRepository;
Expand Down
14 changes: 13 additions & 1 deletion server/src/main/java/access/api/SystemController.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import access.repository.RoleRepository;
import access.repository.UserRoleRepository;
import access.security.UserPermissions;
import access.seed.PerformanceSeed;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.apache.commons.logging.Log;
Expand All @@ -19,6 +20,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -44,17 +46,20 @@ public class SystemController {
private final RoleRepository roleRepository;
private final UserRoleRepository userRoleRepository;
private final Manage manage;
private final PerformanceSeed performanceSeed;

public SystemController(ResourceCleaner resourceCleaner,
RoleExpirationNotifier roleExpirationNotifier,
RoleRepository roleRepository,
UserRoleRepository userRoleRepository,
Manage manage) {
Manage manage,
PerformanceSeed performanceSeed) {
this.resourceCleaner = resourceCleaner;
this.roleExpirationNotifier = roleExpirationNotifier;
this.roleRepository = roleRepository;
this.userRoleRepository = userRoleRepository;
this.manage = manage;
this.performanceSeed = performanceSeed;
}

@GetMapping("/cron/cleanup")
Expand Down Expand Up @@ -91,4 +96,11 @@ public ResponseEntity<List<Role>> unknownRoles(@Parameter(hidden = true) User us
return ResponseEntity.ok(unknownManageRoles);
}

@PutMapping("/performance-seed")
public ResponseEntity<Map<String, Object>> performanceSeed(@Parameter(hidden = true) User user) {
LOG.debug("/performance-seed");
UserPermissions.assertSuperUser(user);
return ResponseEntity.ok(performanceSeed.go());
}

}
2 changes: 2 additions & 0 deletions server/src/main/java/access/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class Config {
private String eduidEntityId;
private boolean roleSearchRequired;
private boolean pastDateAllowed;
private boolean performanceSeedAllowed;
private String groupUrnPrefix;
private boolean authenticated;
private String name;
Expand All @@ -33,6 +34,7 @@ public Config(Config base) {
this.serverWelcomeUrl = base.serverWelcomeUrl;
this.eduidEntityId = base.eduidEntityId;
this.pastDateAllowed = base.pastDateAllowed;
this.performanceSeedAllowed = base.performanceSeedAllowed;
this.roleSearchRequired = base.roleSearchRequired;
this.groupUrnPrefix = base.groupUrnPrefix;
this.eduidIdpSchacHomeOrganization = base.eduidIdpSchacHomeOrganization;
Expand Down
50 changes: 50 additions & 0 deletions server/src/main/java/access/seed/NameGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package access.seed;


import java.util.Locale;
import java.util.Random;

public class NameGenerator {

private static final Random random = new Random();

private static final String[] consonants = new String[]{
"al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it",
"le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to",
"ve", "wa", "it"
};
private static final String[] vowels = new String[]{"a", "e", "i", "o", "u", "y"};


public static String generate() {
int baseMaxLength = 18;
int maxLength = random.nextInt((int) (baseMaxLength * 0.5), baseMaxLength + 1);
StringBuilder result = new StringBuilder();
while (result.length() < maxLength) {
String part = maxLength % 2 == 0 ? vowels[random.nextInt(vowels.length)] : consonants[random.nextInt(consonants.length)];
result.append(part);
}

while (result.length() > maxLength) {
result.deleteCharAt(result.length() - 1);
}
return capitalize(clean(result));
}

private static String capitalize(final StringBuilder sb) {
return sb.substring(0, 1).toUpperCase(Locale.ROOT) + sb.substring(1);
}

private static StringBuilder clean(final StringBuilder sb) {
int codePoint = sb.codePointAt(0);
if (!Character.isAlphabetic(codePoint)) {
sb.deleteCharAt(0);
}
codePoint = sb.codePointAt(sb.length() - 1);
if (!Character.isAlphabetic(codePoint)) {
sb.deleteCharAt(sb.length() - 1);
}
return sb;
}

}
Loading

0 comments on commit 668600a

Please sign in to comment.