Skip to content

Commit

Permalink
Merge pull request #4711 from kobotoolbox/feature-tos--tos-form
Browse files Browse the repository at this point in the history
[TASK-114] TOS form
  • Loading branch information
p2edwards committed Nov 16, 2023
2 parents 079230d + f433196 commit 7c38074
Show file tree
Hide file tree
Showing 15 changed files with 359 additions and 38 deletions.
1 change: 0 additions & 1 deletion jsapp/js/actions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ export namespace actions {
verifyLogin: {
loggedin: GenericCallbackDefinition;
};
logout: GenericDefinition;
changePassword: GenericDefinition;
};
const survey: object;
Expand Down
13 changes: 0 additions & 13 deletions jsapp/js/actions.es6
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ actions.navigation = Reflux.createActions([

actions.auth = Reflux.createActions({
verifyLogin: {children: ['loggedin', 'anonymous', 'failed']},
logout: {children: ['completed', 'failed']},
changePassword: {children: ['completed', 'failed']},
getApiToken: {children: ['completed', 'failed']},
});
Expand Down Expand Up @@ -385,18 +384,6 @@ actions.search.assets.listen(function(searchData, params = {}){
});
});

// reload so a new csrf token is issued
actions.auth.logout.completed.listen(function(){
window.setTimeout(function(){
window.location.replace('', '');
}, 1);
});

actions.auth.logout.listen(function(){
dataInterface.logout().done(actions.auth.logout.completed).fail(function(){
console.error('logout failed for some reason. what should happen now?');
});
});
actions.auth.verifyLogin.listen(function(){
dataInterface.selfProfile()
.done((data/*, msg, req*/)=>{
Expand Down
9 changes: 9 additions & 0 deletions jsapp/js/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,15 @@ const fetchData = async <T>(
export const fetchGet = async <T>(path: string, options?: FetchDataOptions) =>
fetchData<T>(path, 'GET', undefined, options);

/** GET data from Kobo API at url */
export const fetchGetUrl = async <T>(
url: string,
options?: FetchDataOptions
) => {
options = Object.assign({}, options, {prependRootUrl: false});
return fetchData<T>(url, 'GET', undefined, options);
};

/** POST data to Kobo API at path */
export const fetchPost = async <T>(
path: string,
Expand Down
3 changes: 1 addition & 2 deletions jsapp/js/components/header/accountMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {currentLang, stringToColor} from 'js/utils';
import envStore from 'js/envStore';
import type {LabelValuePair} from 'js/dataInterface';
import {dataInterface} from 'js/dataInterface';
import {actions} from 'js/actions';
import {ACCOUNT_ROUTES} from 'jsapp/js/account/routes';
import {isAnyRouteBlockerActive} from 'js/router/routerUtils';

Expand Down Expand Up @@ -143,7 +142,7 @@ export default function AccountMenu() {
</bem.AccountBox__menuLI>

<bem.AccountBox__menuLI m={'logout'} key='4'>
<bem.AccountBox__menuLink onClick={actions.auth.logout}>
<bem.AccountBox__menuLink onClick={sessionStore.logOut}>
<i className='k-icon k-icon-logout' />
{t('Logout')}
</bem.AccountBox__menuLink>
Expand Down
6 changes: 3 additions & 3 deletions jsapp/js/dataInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -681,10 +681,10 @@ export interface AccountResponse {
*/
validated_password: boolean;
/**
* The date when TOS was accepted by user. Will be `null` if given user has
* not accepted latest TOS.
* This will be `true` for user who accepted the latest TOS. If it's missing
* or `false`, it means that the latest TOS was not accepted.
*/
tos_accepted_date: string | null;
accepted_tos?: boolean;
extra_details: {
name: string;
gender: string;
Expand Down
18 changes: 17 additions & 1 deletion jsapp/js/envStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ interface EnvironmentResponse {
enable_custom_password_guidance_text: boolean;
custom_password_localized_help_text: string;
enable_password_entropy_meter: boolean;
/**
* Whether the TOS message is defined. This causes the whole TOS Screen checks
* to be put into motion; i.e. when this is `false` we don't bother to check
* if we should display TOS Screen to user :)
*/
terms_of_service__sitewidemessage__exists: boolean;
}

/*
Expand Down Expand Up @@ -84,7 +90,7 @@ type ProjectMetadataFieldKey =
| 'operational_purpose'
| 'collects_pii';

class EnvStoreData {
export class EnvStoreData {
public terms_of_service_url = '';
public privacy_policy_url = '';
public source_code_url = '';
Expand Down Expand Up @@ -120,6 +126,7 @@ class EnvStoreData {
public enable_custom_password_guidance_text = false;
public custom_password_localized_help_text = '';
public enable_password_entropy_meter = false;
public terms_of_service__sitewidemessage__exists = false;

getProjectMetadataField(
fieldName: ProjectMetadataFieldKey
Expand Down Expand Up @@ -152,6 +159,12 @@ class EnvStoreData {
return dict;
}

public getUserMetadataRequiredFieldNames(): UserFieldName[] {
return this.user_metadata_fields
.filter((item) => item.required)
.map((item) => item.name);
}

public getUserMetadataFieldNames(): UserFieldName[] {
return this.user_metadata_fields.map((item) => item.name);
}
Expand Down Expand Up @@ -235,6 +248,9 @@ class EnvStore {
this.data.enable_password_entropy_meter =
response.enable_password_entropy_meter;

this.data.terms_of_service__sitewidemessage__exists =
response.terms_of_service__sitewidemessage__exists;

this.isReady = true;
}

Expand Down
7 changes: 5 additions & 2 deletions jsapp/js/router/routerUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import {ROUTES, PATHS} from 'js/router/routerConstants';
import {PROJECTS_ROUTES} from 'js/projects/routes';
import sessionStore from 'js/stores/session';
import envStore from 'js/envStore';

/**
* Returns login url with a `next` parameter - after logging in, the app will
Expand Down Expand Up @@ -256,9 +257,11 @@ export function isInvalidatedPasswordRouteBlockerActive() {
/** TOSAgreement is displayed when user has not accepted latest TOS. */
export function isTOSAgreementRouteBlockerActive() {
return (
envStore.data.terms_of_service__sitewidemessage__exists &&
sessionStore.isLoggedIn &&
'tos_accepted_date' in sessionStore.currentAccount &&
typeof sessionStore.currentAccount.tos_accepted_date !== 'string'
// We check for email, because `currentAccount` can be two different things
'email' in sessionStore.currentAccount &&
sessionStore.currentAccount.accepted_tos !== true
);
}

Expand Down
9 changes: 5 additions & 4 deletions jsapp/js/router/tosAgreement.component.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, {useState} from 'react';
import Icon from 'js/components/common/icon';
import Button from 'js/components/common/button';
import React from 'react';
import styles from './tosAgreement.module.scss';
import BasicLayout from './basicLayout.component';
import TOSForm from 'js/tos/tosForm.component';

/**
* This is a route blocker component to be used for accounts that have not
Expand All @@ -12,7 +11,9 @@ import BasicLayout from './basicLayout.component';
export default function TOSAgreement() {
return (
<BasicLayout>
<div className={styles.root}>TOS agreement here :)</div>
<div className={styles.root}>
<TOSForm />
</div>
</BasicLayout>
);
}
21 changes: 14 additions & 7 deletions jsapp/js/stores/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@ class SessionStore {
action(
'verifyLoginSuccess',
(account: AccountResponse | {message: string}) => {
// TEMP
// Override the response to cause TOS Screen to appear
if ('email' in account) {
account.tos_accepted_date = null;
}
// END TEMP

this.isPending = false;
this.isInitialLoadComplete = true;
if ('email' in account) {
Expand Down Expand Up @@ -89,6 +82,20 @@ class SessionStore {
);
}

public logOut() {
dataInterface.logout().then(
action('logOutSuccess', () => {
// Reload so a new CSRF token is issued
window.setTimeout(() => {
window.location.replace('');
}, 1);
}),
action('logOutFailed', () => {
console.error('logout failed for some reason. what should happen now?');
}),
);
}

private saveUiLanguage() {
// We want to save the language if it differs from the one we saved or if
// none is saved yet.
Expand Down
Loading

0 comments on commit 7c38074

Please sign in to comment.