commit
122bd8bbe8
|
@ -20,26 +20,22 @@ function print_success {
|
|||
}
|
||||
|
||||
function print_error {
|
||||
tput setaf 1; echo " ERROR: $1"
|
||||
tput setaf 0
|
||||
tput setaf 1; echo " ERROR: $1"; tput sgr0
|
||||
}
|
||||
|
||||
function print_ok {
|
||||
tput setaf 2; echo " OK: $1"
|
||||
tput setaf 2; echo " OK: $1"; tput sgr0
|
||||
echo
|
||||
tput setaf 0
|
||||
}
|
||||
|
||||
function print_message {
|
||||
tput setaf 3; echo "-------- $1"
|
||||
tput setaf 3; echo "-------- $1"; tput sgr0
|
||||
echo
|
||||
tput setaf 0
|
||||
}
|
||||
|
||||
function print_title {
|
||||
stepnumber=$(($stepnumber + 1))
|
||||
echo
|
||||
tput setaf 5; echo "$stepnumber $1"
|
||||
tput setaf 5; echo '=================='
|
||||
tput setaf 0
|
||||
tput setaf 5; echo "$stepnumber $1"; tput sgr0
|
||||
tput setaf 5; echo '=================='; tput sgr0
|
||||
}
|
|
@ -1567,7 +1567,7 @@
|
|||
"core.login.changepassword": "moodle",
|
||||
"core.login.changepasswordbutton": "local_moodlemobileapp",
|
||||
"core.login.changepasswordhelp": "local_moodlemobileapp",
|
||||
"core.login.changepassowrdinstructions": "local_moodlemobileapp",
|
||||
"core.login.changepasswordinstructions": "local_moodlemobileapp",
|
||||
"core.login.changepasswordlogoutinstructions": "local_moodlemobileapp",
|
||||
"core.login.changepasswordreconnectinstructions": "local_moodlemobileapp",
|
||||
"core.login.checksiteversion": "local_moodlemobileapp",
|
||||
|
@ -1925,6 +1925,8 @@
|
|||
"core.unknown": "local_moodlemobileapp",
|
||||
"core.unlimited": "moodle",
|
||||
"core.unzipping": "local_moodlemobileapp",
|
||||
"core.updaterequired": "local_moodlemobileapp",
|
||||
"core.updaterequireddesc": "local_moodlemobileapp",
|
||||
"core.upgraderunning": "error",
|
||||
"core.user": "moodle",
|
||||
"core.user.address": "moodle",
|
||||
|
|
|
@ -1562,10 +1562,10 @@
|
|||
"core.login.auth_email": "Email-based self-registration",
|
||||
"core.login.authenticating": "Authenticating",
|
||||
"core.login.cancel": "Cancel",
|
||||
"core.login.changepassowrdinstructions": "You cannot change your password in the app. Please click the following button to open the site in a web browser to change your password. Take into account you need to close the browser after changing the password as you will not be redirected to the app.",
|
||||
"core.login.changepassword": "Change password",
|
||||
"core.login.changepasswordbutton": "Open the change password page",
|
||||
"core.login.changepasswordhelp": "If you have problems changing your password, please contact your site administrator. \"Site Administrators\" are the people who manages the Moodle at your school/university/company or learning organisation. If you don't know how to contact them, please contact your teachers/trainers.",
|
||||
"core.login.changepasswordinstructions": "You cannot change your password in the app. Please click the following button to open the site in a web browser to change your password. Take into account you need to close the browser after changing the password as you will not be redirected to the app.",
|
||||
"core.login.changepasswordlogoutinstructions": "If you prefer to change site or log out, please click the following button:",
|
||||
"core.login.changepasswordreconnectinstructions": "Click the following button to reconnect to the site. (Take into account that if you didn't change your password successfully, you would return to the previous screen).",
|
||||
"core.login.checksiteversion": "Check that your site uses Moodle 3.1 or later.",
|
||||
|
@ -1920,6 +1920,8 @@
|
|||
"core.unknown": "Unknown",
|
||||
"core.unlimited": "Unlimited",
|
||||
"core.unzipping": "Unzipping",
|
||||
"core.updaterequired": "App update required",
|
||||
"core.updaterequireddesc": "Please update your app to version {{$a}}",
|
||||
"core.upgraderunning": "Site is being upgraded, please retry later.",
|
||||
"core.user": "User",
|
||||
"core.user.address": "Address",
|
||||
|
|
|
@ -25,8 +25,8 @@ ion-app.app-root {
|
|||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
|
||||
> .core-loading-content > *,
|
||||
> .core-loading-content-loading > * {
|
||||
> .core-loading-content > *:not[padding],
|
||||
> .core-loading-content-loading > *:not[padding] {
|
||||
@include safe-area-padding-horizontal(0px, 0px);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
"changepassword": "Change password",
|
||||
"changepasswordbutton": "Open the change password page",
|
||||
"changepasswordhelp": "If you have problems changing your password, please contact your site administrator. \"Site Administrators\" are the people who manages the Moodle at your school/university/company or learning organisation. If you don't know how to contact them, please contact your teachers/trainers.",
|
||||
"changepassowrdinstructions": "You cannot change your password in the app. Please click the following button to open the site in a web browser to change your password. Take into account you need to close the browser after changing the password as you will not be redirected to the app.",
|
||||
"changepasswordinstructions": "You cannot change your password in the app. Please click the following button to open the site in a web browser to change your password. Take into account you need to close the browser after changing the password as you will not be redirected to the app.",
|
||||
"changepasswordlogoutinstructions": "If you prefer to change site or log out, please click the following button:",
|
||||
"changepasswordreconnectinstructions": "Click the following button to reconnect to the site. (Take into account that if you didn't change your password successfully, you would return to the previous screen).",
|
||||
"confirmdeletesite": "Are you sure you want to delete the site {{sitename}}?",
|
||||
|
|
|
@ -13,12 +13,15 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CoreCronDelegate } from '@providers/cron';
|
||||
import { CoreLoginHelperProvider } from './providers/helper';
|
||||
import { CoreLoginCronHandler } from './providers/cron-handler';
|
||||
import { CoreLoginSitesPageModule } from './pages/sites/sites.module';
|
||||
|
||||
// List of providers.
|
||||
export const CORE_LOGIN_PROVIDERS = [
|
||||
CoreLoginHelperProvider
|
||||
CoreLoginHelperProvider,
|
||||
CoreLoginCronHandler
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@ -29,4 +32,9 @@ export const CORE_LOGIN_PROVIDERS = [
|
|||
],
|
||||
providers: CORE_LOGIN_PROVIDERS
|
||||
})
|
||||
export class CoreLoginModule {}
|
||||
export class CoreLoginModule {
|
||||
constructor(cronDelegate: CoreCronDelegate, cronHandler: CoreLoginCronHandler) {
|
||||
// Register handlers.
|
||||
cronDelegate.register(cronHandler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<ion-list>
|
||||
<ion-item text-wrap *ngIf="!changingPassword">
|
||||
<h2>{{ 'core.login.forcepasswordchangenotice' | translate }}</h2>
|
||||
<p padding-vertical>{{ 'core.login.changepassowrdinstructions' | translate }}</p>
|
||||
<p padding-vertical>{{ 'core.login.changepasswordinstructions' | translate }}</p>
|
||||
<button text-wrap ion-button block (click)="openChangePasswordPage()">{{ 'core.login.changepasswordbutton' | translate }}</button>
|
||||
</ion-item>
|
||||
<ion-item text-wrap *ngIf="changingPassword">
|
||||
|
|
|
@ -85,15 +85,22 @@ export class CoreLoginInitPage {
|
|||
*/
|
||||
protected loadPage(): Promise<any> {
|
||||
if (this.sitesProvider.isLoggedIn()) {
|
||||
if (!this.loginHelper.isSiteLoggedOut()) {
|
||||
// User is logged in, go to site initial page.
|
||||
return this.loginHelper.goToSiteInitialPage();
|
||||
} else {
|
||||
// The site is marked as logged out. Logout and try again.
|
||||
if (this.loginHelper.isSiteLoggedOut()) {
|
||||
return this.sitesProvider.logout().then(() => {
|
||||
return this.loadPage();
|
||||
});
|
||||
}
|
||||
|
||||
return this.sitesProvider.getCurrentSite().getPublicConfig().catch(() => {
|
||||
return {};
|
||||
}).then((config) => {
|
||||
return this.sitesProvider.checkRequiredMinimumVersion(config).then(() => {
|
||||
// User is logged in, go to site initial page.
|
||||
return this.loginHelper.goToSiteInitialPage();
|
||||
}).catch(() => {
|
||||
return this.loadPage();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return this.navCtrl.setRoot('CoreLoginSitesPage');
|
||||
|
|
|
@ -82,16 +82,20 @@ export class CoreLoginReconnectPage {
|
|||
this.siteUrl = site.infos.siteurl;
|
||||
this.siteName = site.getSiteName();
|
||||
|
||||
// Check logoURL if user avatar is not set.
|
||||
if (this.site.avatar.startsWith(site.infos.siteurl + '/theme/image.php')) {
|
||||
this.site.avatar = false;
|
||||
return site.getPublicConfig().then((config) => {
|
||||
return this.sitesProvider.checkRequiredMinimumVersion(config).then(() => {
|
||||
// Check logoURL if user avatar is not set.
|
||||
if (this.site.avatar.startsWith(site.infos.siteurl + '/theme/image.php')) {
|
||||
this.site.avatar = false;
|
||||
|
||||
return site.getPublicConfig().then((config) => {
|
||||
this.logoUrl = config.logourl || config.compactlogourl;
|
||||
this.logoUrl = config.logourl || config.compactlogourl;
|
||||
}
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
this.cancel();
|
||||
});
|
||||
}
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}).catch(() => {
|
||||
// Shouldn't happen. Just leave the view.
|
||||
this.cancel();
|
||||
|
|
|
@ -112,18 +112,21 @@ export class CoreLoginSitePage {
|
|||
} else {
|
||||
// Not a demo site.
|
||||
this.sitesProvider.checkSite(url).then((result) => {
|
||||
return this.sitesProvider.checkRequiredMinimumVersion(result.config).then(() => {
|
||||
if (result.warning) {
|
||||
this.domUtils.showErrorModal(result.warning, true, 4000);
|
||||
}
|
||||
|
||||
if (result.warning) {
|
||||
this.domUtils.showErrorModal(result.warning, true, 4000);
|
||||
}
|
||||
|
||||
if (this.loginHelper.isSSOLoginNeeded(result.code)) {
|
||||
// SSO. User needs to authenticate in a browser.
|
||||
this.loginHelper.confirmAndOpenBrowserForSSOLogin(
|
||||
result.siteUrl, result.code, result.service, result.config && result.config.launchurl);
|
||||
} else {
|
||||
this.navCtrl.push('CoreLoginCredentialsPage', { siteUrl: result.siteUrl, siteConfig: result.config });
|
||||
}
|
||||
if (this.loginHelper.isSSOLoginNeeded(result.code)) {
|
||||
// SSO. User needs to authenticate in a browser.
|
||||
this.loginHelper.confirmAndOpenBrowserForSSOLogin(
|
||||
result.siteUrl, result.code, result.service, result.config && result.config.launchurl);
|
||||
} else {
|
||||
this.navCtrl.push('CoreLoginCredentialsPage', { siteUrl: result.siteUrl, siteConfig: result.config });
|
||||
}
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}, (error) => {
|
||||
this.showLoginIssue(url, error);
|
||||
}).finally(() => {
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreCronHandler } from '@providers/cron';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
|
||||
/**
|
||||
* Cron handler to log out sites when does not meet the app requirements.
|
||||
*/
|
||||
@Injectable()
|
||||
export class CoreLoginCronHandler implements CoreCronHandler {
|
||||
name = 'CoreLoginCronHandler';
|
||||
|
||||
constructor(private sitesProvider: CoreSitesProvider) {}
|
||||
|
||||
/**
|
||||
* Execute the process.
|
||||
* Receives the ID of the site affected, undefined for all sites.
|
||||
*
|
||||
* @param siteId ID of the site affected, undefined for all sites.
|
||||
* @return Promise resolved when done, rejected if failure.
|
||||
*/
|
||||
execute(siteId?: string): Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
if (!siteId) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// Check logged in site minimun required version.
|
||||
// Do not check twice in the same 10 minutes.
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return site.getPublicConfig().catch(() => {
|
||||
return {};
|
||||
}).then((config) => {
|
||||
this.sitesProvider.checkRequiredMinimumVersion(config).catch(() => {
|
||||
// Ignore errors.
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether it's a synchronization process or not. True if not defined.
|
||||
*
|
||||
* @return Whether it's a synchronization process or not.
|
||||
*/
|
||||
isSync(): boolean {
|
||||
// Defined to true to be checked on sync site.
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -171,9 +171,9 @@ export class CoreSettingsHelper {
|
|||
});
|
||||
}));
|
||||
|
||||
const syncPromise = Promise.all(promises);
|
||||
let syncPromise = Promise.all(promises);
|
||||
this.syncPromises[siteId] = syncPromise;
|
||||
syncPromise.finally(() => {
|
||||
syncPromise = syncPromise.finally(() => {
|
||||
delete this.syncPromises[siteId];
|
||||
});
|
||||
|
||||
|
|
|
@ -273,6 +273,8 @@
|
|||
"unlimited": "Unlimited",
|
||||
"unzipping": "Unzipping",
|
||||
"upgraderunning": "Site is being upgraded, please retry later.",
|
||||
"updaterequired": "App update required",
|
||||
"updaterequireddesc": "Please update your app to version {{$a}}",
|
||||
"user": "User",
|
||||
"userdeleted": "This user account has been deleted",
|
||||
"userdetails": "User details",
|
||||
|
|
|
@ -170,6 +170,15 @@ export class CoreAppProvider {
|
|||
return this.isDesktop() && process.arch == 'x64';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the app is running in an Android mobile or tablet device.
|
||||
*
|
||||
* @return Whether the app is running in an Android mobile or tablet device.
|
||||
*/
|
||||
isAndroid(): boolean {
|
||||
return this.platform.is('android');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the app is running in a desktop environment (not browser).
|
||||
*
|
||||
|
@ -181,6 +190,15 @@ export class CoreAppProvider {
|
|||
return !!(process && process.versions && typeof process.versions.electron != 'undefined');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the app is running in an iOS mobile or tablet device.
|
||||
*
|
||||
* @return Whether the app is running in an iOS mobile or tablet device.
|
||||
*/
|
||||
isIOS(): boolean {
|
||||
return this.platform.is('ios');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the keyboard is visible.
|
||||
*
|
||||
|
|
|
@ -19,6 +19,7 @@ import { CoreAppProvider } from './app';
|
|||
import { CoreEventsProvider } from './events';
|
||||
import { CoreLoggerProvider } from './logger';
|
||||
import { CoreSitesFactoryProvider } from './sites-factory';
|
||||
import { CoreDomUtilsProvider } from './utils/dom';
|
||||
import { CoreTextUtilsProvider } from './utils/text';
|
||||
import { CoreUrlUtilsProvider } from './utils/url';
|
||||
import { CoreUtilsProvider } from './utils/utils';
|
||||
|
@ -311,7 +312,8 @@ export class CoreSitesProvider {
|
|||
constructor(logger: CoreLoggerProvider, private http: HttpClient, private sitesFactory: CoreSitesFactoryProvider,
|
||||
private appProvider: CoreAppProvider, private translate: TranslateService, private urlUtils: CoreUrlUtilsProvider,
|
||||
private eventsProvider: CoreEventsProvider, private textUtils: CoreTextUtilsProvider,
|
||||
private utils: CoreUtilsProvider, private injector: Injector, private wsProvider: CoreWSProvider) {
|
||||
private utils: CoreUtilsProvider, private injector: Injector, private wsProvider: CoreWSProvider,
|
||||
protected domUtils: CoreDomUtilsProvider) {
|
||||
this.logger = logger.getInstance('CoreSitesProvider');
|
||||
|
||||
this.appDB = appProvider.getDB();
|
||||
|
@ -862,6 +864,87 @@ export class CoreSitesProvider {
|
|||
return this.appDB.insertRecord(this.SITES_TABLE, entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the required minimum version of the app for a site and shows a download dialog.
|
||||
*
|
||||
* @param config Config object of the site.
|
||||
* @param siteId ID of the site to check. Current site id will be used otherwise.
|
||||
* @return Resolved with if meets the requirements, rejected otherwise.
|
||||
*/
|
||||
checkRequiredMinimumVersion(config: any, siteId?: string): Promise<void> {
|
||||
if (config && config.tool_mobile_minimumversion) {
|
||||
const requiredVersion = this.convertVersionName(config.tool_mobile_minimumversion),
|
||||
appVersion = this.convertVersionName(CoreConfigConstants.versionname);
|
||||
|
||||
if (requiredVersion > appVersion) {
|
||||
let downloadUrl = '';
|
||||
|
||||
if (this.appProvider.isAndroid() && config.tool_mobile_androidappid) {
|
||||
downloadUrl = 'market://details?id=' + config.tool_mobile_androidappid;
|
||||
} else if (this.appProvider.isIOS() && config.tool_mobile_iosappid) {
|
||||
downloadUrl = 'itms-apps://itunes.apple.com/app/id' + config.tool_mobile_iosappid;
|
||||
} else if (config.tool_mobile_setuplink) {
|
||||
downloadUrl = config.tool_mobile_setuplink;
|
||||
} else if (this.appProvider.isMobile()) {
|
||||
downloadUrl = 'https://download.moodle.org/mobile/';
|
||||
} else {
|
||||
downloadUrl = 'https://download.moodle.org/desktop/';
|
||||
}
|
||||
|
||||
siteId = siteId || this.getCurrentSiteId();
|
||||
|
||||
// Do not block interface.
|
||||
this.domUtils.showConfirm(
|
||||
this.translate.instant('core.updaterequireddesc', { $a: config.tool_mobile_minimumversion }),
|
||||
this.translate.instant('core.updaterequired'),
|
||||
this.translate.instant('core.download'),
|
||||
this.translate.instant(siteId ? 'core.mainmenu.logout' : 'core.cancel')).then(() => {
|
||||
|
||||
this.utils.openInBrowser(downloadUrl);
|
||||
}).catch(() => {
|
||||
// Do nothing.
|
||||
});
|
||||
|
||||
if (siteId) {
|
||||
// Logout if it's the currentSite.
|
||||
const promise = siteId == this.getCurrentSiteId() ? this.logout() : Promise.resolve();
|
||||
|
||||
return promise.then(() => {
|
||||
// Always expire the token.
|
||||
return this.setSiteLoggedOut(siteId, true);
|
||||
}).then(() => {
|
||||
return Promise.reject(null);
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject(null);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert version name to numbers.
|
||||
*
|
||||
* @param name Version name (dot separated).
|
||||
* @return Version translated to a comparable number.
|
||||
*/
|
||||
protected convertVersionName(name: string): number {
|
||||
let version = 0;
|
||||
|
||||
const parts = name.split('.', 3);
|
||||
parts.forEach((num) => {
|
||||
version = (version * 100) + Number(num);
|
||||
});
|
||||
|
||||
if (parts.length < 3) {
|
||||
version = version * Math.pow(100, 3 - parts.length);
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login a user to a site from the list of sites.
|
||||
*
|
||||
|
@ -896,12 +979,20 @@ export class CoreSitesProvider {
|
|||
|
||||
return false;
|
||||
}, () => {
|
||||
this.login(siteId);
|
||||
return site.getPublicConfig().catch(() => {
|
||||
return {};
|
||||
}).then((config) => {
|
||||
return this.checkRequiredMinimumVersion(config).then(() => {
|
||||
this.login(siteId);
|
||||
|
||||
// Update site info. We don't block the UI.
|
||||
this.updateSiteInfo(siteId);
|
||||
// Update site info. We don't block the UI.
|
||||
this.updateSiteInfo(siteId);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}).catch(() => {
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue