Skip to content

Commit

Permalink
Merge pull request #100 from loneil/feature/publicOption
Browse files Browse the repository at this point in the history
Enable Public forms
  • Loading branch information
TimCsaky authored Nov 20, 2020
2 parents 8fc7b09 + 52e295a commit 5a65c82
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 24 deletions.
3 changes: 1 addition & 2 deletions app/frontend/src/components/base/BaseAuthButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ export default {
methods: {
login() {
if (this.keycloakReady) {
window.location.replace(this.createLoginUrl());
//window.location.replace(this.createLoginUrl({ idpHint: 'idir' }));
window.location.replace(this.createLoginUrl({ idpHint: 'idir' }));
}
},
logout() {
Expand Down
3 changes: 1 addition & 2 deletions app/frontend/src/components/base/BaseSecure.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ export default {
methods: {
login() {
if (this.keycloakReady) {
window.location.replace(this.createLoginUrl());
// window.location.replace(this.createLoginUrl({ idpHint: 'idir' }));
window.location.replace(this.createLoginUrl({ idpHint: 'idir' }));
}
},
},
Expand Down
2 changes: 1 addition & 1 deletion app/frontend/src/components/designer/FormSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
:mandatory="false"
:rules="loginRequiredRules"
>
<v-radio disabled label="Public (anonymous)" :value="ID_MODE.PUBLIC" />
<v-radio label="Public (anonymous)" :value="ID_MODE.PUBLIC" />
<v-radio label="Log-in Required" value="login"></v-radio>
<v-row v-if="userType === ID_MODE.LOGIN" class="pl-6 mb-2">
<v-checkbox
Expand Down
38 changes: 25 additions & 13 deletions app/frontend/src/router/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,19 @@ export default function getRouter(basePath = '/') {
name: 'FormCreate',
component: () => import(/* webpackChunkName: "create" */ '@/views/form/Create.vue'),
meta: {
breadcrumbTitle: 'Form Designer'
breadcrumbTitle: 'Form Designer',
requiresAuth: true,
hasLogin: true
},
},
{
path: 'design',
name: 'FormDesigner',
component: () => import(/* webpackChunkName: "designer" */ '@/views/form/Design.vue'),
meta: {
breadcrumbTitle: 'Form Designer'
breadcrumbTitle: 'Form Designer',
requiresAuth: true,
hasLogin: true
},
props: createProps
},
Expand All @@ -64,7 +68,9 @@ export default function getRouter(basePath = '/') {
name: 'FormManage',
component: () => import(/* webpackChunkName: "manage" */ '@/views/form/Manage.vue'),
meta: {
breadcrumbTitle: 'Manage Form'
breadcrumbTitle: 'Manage Form',
requiresAuth: true,
hasLogin: true
},
props: createProps
},
Expand All @@ -73,7 +79,9 @@ export default function getRouter(basePath = '/') {
name: 'FormPreview',
component: () => import(/* webpackChunkName: "viewsubmission" */ '@/views/form/Preview.vue'),
meta: {
breadcrumbTitle: 'Preview Form'
breadcrumbTitle: 'Preview Form',
requiresAuth: true,
hasLogin: true
},
props: createProps
},
Expand All @@ -82,7 +90,9 @@ export default function getRouter(basePath = '/') {
name: 'FormSubmissions',
component: () => import(/* webpackChunkName: "submissions" */ '@/views/form/Submissions.vue'),
meta: {
breadcrumbTitle: 'Submissions'
breadcrumbTitle: 'Submissions',
requiresAuth: true,
hasLogin: true
},
props: createProps
},
Expand Down Expand Up @@ -111,7 +121,9 @@ export default function getRouter(basePath = '/') {
name: 'FormTeams',
component: () => import(/* webpackChunkName: "teams" */ '@/views/form/Teams.vue'),
meta: {
breadcrumbTitle: 'Team Management'
breadcrumbTitle: 'Team Management',
requiresAuth: true,
hasLogin: true
},
props: createProps
},
Expand All @@ -120,15 +132,13 @@ export default function getRouter(basePath = '/') {
name: 'FormView',
component: () => import(/* webpackChunkName: "viewsubmission" */ '@/views/form/View.vue'),
meta: {
breadcrumbTitle: 'View Submission'
breadcrumbTitle: 'View Submission',
requiresAuth: true,
hasLogin: true
},
props: createProps
},
],
meta: {
requiresAuth: true,
hasLogin: true
}
]
},
{
path: '/user',
Expand Down Expand Up @@ -193,13 +203,15 @@ export default function getRouter(basePath = '/') {
}

// Force login redirect if not authenticated
// Note some pages (Submit and Success) only require auth if the form being loaded is secured
// in those cases, see the navigation gaurds in their views for auth loop
if (to.matched.some(route => route.meta.requiresAuth)
&& router.app.$keycloak
&& router.app.$keycloak.ready
&& !router.app.$keycloak.authenticated) {
const redirect = location.origin + basePath + to.path + location.search;
const loginUrl = router.app.$keycloak.createLoginUrl({
//idpHint: 'idir',
idpHint: 'idir',
redirectUri: redirect
});
window.location.replace(loginUrl);
Expand Down
2 changes: 1 addition & 1 deletion app/frontend/src/store/modules/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default {
authenticated: () => Vue.prototype.$keycloak.authenticated,
createLoginUrl: () => options => Vue.prototype.$keycloak.createLoginUrl(options),
createLogoutUrl: () => options => Vue.prototype.$keycloak.createLogoutUrl(options),
email: () => Vue.prototype.$keycloak.tokenParsed.email,
email: () => Vue.prototype.$keycloak.tokenParsed ? Vue.prototype.$keycloak.tokenParsed.email : '',
fullName: () => Vue.prototype.$keycloak.fullName,
hasResourceRoles: (_state, getters) => (resource, roles) => {
if (!getters.authenticated) return false;
Expand Down
40 changes: 40 additions & 0 deletions app/frontend/src/utils/permissionUtils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { FormPermissions, IdentityProviders } from '@/utils/constants';
import { formService } from '@/services';
import store from '@/store';

//
// Utility Functions for determining permissions
Expand Down Expand Up @@ -45,3 +47,41 @@ export function checkSubmissionView(userForm) {
];
return userForm && userForm.permissions && userForm.permissions.some(p => perms.includes(p));
}

/**
* @function determineFormNeedsAuth
* When loading a form to fill out, determine if the user needs to log in to submit it
* @param {Object} store The vuex store reference
* @param {String} formId The form guid
* @param {String} submissionId The submission guid
* @param {Object} next The routing next object
*/
export async function determineFormNeedsAuth(formId, submissionId, next) {
// before this view is loaded, determine if this is a public form
// if it IS, they don't need to log in. If it's secured, go through auth loop
// If authed already skip all this
if (!store.getters['auth/authenticated']) {
try {
// Get this form or submission
if (formId) {
await formService.readForm(formId);
} else if (submissionId) {
await formService.getSubmission(submissionId);
}
} catch (error) {
// If there's a 401 trying to get this form, make that user log in
if (error.response && error.response.status === 401) {
window.location.replace(
store.getters['auth/createLoginUrl']({ idpHint: 'idir' })
);
} else {
// Other errors raise an issue
store.dispatch('notifications/addNotification', {
message: 'An error occurred while loading this form.',
consoleError: `Error loading form ${formId} or submission ${submissionId}: ${error}`,
});
}
}
}
next();
}
4 changes: 2 additions & 2 deletions app/frontend/src/utils/transformUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function generateIdps({ idps, userType }) {
if (userType === IdentityMode.LOGIN && idps && idps.length) {
identityProviders = identityProviders.concat(idps.map((i) => ({ code: i })));
} else if (userType === IdentityMode.PUBLIC) {
identityProviders.push(IdentityMode.PUBLIC);
identityProviders.push({ code: IdentityMode.PUBLIC });
}
return identityProviders;
}
Expand All @@ -33,7 +33,7 @@ export function parseIdps(identityProviders) {
userType: IdentityMode.TEAM,
};
if (identityProviders && identityProviders.length) {
if (identityProviders[0] === IdentityMode.PUBLIC) {
if (identityProviders[0].code === IdentityMode.PUBLIC) {
result.userType = IdentityMode.PUBLIC;
} else {
result.userType = IdentityMode.LOGIN;
Expand Down
6 changes: 5 additions & 1 deletion app/frontend/src/views/form/Submit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
</template>

<script>
import { determineFormNeedsAuth } from '@/utils/permissionUtils';
import FormViewer from '@/components/designer/FormViewer.vue';
export default {
Expand All @@ -13,7 +14,10 @@ export default {
FormViewer,
},
props: {
f: String
f: String,
},
beforeRouteEnter(to, from, next) {
determineFormNeedsAuth(to.query.f, undefined, next);
},
};
</script>
4 changes: 4 additions & 0 deletions app/frontend/src/views/form/Success.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<script>
import { mapGetters } from 'vuex';
import { determineFormNeedsAuth } from '@/utils/permissionUtils';
import FormViewer from '@/components/designer/FormViewer.vue';
import RequestReceipt from '@/components/forms/RequestReceipt.vue';
Expand All @@ -42,5 +43,8 @@ export default {
RequestReceipt,
},
computed: mapGetters('auth', ['email']),
beforeRouteEnter(to, from, next) {
determineFormNeedsAuth(undefined, to.query.s, next);
},
};
</script>
4 changes: 2 additions & 2 deletions app/frontend/tests/unit/utils/transformUtils.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('generateIdps', () => {
});

it('returns correct values when usertype is public', () => {
expect(transformUtils.generateIdps({ userType: IdentityMode.PUBLIC })).toEqual([IdentityMode.PUBLIC]);
expect(transformUtils.generateIdps({ userType: IdentityMode.PUBLIC })).toEqual([{ code: IdentityMode.PUBLIC }]);
});
});

Expand All @@ -41,7 +41,7 @@ describe('parseIdps', () => {
});

it('returns an empty array idps and usertype public when public', () => {
expect(transformUtils.parseIdps([IdentityMode.PUBLIC])).toEqual({
expect(transformUtils.parseIdps([{ code: IdentityMode.PUBLIC }])).toEqual({
idps: [],
userType: IdentityMode.PUBLIC,
});
Expand Down

0 comments on commit 5a65c82

Please sign in to comment.