Skip to content

Commit f5317ea

Browse files
committed
Fixes #77
1 parent 952f6b4 commit f5317ea

7 files changed

Lines changed: 55 additions & 34 deletions

File tree

client/src/application/AppTeamManagement.jsx

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export const AppTeamManagement = ({
2020
refreshApp
2121
}) => {
2222

23-
const {user: currentUser, currentOrganization, setFlash} = useAppStore(state => state);
23+
const {user: currentUser, setFlash} = useAppStore(state => state);
2424
const navigate = useNavigate();
2525

2626
const [confirmation, setConfirmation] = useState({});
@@ -31,23 +31,26 @@ export const AppTeamManagement = ({
3131
const [applicationMemberships, setApplicationMemberships] = useState([]);
3232

3333
useEffect(() => {
34-
organizationUsersById(currentOrganization.id)
34+
organizationUsersById(application.organization.id)
3535
.then(res => {
3636
setOrganization(res);
3737
setApplicationMemberships((application.applicationMemberships || [])
3838
.map(membership => {
39-
membership.user = res.organizationMemberships
40-
.find(m => m.id === membership.organizationMembershipIdentifier).user;
41-
return membership;
42-
}
43-
))
39+
const organizationMembership = res.organizationMemberships
40+
.find(m => m.id === membership.organizationMembershipIdentifier);
41+
if (organizationMembership) {
42+
membership.user = organizationMembership.user;
43+
}
44+
return membership;
45+
}
46+
))
4447
const membership = (currentUser.organizationMemberships || []).find(membership => membership.organization.id === res.id);
4548
setCurrentUserAuthority(currentUserMembershipAuthority(currentUser, membership));
4649
setLoading(false);
4750
}).catch(() => {
4851
navigate("/404")
4952
});
50-
}, [refreshApp, currentOrganization]);
53+
}, [refreshApp, application]);
5154

5255
const doDelete = (membership, confirmationRequired) => {
5356
if (confirmationRequired) {
@@ -115,7 +118,7 @@ export const AppTeamManagement = ({
115118
key: "user__name",
116119
header: I18n.t("appTeamManagement.name"),
117120
mapper: membership => {
118-
return <UserMembership user={membership.user} currentUser={currentUser}/>
121+
return <UserMembership user={membership.user} currentUser={currentUser}/>
119122
}
120123
},
121124
{

client/src/connection/AppInformation.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,10 @@ export const AppInformation = ({
317317
<ErrorIndicator msg={I18n.t("connection.privacy.answerIsRequired")}
318318
/>
319319
}
320+
{(p.format && !initial && !isEmpty(application.privacy[p.name]) && !isValidUrl(application.privacy[p.name])) &&
321+
<ErrorIndicator msg={I18n.t("forms.invalidURL", {name: p[`info_${I18n.locale}`]})}
322+
/>
323+
}
320324
</section>
321325
)}
322326
</section>

client/src/connection/Testing.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,8 @@ export const Testing = ({
9292
setTab,
9393
profileOptions,
9494
identityProviders,
95-
isProduction
95+
isProduction,
96+
setDirty
9697
}) => {
9798
const {setFlash, config} = useAppStore(state => state);
9899

@@ -980,6 +981,7 @@ export const Testing = ({
980981
setFinishedSections([...finishedSections, section]);
981982
setLoading(false);
982983
setInitial(true);
984+
setDirty(true);
983985
setFlash(I18n.t(`connection.flash.${connection.id ? "updated" : "created"}`, {
984986
name: connection.name
985987
}));

client/src/pages/ApplicationDetail.jsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -144,22 +144,23 @@ const ApplicationDetail = () => {
144144
{!showPrivacy && <a href="/" onClick={toggleShowPrivacy}>
145145
{I18n.t("applicationDetail.details")}
146146
</a>}
147-
{showPrivacy && <div className="privacy-questions">
148-
{privacy.map(item => {
149-
const question = item[`info_${I18n.locale}`];
150-
const strippedQuestion = question.substring(question.indexOf(" ") + 1);
151-
const answer = metaData[item.manage]
152-
return (
153-
<div className="privacy-question">
154-
<span className="priv-name">{strippedQuestion}</span>
155-
{isEmpty(answer) && <span
156-
className="priv-answer">{I18n.t("applicationDetail.noPrivacyInfo")}</span>}
157-
{!isEmpty(answer) && <span className="priv-answer">{answer}</span>}
158-
</div>
159-
);
160-
}
161-
)}
162-
</div>}
147+
{showPrivacy &&
148+
<div className="privacy-questions">
149+
{privacy.map(item => {
150+
const question = item[`info_${I18n.locale}`];
151+
const strippedQuestion = question.substring(question.indexOf(" ") + 1);
152+
const answer = metaData[item.manage]
153+
return (
154+
<div className="privacy-question">
155+
<span className="priv-name">{strippedQuestion}</span>
156+
{isEmpty(answer) && <span
157+
className="priv-answer">{I18n.t("applicationDetail.noPrivacyInfo")}</span>}
158+
{!isEmpty(answer) && <span className="priv-answer">{answer}</span>}
159+
</div>
160+
);
161+
}
162+
)}
163+
</div>}
163164
</div>
164165
</div>
165166
<div className="right">

client/src/pages/Connection.jsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {useAppStore} from "../stores/AppStore.js";
66
import {ApplicationConnectionHeader} from "../components/ApplicationConnectionHeader.jsx";
77
import {Overview} from "../connection/Overview.jsx";
88
import {Testing} from "../connection/Testing.jsx";
9-
import {arp, getApplicationById, getIdentityProviders, privacy} from "../api/index.js";
9+
import {getApplicationById, getIdentityProviders} from "../api/index.js";
1010
import {Loader} from "@surfnet/sds";
1111
import {APPLICATION_STATUSES, CONNECTION_STATUSES, ENVIRONMENTS, PROTOCOLS} from "../utils/Manage.js";
1212
import {AppInformation} from "../connection/AppInformation.jsx";
@@ -30,22 +30,22 @@ const protocolOptions = Object.values(PROTOCOLS).map(protocol => ({
3030

3131
export const Connection = () => {
3232
const {applicationId, tab = "overview"} = useParams();
33-
const {user, currentOrganization, arp, privacy} = useAppStore(state => state);
33+
const {user, arp, privacy} = useAppStore(state => state);
3434

3535
const [application, setApplication] = useState({});
36-
const [arpInfo, setArpInfo] = useState({profiles: [], attributes: []});
3736
const [profileOptions, setProfileOptions] = useState([]);
3837
const [currentTab, setCurrentTab] = useState(tab);
3938
const [connection, setConnection] = useState(null);
4039
const [identityProviders, setIdentityProviders] = useState([]);
4140
const [prodIdentityProviders, setProdIdentityProviders] = useState([]);
4241
const [loading, setLoading] = useState(true);
4342
const [refreshApp, setRefreshApp] = useState(0);
43+
const [dirty, setDirty] = useState(false);
4444

4545
const navigate = useNavigate();
4646

4747
useEffect(() => {
48-
getApplicationById(applicationId)
48+
getApplicationById(applicationId)
4949
.then(res => {
5050
//For convenience editing
5151
const options = arp.profiles.map(profile => ({
@@ -64,8 +64,8 @@ export const Connection = () => {
6464
breadcrumbPaths: [
6565
{path: "/home", value: I18n.t("breadCrumb.access"), menuItemName: "yourApps"},
6666
{
67-
path: `/organization/${currentOrganization.id}`,
68-
value: currentOrganization.name,
67+
path: `/organization/${application.organization.id}`,
68+
value: application.organization.name,
6969
menuItemName: "yourApps"
7070
},
7171
{path: `/application/${applicationId}`, value: I18n.t("breadCrumb.applications")},
@@ -114,6 +114,7 @@ export const Connection = () => {
114114
.then(res => {
115115
setApplication(convertServerApplicationToClient(res, protocolOptions, profileOptions, arp));
116116
setConnection(null);
117+
setDirty(false);
117118
setLoading(false);
118119
setRefreshApp(new Date().getTime());
119120
})
@@ -146,6 +147,9 @@ export const Connection = () => {
146147
}
147148

148149
const changeTab = newTab => {
150+
if (dirty) {
151+
refresh()
152+
}
149153
if (currentTab === "testing" || currentTab === "prod") {
150154
//force the overview
151155
setConnection(null);
@@ -179,6 +183,7 @@ export const Connection = () => {
179183
profileOptions={profileOptions}
180184
identityProviders={identityProviders}
181185
isProduction={false}
186+
setDirty={setDirty}
182187
/>
183188
}
184189
case "prod": {
@@ -193,6 +198,7 @@ export const Connection = () => {
193198
profileOptions={profileOptions}
194199
identityProviders={prodIdentityProviders}
195200
isProduction={true}
201+
setDirty={setDirty}
196202
/>
197203
}
198204
case "application": {
@@ -226,6 +232,7 @@ export const Connection = () => {
226232
throw new Error(`Unknown tab; ${currentTab}`)
227233
}
228234
}
235+
229236
if (loading) {
230237
return <Loader/>
231238
}

client/src/utils/Application.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ export const contactSectionValid = (application) => {
1919

2020
export const privacySectionValid = (privacyInfo, application) => {
2121
const requiredPrivacyAttributes = privacyInfo.filter(p => p.required);
22+
const formatPrivacyAttributes = privacyInfo.filter(p => p.format);
23+
const invalidUrls = formatPrivacyAttributes
24+
.map(val => val.name)
25+
.some(attr => !isValidUrl(application?.privacy?.[attr]));
2226
return requiredPrivacyAttributes
2327
.map(val => val.name)
24-
.every(attr => !isEmpty(application?.privacy?.[attr]));
28+
.every(attr => !isEmpty(application?.privacy?.[attr])) && !invalidUrls;
2529
};
2630

2731
//Pull the metaData of the application up in the root

client/src/validations/regExps.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export const validEmailRegExp = /^[+a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.?[a-zA-Z]*$/;
55
export const validUrlRegExp = /(https?|ssh|ftp):\/\/(((www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.?[a-z]{0,63})|(localhost))\b([-a-zA-Z0-9@:%_+.~#?&/=]*)/i
66

77
export const isValidUrl = url => {
8-
//We allow for empty URL's, enforcing required is different responsibility
8+
//We allow for empty URL's, enforcing required is a different responsibility
99
return isEmpty(url) || (validUrlRegExp.test(url) && (url.startsWith("https")
1010
|| (url.startsWith("http://localhost") || url.startsWith("http://127.0.0.1"))));
1111
}

0 commit comments

Comments
 (0)