Skip to content

Commit a1445dc

Browse files
committed
MOBILE-3320 config: BUILD and CONFIG constants
Generate constants from webpack script to support jsonc files and read environment config
1 parent 51c1e42 commit a1445dc

25 files changed

+207
-109
lines changed

.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.js

.eslintrc.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
var appConfig = {
1+
const appConfig = {
22
env: {
33
browser: true,
44
es6: true,

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@ npm-debug.log*
2828
/platforms
2929
/plugins
3030
/www
31+
32+
/config/config.*.json

.vscode/settings.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
3+
"files.associations": {
4+
"config.json": "jsonc",
5+
"config.*.json": "jsonc",
6+
},
7+
8+
}

angular.json

-6
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,6 @@
4646
},
4747
"configurations": {
4848
"production": {
49-
"fileReplacements": [
50-
{
51-
"replace": "src/environments/environment.ts",
52-
"with": "src/environments/environment.prod.ts"
53-
}
54-
],
5549
"optimization": true,
5650
"outputHashing": "all",
5751
"sourceMap": false,

src/app/config.json config/config.json

+11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
1+
/**
2+
* Application config.
3+
*
4+
* You can create your own environment files such as "config.prod.json" and "config.dev.json"
5+
* to override some values. The values will be merged, so you don't need to duplicate everything
6+
* in this file.
7+
*/
8+
19
{
210
"app_id": "com.moodle.moodlemobile",
311
"appname": "Moodle Mobile",
412
"desktopappname": "Moodle Desktop",
513
"versioncode": 3930,
14+
15+
// @todo This could be read from package.json.
616
"versionname": "3.9.3-dev",
17+
718
"cache_update_frequency_usually": 420000,
819
"cache_update_frequency_often": 1200000,
920
"cache_update_frequency_sometimes": 3600000,

config/utils.js

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// (C) Copyright 2015 Moodle Pty Ltd.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
const { execSync } = require('child_process');
16+
const { resolve } = require('path');
17+
18+
export function getConfig(environment) {
19+
const { parse: parseJsonc } = require('jsonc-parser');
20+
const { readFileSync, existsSync } = require('fs');
21+
const envSuffixesMap = {
22+
testing: ['test', 'testing'],
23+
development: ['dev', 'development'],
24+
production: ['prod', 'production'],
25+
};
26+
const config = parseJsonc(readFileSync(resolve('config/config.json')).toString());
27+
const envSuffixes = (envSuffixesMap[environment] || []);
28+
const envConfigPath = envSuffixes.map(suffix => resolve(`config/config.${suffix}.json`)).find(existsSync);
29+
30+
if (envConfigPath) {
31+
const envConfig = parseJsonc(readFileSync(envConfigPath).toString());
32+
33+
for (const [key, value] of Object.entries(envConfig)) {
34+
config[key] = value;
35+
}
36+
}
37+
38+
return config;
39+
}
40+
41+
export function getBuild(environment) {
42+
return {
43+
environment,
44+
isProduction: environment === 'production',
45+
lastCommitHash: execSync('git log -1 --pretty=format:"%H"').toString(),
46+
compilationTime: Date.now(),
47+
};
48+
}

config/webpack.config.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
const { webpack } = require('webpack');
15+
const webpack = require('webpack');
16+
const { getConfig, getBuild } = require('./utils');
1617
const { resolve } = require('path');
1718

18-
module.exports = (config, options, targetOptions) => {
19+
module.exports = config => {
1920
config.resolve.alias['@'] = resolve('src');
2021
config.resolve.alias['@addon'] = resolve('src/app/addon');
2122
config.resolve.alias['@app'] = resolve('src/app');
@@ -27,5 +28,14 @@ module.exports = (config, options, targetOptions) => {
2728
config.resolve.alias['@services'] = resolve('src/app/services');
2829
config.resolve.alias['@singletons'] = resolve('src/app/singletons');
2930

31+
config.plugins.push(
32+
new webpack.DefinePlugin({
33+
'window.MoodleApp': {
34+
CONFIG: JSON.stringify(getConfig(process.env.NODE_ENV || 'development')),
35+
BUILD: JSON.stringify(getBuild(process.env.NODE_ENV || 'development')),
36+
},
37+
}),
38+
);
39+
3040
return config;
3141
};

package-lock.json

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@
144144
"gulp-slash": "^1.1.3",
145145
"jest": "^26.5.0",
146146
"jest-preset-angular": "^8.3.1",
147+
"jsonc-parser": "^2.3.1",
147148
"ts-jest": "^26.4.1",
148149
"ts-node": "~8.3.0",
149150
"typescript": "~3.9.5"

src/app/classes/site.ts

+7-8
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import { CoreTimeUtils } from '@services/utils/time';
2626
import { CoreUrlUtils, CoreUrlParams } from '@services/utils/url';
2727
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
2828
import { CoreConstants } from '@core/constants';
29-
import CoreConfigConstants from '@app/config.json';
3029
import { SQLiteDB } from '@classes/sqlitedb';
3130
import { CoreError } from '@classes/errors/error';
3231
import { CoreWSError } from '@classes/errors/wserror';
@@ -73,10 +72,10 @@ export class CoreSite {
7372

7473
// Possible cache update frequencies.
7574
protected readonly UPDATE_FREQUENCIES = [
76-
CoreConfigConstants.cache_update_frequency_usually || 420000,
77-
CoreConfigConstants.cache_update_frequency_often || 1200000,
78-
CoreConfigConstants.cache_update_frequency_sometimes || 3600000,
79-
CoreConfigConstants.cache_update_frequency_rarely || 43200000,
75+
CoreConstants.CONFIG.cache_update_frequency_usually || 420000,
76+
CoreConstants.CONFIG.cache_update_frequency_often || 1200000,
77+
CoreConstants.CONFIG.cache_update_frequency_sometimes || 3600000,
78+
CoreConstants.CONFIG.cache_update_frequency_rarely || 43200000,
8079
];
8180

8281
// Rest of variables.
@@ -227,9 +226,9 @@ export class CoreSite {
227226
* @return Site name.
228227
*/
229228
getSiteName(): string {
230-
if (CoreConfigConstants.sitename) {
229+
if (CoreConstants.CONFIG.sitename) {
231230
// Overridden by config.
232-
return CoreConfigConstants.sitename;
231+
return CoreConstants.CONFIG.sitename;
233232
} else {
234233
return this.infos?.sitename || '';
235234
}
@@ -1284,7 +1283,7 @@ export class CoreSite {
12841283
*/
12851284
async checkLocalMobilePlugin(retrying?: boolean): Promise<LocalMobileResponse> {
12861285
const checkUrl = this.siteUrl + '/local/mobile/check.php';
1287-
const service = CoreConfigConstants.wsextservice;
1286+
const service = CoreConstants.CONFIG.wsextservice;
12881287

12891288
if (!service) {
12901289
// External service not defined.

src/app/core/constants.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const enum ContextLevel {
2828
* Static class to contain all the core constants.
2929
*/
3030
export class CoreConstants {
31+
3132
/* eslint-disable max-len */
3233

3334
static readonly SECONDS_YEAR = 31536000;
@@ -100,9 +101,14 @@ export class CoreConstants {
100101
static readonly FEATURE_SHOW_DESCRIPTION = 'showdescription'; // True if module can show description on course main page.
101102
static readonly FEATURE_USES_QUESTIONS = 'usesquestions'; // True if module uses the question bank.
102103

103-
// Possbile archetypes for modules.
104+
// Possible archetypes for modules.
104105
static readonly MOD_ARCHETYPE_OTHER = 0; // Unspecified module archetype.
105106
static readonly MOD_ARCHETYPE_RESOURCE = 1; // Resource-like type module.
106107
static readonly MOD_ARCHETYPE_ASSIGNMENT = 2; // Assignment module archetype.
107108
static readonly MOD_ARCHETYPE_SYSTEM = 3; // System (not user-addable) module archetype.
109+
110+
// Config & environment constants.
111+
static readonly CONFIG = (window as unknown as MoodleAppWindow).MoodleApp.CONFIG; // Data parsed from config.json files.
112+
static readonly BUILD = (window as unknown as MoodleAppWindow).MoodleApp.BUILD; // Environment info.
113+
108114
}

src/app/services/app.ts

+16-16
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { CoreDB } from '@services/db';
2020
import { CoreEvents, CoreEventsProvider } from '@services/events';
2121
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
2222
import { SQLiteDB, SQLiteDBTableSchema } from '@classes/sqlitedb';
23-
import CoreConfigConstants from '@app/config.json';
23+
import { CoreConstants } from '@core/constants';
2424

2525
import { makeSingleton, Keyboard, Network, StatusBar, Platform } from '@singletons/core.singletons';
2626
import { CoreLogger } from '@singletons/logger';
@@ -645,21 +645,21 @@ export class CoreAppProvider {
645645
* Set StatusBar color depending on platform.
646646
*/
647647
setStatusBarColor(): void {
648-
if (typeof CoreConfigConstants.statusbarbgios == 'string' && this.isIOS()) {
648+
if (typeof CoreConstants.CONFIG.statusbarbgios == 'string' && this.isIOS()) {
649649
// IOS Status bar properties.
650650
StatusBar.instance.overlaysWebView(false);
651-
StatusBar.instance.backgroundColorByHexString(CoreConfigConstants.statusbarbgios);
652-
CoreConfigConstants.statusbarlighttextios ? StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
653-
} else if (typeof CoreConfigConstants.statusbarbgandroid == 'string' && this.isAndroid()) {
651+
StatusBar.instance.backgroundColorByHexString(CoreConstants.CONFIG.statusbarbgios);
652+
CoreConstants.CONFIG.statusbarlighttextios ? StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
653+
} else if (typeof CoreConstants.CONFIG.statusbarbgandroid == 'string' && this.isAndroid()) {
654654
// Android Status bar properties.
655-
StatusBar.instance.backgroundColorByHexString(CoreConfigConstants.statusbarbgandroid);
656-
CoreConfigConstants.statusbarlighttextandroid ?
655+
StatusBar.instance.backgroundColorByHexString(CoreConstants.CONFIG.statusbarbgandroid);
656+
CoreConstants.CONFIG.statusbarlighttextandroid ?
657657
StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
658-
} else if (typeof CoreConfigConstants.statusbarbg == 'string') {
658+
} else if (typeof CoreConstants.CONFIG.statusbarbg == 'string') {
659659
// Generic Status bar properties.
660660
this.isIOS() && StatusBar.instance.overlaysWebView(false);
661-
StatusBar.instance.backgroundColorByHexString(CoreConfigConstants.statusbarbg);
662-
CoreConfigConstants.statusbarlighttext ? StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
661+
StatusBar.instance.backgroundColorByHexString(CoreConstants.CONFIG.statusbarbg);
662+
CoreConstants.CONFIG.statusbarlighttext ? StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
663663
} else {
664664
// Default Status bar properties.
665665
this.isAndroid() ? StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
@@ -670,14 +670,14 @@ export class CoreAppProvider {
670670
* Reset StatusBar color if any was set.
671671
*/
672672
resetStatusBarColor(): void {
673-
if (typeof CoreConfigConstants.statusbarbgremotetheme == 'string' &&
674-
((typeof CoreConfigConstants.statusbarbgios == 'string' && this.isIOS()) ||
675-
(typeof CoreConfigConstants.statusbarbgandroid == 'string' && this.isAndroid()) ||
676-
typeof CoreConfigConstants.statusbarbg == 'string')) {
673+
if (typeof CoreConstants.CONFIG.statusbarbgremotetheme == 'string' &&
674+
((typeof CoreConstants.CONFIG.statusbarbgios == 'string' && this.isIOS()) ||
675+
(typeof CoreConstants.CONFIG.statusbarbgandroid == 'string' && this.isAndroid()) ||
676+
typeof CoreConstants.CONFIG.statusbarbg == 'string')) {
677677
// If the status bar has been overriden and there's a fallback color for remote themes, use it now.
678678
this.isIOS() && StatusBar.instance.overlaysWebView(false);
679-
StatusBar.instance.backgroundColorByHexString(CoreConfigConstants.statusbarbgremotetheme);
680-
CoreConfigConstants.statusbarlighttextremotetheme ?
679+
StatusBar.instance.backgroundColorByHexString(CoreConstants.CONFIG.statusbarbgremotetheme);
680+
CoreConstants.CONFIG.statusbarlighttextremotetheme ?
681681
StatusBar.instance.styleLightContent() : StatusBar.instance.styleDefault();
682682
}
683683
}

src/app/services/file.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { CoreWSExternalFile } from '@services/ws';
2121
import { CoreMimetypeUtils } from '@services/utils/mimetype';
2222
import { CoreTextUtils } from '@services/utils/text';
2323
import { CoreUtils } from '@services/utils/utils';
24-
import CoreConfigConstants from '@app/config.json';
24+
import { CoreConstants } from '@core/constants';
2525
import { CoreError } from '@classes/errors/error';
2626

2727
import { CoreLogger } from '@singletons/logger';
@@ -1227,7 +1227,7 @@ export class CoreFileProvider {
12271227
return src;
12281228
}
12291229

1230-
return src.replace(CoreConfigConstants.ioswebviewscheme + '://localhost/_app_file_', 'file://');
1230+
return src.replace(CoreConstants.CONFIG.ioswebviewscheme + '://localhost/_app_file_', 'file://');
12311231
}
12321232

12331233
/**

src/app/services/lang.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import { Injectable } from '@angular/core';
1616

17-
import CoreConfigConstants from '@app/config.json';
17+
import { CoreConstants } from '@core/constants';
1818
import { LangChangeEvent } from '@ngx-translate/core';
1919
import { CoreAppProvider } from '@services/app';
2020
import { CoreConfig } from '@services/config';
@@ -29,7 +29,7 @@ import * as moment from 'moment';
2929
export class CoreLangProvider {
3030

3131
protected fallbackLanguage = 'en'; // Always use English as fallback language since it contains all strings.
32-
protected defaultLanguage = CoreConfigConstants.default_lang || 'en'; // Lang to use if device lang not valid or is forced.
32+
protected defaultLanguage = CoreConstants.CONFIG.default_lang || 'en'; // Lang to use if device lang not valid or is forced.
3333
protected currentLanguage?: string; // Save current language in a variable to speed up the get function.
3434
protected customStrings: CoreLanguageObject = {}; // Strings defined using the admin tool.
3535
protected customStringsRaw?: string;
@@ -252,21 +252,21 @@ export class CoreLangProvider {
252252
}
253253

254254
// User hasn't defined a language. If default language is forced, use it.
255-
if (CoreConfigConstants.default_lang && CoreConfigConstants.forcedefaultlanguage) {
256-
return CoreConfigConstants.default_lang;
255+
if (CoreConstants.CONFIG.default_lang && CoreConstants.CONFIG.forcedefaultlanguage) {
256+
return CoreConstants.CONFIG.default_lang;
257257
}
258258

259259
// No forced language, try to get current language from browser.
260260
let preferredLanguage = navigator.language.toLowerCase();
261261
if (preferredLanguage.indexOf('-') > -1) {
262262
// Language code defined by locale has a dash, like en-US or es-ES. Check if it's supported.
263-
if (CoreConfigConstants.languages && typeof CoreConfigConstants.languages[preferredLanguage] == 'undefined') {
263+
if (CoreConstants.CONFIG.languages && typeof CoreConstants.CONFIG.languages[preferredLanguage] == 'undefined') {
264264
// Code is NOT supported. Fallback to language without dash. E.g. 'en-US' would fallback to 'en'.
265265
preferredLanguage = preferredLanguage.substr(0, preferredLanguage.indexOf('-'));
266266
}
267267
}
268268

269-
if (typeof CoreConfigConstants.languages[preferredLanguage] == 'undefined') {
269+
if (typeof CoreConstants.CONFIG.languages[preferredLanguage] == 'undefined') {
270270
// Language not supported, use default language.
271271
return this.defaultLanguage;
272272
}

src/app/services/local-notifications.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import { CoreSite } from '@classes/site';
2626
import { CoreQueueRunner } from '@classes/queue-runner';
2727
import { CoreError } from '@classes/errors/error';
2828
import { CoreConstants } from '@core/constants';
29-
import CoreConfigConstants from '@app/config.json';
3029
import { makeSingleton, NgZone, Platform, Translate, LocalNotifications, Push, Device } from '@singletons/core.singletons';
3130
import { CoreLogger } from '@singletons/logger';
3231

@@ -611,7 +610,7 @@ export class CoreLocalNotificationsProvider {
611610
if (CoreApp.instance.isAndroid()) {
612611
notification.icon = notification.icon || 'res://icon';
613612
notification.smallIcon = notification.smallIcon || 'res://smallicon';
614-
notification.color = notification.color || CoreConfigConstants.notificoncolor;
613+
notification.color = notification.color || CoreConstants.CONFIG.notificoncolor;
615614

616615
if (notification.led !== false) {
617616
let ledColor = 'FF9900';

0 commit comments

Comments
 (0)