Skip to content

Commit

Permalink
Merge pull request #4689 from kobotoolbox/3910-fix-replace-support-em…
Browse files Browse the repository at this point in the history
…ail-function

Fix replaceSupportEmail function
  • Loading branch information
magicznyleszek authored Nov 1, 2023
2 parents 1350305 + 9466cf4 commit a3b435d
Show file tree
Hide file tree
Showing 23 changed files with 180 additions and 197 deletions.
3 changes: 2 additions & 1 deletion jsapp/js/account/accountSettingsRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import sessionStore from 'js/stores/session';
import './accountSettings.scss';
import Checkbox from '../components/common/checkbox';
import TextBox from '../components/common/textBox';
import {addRequiredToLabel, notify, stringToColor} from '../utils';
import {notify, stringToColor} from 'js/utils';
import {addRequiredToLabel} from 'js/textUtils';
import envStore from '../envStore';
import WrappedSelect from '../components/common/wrappedSelect';
import {dataInterface} from '../dataInterface';
Expand Down
2 changes: 1 addition & 1 deletion jsapp/js/account/subscriptionStore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {makeAutoObservable} from 'mobx';
import {handleApiFail} from 'js/utils';
import {handleApiFail} from 'js/api';
import {ROOT_URL} from 'js/constants';
import {fetchGet} from 'jsapp/js/api';
import type {PaginatedResponse} from 'js/dataInterface';
Expand Down
12 changes: 0 additions & 12 deletions jsapp/js/actions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,6 @@ interface GetProcessingSubmissionsCompletedDefinition extends Function {
listen: (callback: (response: GetProcessingSubmissionsResponse) => void) => Function;
}

interface GetEnvironmentDefinition extends Function {
(): void;
completed: GetEnvironmentCompletedDefinition;
failed: GenericFailedDefinition;
}

interface GetEnvironmentCompletedDefinition extends Function {
(response: EnvironmentResponse): void;
listen: (callback: (response: EnvironmentResponse) => void) => Function;
}

interface LoadAssetDefinition extends Function {
(params: {id: string}): void;
completed: LoadAssetCompletedDefinition;
Expand Down Expand Up @@ -107,7 +96,6 @@ export namespace actions {
routeUpdate: GenericCallbackDefinition;
};
const auth: {
getEnvironment: GetEnvironmentDefinition;
verifyLogin: {
loggedin: GenericCallbackDefinition;
};
Expand Down
18 changes: 2 additions & 16 deletions jsapp/js/actions.es6
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ import submissionsActions from './actions/submissions';
import formMediaActions from './actions/mediaActions';
import exportsActions from './actions/exportsActions';
import dataShareActions from './actions/dataShareActions';
import {
notify,
replaceSupportEmail,
} from 'utils';
import {notify} from 'js/utils';
import {replaceSupportEmail} from 'js/textUtils';

// Configure Reflux
Reflux.use(RefluxPromise(window.Promise));
Expand All @@ -45,7 +43,6 @@ actions.auth = Reflux.createActions({
verifyLogin: {children: ['loggedin', 'anonymous', 'failed']},
logout: {children: ['completed', 'failed']},
changePassword: {children: ['completed', 'failed']},
getEnvironment: {children: ['completed', 'failed']},
getApiToken: {children: ['completed', 'failed']},
});

Expand Down Expand Up @@ -466,17 +463,6 @@ actions.auth.changePassword.failed.listen(() => {
notify(t('failed to change password'), 'error');
});

actions.auth.getEnvironment.listen(function(){
dataInterface.environment()
.done((data)=>{
actions.auth.getEnvironment.completed(data);
})
.fail(actions.auth.getEnvironment.failed);
});
actions.auth.getEnvironment.failed.listen(() => {
notify(t('failed to load environment data'), 'error');
});

actions.auth.getApiToken.listen(() => {
dataInterface.apiToken()
.done((response) => {
Expand Down
47 changes: 46 additions & 1 deletion jsapp/js/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,52 @@
import {ROOT_URL} from './constants';
import type {Json} from './components/common/common.interfaces';
import type {FailResponse} from 'js/dataInterface';
import {handleApiFail} from 'js/utils';
import {notify} from './utils';

/**
* Useful for handling the fail responses from API. Its main goal is to display
* a helpful error toast notification and to pass the error message to Raven.
*
* It can detect if we got HTML string as response and uses a generic message
* instead of spitting it out.
*/
export function handleApiFail(response: FailResponse) {
// Avoid displaying toast when purposefuly aborted a request
if (response.status === 0 && response.statusText === 'abort') {
return;
}

let message = response.responseText;

// Detect if response is HTML code string
if (
typeof message === 'string' &&
message.includes('</html>') &&
message.includes('</body>')
) {
// Try plucking the useful error message from the HTML string - this works
// for Werkzeug Debugger only. It is being used on development environment,
// on production this would most probably result in undefined message (and
// thus falling back to the generic message below).
const htmlDoc = new DOMParser().parseFromString(message, 'text/html');
message = htmlDoc.getElementsByClassName('errormsg')?.[0]?.innerHTML;
}

if (!message) {
message = t('An error occurred');
if (response.status || response.statusText) {
message += ` — ${response.status} ${response.statusText}`;
} else if (!window.navigator.onLine) {
// another general case — the original fetch response.message might have
// something more useful to say.
message += ' — ' + t('Your connection is offline');
}
}

notify.error(message);

window.Raven?.captureMessage(message);
}

const JSON_HEADER = 'application/json';

Expand Down
2 changes: 1 addition & 1 deletion jsapp/js/components/common/assetName.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import {getAssetDisplayName} from 'js/assetUtils';
import {hasLongWords} from 'js/utils';
import {hasLongWords} from 'js/textUtils';
import type {AssetResponse, ProjectViewAsset} from 'js/dataInterface';
import './assetName.scss';

Expand Down
2 changes: 1 addition & 1 deletion jsapp/js/components/languages/languagesListStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type {
PaginatedResponse,
FailResponse,
} from 'js/dataInterface';
import {handleApiFail} from 'js/utils';
import {handleApiFail} from 'js/api';
import {ROOT_URL} from 'js/constants';
import languagesStore from './languagesStore';
import type {ListLanguage} from './languagesStore';
Expand Down
6 changes: 2 additions & 4 deletions jsapp/js/components/modalForms/languageForm.es6
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@ import React from 'react';
import autoBind from 'react-autobind';
import bem from 'js/bem';
import TextBox from 'js/components/common/textBox';
import {
getLangAsObject,
toTitleCase
} from 'utils';
import {getLangAsObject} from 'js/utils';
import {toTitleCase} from 'js/textUtils';

/*
Properties:
Expand Down
4 changes: 2 additions & 2 deletions jsapp/js/components/modalForms/projectSettings.es6
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ import TemplatesList from 'js/components/templatesList';
import {actions} from 'js/actions';
import {dataInterface} from 'js/dataInterface';
import {
addRequiredToLabel,
escapeHtml,
isAValidUrl,
validFileTypes,
notify,
join,
} from 'utils';
} from 'js/utils';
import {addRequiredToLabel} from 'js/textUtils';
import {
NAME_MAX_LENGTH,
PROJECT_SETTINGS_CONTEXTS,
Expand Down
6 changes: 2 additions & 4 deletions jsapp/js/components/permissions/permValidator.es6
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ import autoBind from 'react-autobind';
import permConfig from './permConfig';
import {actions} from '../../actions';
import union from 'lodash.union';
import {
notify,
replaceSupportEmail
} from 'utils';
import {notify} from 'js/utils';
import {replaceSupportEmail} from 'js/textUtils';

const INVALID_PERMS_ERROR = t('The stored permissions are invalid. Please assign them again. If this problem persists, contact help@kobotoolbox.org');

Expand Down
6 changes: 2 additions & 4 deletions jsapp/js/components/permissions/sharingForm.es6
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ import {actions} from 'js/actions';
import bem from 'js/bem';
import LoadingSpinner from 'js/components/common/loadingSpinner';
import InlineMessage from 'js/components/common/inlineMessage';
import {
buildUserUrl,
replaceBracketsWithLink,
} from 'utils';
import {buildUserUrl} from 'js/utils';
import {replaceBracketsWithLink} from 'js/textUtils';
import {
ASSET_TYPES,
ANON_USERNAME,
Expand Down
2 changes: 1 addition & 1 deletion jsapp/js/components/support/helpBubbleStore.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import throttle from 'lodash.throttle';
import {makeAutoObservable, when} from 'mobx';
import type {PaginatedResponse, FailResponse} from 'js/dataInterface';
import {handleApiFail} from 'js/utils';
import {handleApiFail} from 'js/api';
import {ROOT_URL} from 'js/constants';
import sessionStore from 'js/stores/session';

Expand Down
37 changes: 0 additions & 37 deletions jsapp/js/dataInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -735,39 +735,6 @@ export interface TransxLanguages {
};
}

export interface EnvironmentResponse {
mfa_has_availability_list: boolean;
terms_of_service_url: string;
privacy_policy_url: string;
source_code_url: string;
support_email: string;
support_url: string;
community_url: string;
project_metadata_fields: EnvStoreFieldItem[];
user_metadata_fields: EnvStoreFieldItem[];
sector_choices: string[][];
operational_purpose_choices: string[][];
country_choices: string[][];
interface_languages: string[][];
transcription_languages: TransxLanguages;
translation_languages: TransxLanguages;
submission_placeholder: string;
frontend_min_retry_time: number;
frontend_max_retry_time: number;
asr_mt_features_enabled: boolean;
mfa_localized_help_text: string;
mfa_enabled: boolean;
mfa_per_user_availability: boolean;
mfa_code_length: number;
stripe_public_key: string | null;
social_apps: SocialApp[];
free_tier_thresholds: FreeTierThresholds;
free_tier_display: FreeTierDisplay;
enable_custom_password_guidance_text: boolean;
custom_password_localized_help_text: string;
enable_password_entropy_meter: boolean;
}

export interface AssetSubscriptionsResponse {
/** url of subscription */
url: string;
Expand Down Expand Up @@ -1782,8 +1749,4 @@ export const dataInterface: DataInterface = {
data: data,
});
},

environment(): JQuery.jqXHR<EnvironmentResponse> {
return $ajax({url: `${ROOT_URL}/environment/`});
},
};
75 changes: 62 additions & 13 deletions jsapp/js/envStore.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,45 @@
import {actions} from 'js/actions';
import type {
LabelValuePair,
TransxLanguages,
EnvironmentResponse,
FailResponse,
} from 'js/dataInterface';
import {makeAutoObservable} from 'mobx';
import {fetchGet, handleApiFail} from 'js/api';

const ENV_ENDPOINT = '/environment/';

interface EnvironmentResponse {
mfa_has_availability_list: boolean;
terms_of_service_url: string;
privacy_policy_url: string;
source_code_url: string;
support_email: string;
support_url: string;
community_url: string;
project_metadata_fields: EnvStoreFieldItem[];
user_metadata_fields: EnvStoreFieldItem[];
sector_choices: string[][];
operational_purpose_choices: string[][];
country_choices: string[][];
interface_languages: string[][];
transcription_languages: TransxLanguages;
translation_languages: TransxLanguages;
submission_placeholder: string;
frontend_min_retry_time: number;
frontend_max_retry_time: number;
asr_mt_features_enabled: boolean;
mfa_localized_help_text: string;
mfa_enabled: boolean;
mfa_per_user_availability: boolean;
mfa_code_length: number;
stripe_public_key: string | null;
social_apps: SocialApp[];
free_tier_thresholds: FreeTierThresholds;
free_tier_display: FreeTierDisplay;
enable_custom_password_guidance_text: boolean;
custom_password_localized_help_text: string;
enable_password_entropy_meter: boolean;
}

/*
* NOTE: This store is written to use MobX, but its imports do not need to be
Expand Down Expand Up @@ -76,7 +111,7 @@ class EnvStoreData {
storage: null,
data: null,
transcription_minutes: null,
translation_chars: null
translation_chars: null,
};
public free_tier_display: FreeTierDisplay = {name: null, feature_list: []};
public enable_custom_password_guidance_text = false;
Expand Down Expand Up @@ -122,9 +157,13 @@ class EnvStore {
constructor() {
makeAutoObservable(this);
this.data = new EnvStoreData();
this.fetchData();
}

actions.auth.getEnvironment.completed.listen(this.onGetEnvCompleted.bind(this));
actions.auth.getEnvironment();
async fetchData() {
// Error handling is done inside `fetchGet`
const response = await fetchGet<EnvironmentResponse>(ENV_ENDPOINT);
this.onGetEnvCompleted(response);
}

/**
Expand Down Expand Up @@ -161,23 +200,33 @@ class EnvStore {
this.data.free_tier_display = response.free_tier_display;

if (response.sector_choices) {
this.data.sector_choices = response.sector_choices.map(this.nestedArrToChoiceObjs);
this.data.sector_choices = response.sector_choices.map(
this.nestedArrToChoiceObjs
);
}
if (response.operational_purpose_choices) {
this.data.operational_purpose_choices = response.operational_purpose_choices.map(this.nestedArrToChoiceObjs);
this.data.operational_purpose_choices =
response.operational_purpose_choices.map(this.nestedArrToChoiceObjs);
}
if (response.country_choices) {
this.data.country_choices = response.country_choices.map(this.nestedArrToChoiceObjs);
this.data.country_choices = response.country_choices.map(
this.nestedArrToChoiceObjs
);
}
if (response.interface_languages) {
this.data.interface_languages = response.interface_languages.map(this.nestedArrToChoiceObjs);
this.data.interface_languages = response.interface_languages.map(
this.nestedArrToChoiceObjs
);
}

this.data.asr_mt_features_enabled = response.asr_mt_features_enabled;

this.data.enable_custom_password_guidance_text = response.enable_custom_password_guidance_text;
this.data.custom_password_localized_help_text = response.custom_password_localized_help_text;
this.data.enable_password_entropy_meter = response.enable_password_entropy_meter;
this.data.enable_custom_password_guidance_text =
response.enable_custom_password_guidance_text;
this.data.custom_password_localized_help_text =
response.custom_password_localized_help_text;
this.data.enable_password_entropy_meter =
response.enable_password_entropy_meter;

this.isReady = true;
}
Expand Down Expand Up @@ -207,4 +256,4 @@ class EnvStore {
* This store keeps all environment data (constants) like languages, countries,
* external urls…
*/
export default new EnvStore;
export default new EnvStore();
4 changes: 2 additions & 2 deletions jsapp/js/project/submissionsCountGraph.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import moment from 'moment';
import Chart from 'chart.js/auto';
import type {ChartConfiguration} from 'chart.js/auto';
import type {FailResponse} from 'js/dataInterface';
import {fetchGet} from 'js/api';
import {formatDate, handleApiFail} from 'js/utils';
import {fetchGet, handleApiFail} from 'js/api';
import {formatDate} from 'js/utils';
import LoadingSpinner from 'js/components/common/loadingSpinner';
import styles from './submissionsCountGraph.module.scss';

Expand Down
Loading

0 comments on commit a3b435d

Please sign in to comment.