From b8cbbd872cf3844e8b4afb0857aba7ed886732e3 Mon Sep 17 00:00:00 2001
From: Dani Palou <dani@moodle.com>
Date: Tue, 17 Jul 2018 16:10:29 +0200
Subject: [PATCH] MOBILE-2161 menu: Support auto-login in embedded menu items

---
 src/classes/site.ts                      | 105 ++++++++++++-----------
 src/components/loading/core-loading.html |   2 +-
 src/core/mainmenu/providers/mainmenu.ts  |   7 +-
 src/core/viewer/pages/iframe/iframe.html |   4 +-
 src/core/viewer/pages/iframe/iframe.scss |   5 ++
 src/core/viewer/pages/iframe/iframe.ts   |  22 ++++-
 6 files changed, 91 insertions(+), 54 deletions(-)
 create mode 100644 src/core/viewer/pages/iframe/iframe.scss

diff --git a/src/classes/site.ts b/src/classes/site.ts
index 6d1cfed01..565493518 100644
--- a/src/classes/site.ts
+++ b/src/classes/site.ts
@@ -1221,59 +1221,30 @@ export class CoreSite {
      * @return {Promise<InAppBrowserObject|void>} Promise resolved when done. Resolve param is returned only if inApp=true.
      */
     openWithAutoLogin(inApp: boolean, url: string, options?: any, alertMessage?: string): Promise<InAppBrowserObject | void> {
-        // Convenience function to open the URL.
-        const open = (url): Promise<any> => {
-            return new Promise<InAppBrowserObject | void>((resolve, reject): void => {
-                if (modal) {
-                    modal.dismiss();
-                }
-
-                if (alertMessage) {
-                    this.domUtils.showAlert(this.translate.instant('core.notice'), alertMessage, undefined, 3000).then((alert) => {
-                        alert.onDidDismiss(() => {
-                            if (inApp) {
-                                resolve(this.utils.openInApp(url, options));
-                            } else {
-                                resolve(this.utils.openInBrowser(url));
-                            }
-                        });
-                    });
+        // Get the URL to open.
+        return this.getAutoLoginUrl(url).then((url) => {
+            if (!alertMessage) {
+                // Just open the URL.
+                if (inApp) {
+                    return this.utils.openInApp(url, options);
                 } else {
-                    if (inApp) {
-                        resolve(this.utils.openInApp(url, options));
-                    } else {
-                        resolve(this.utils.openInBrowser(url));
-                    }
+                    return this.utils.openInBrowser(url);
                 }
-            });
-        };
-
-        if (!this.privateToken || !this.wsAvailable('tool_mobile_get_autologin_key') ||
-                (this.lastAutoLogin && this.timeUtils.timestamp() - this.lastAutoLogin < CoreConstants.SECONDS_MINUTE * 6)) {
-            // No private token, WS not available or last auto-login was less than 6 minutes ago.
-            // Open the final URL without auto-login.
-            return Promise.resolve(open(url));
-        }
-
-        const userId = this.getUserId(),
-            params = {
-                privatetoken: this.privateToken
-            },
-            modal = this.domUtils.showModalLoading();
-
-        // Use write to not use cache.
-        return this.write('tool_mobile_get_autologin_key', params).then((data) => {
-            if (!data.autologinurl || !data.key) {
-                // Not valid data, open the final URL without auto-login.
-                return open(url);
             }
 
-            this.lastAutoLogin = this.timeUtils.timestamp();
+            // Show an alert first.
+            return this.domUtils.showAlert(this.translate.instant('core.notice'), alertMessage, undefined, 3000).then((alert) => {
 
-            return open(data.autologinurl + '?userid=' + userId + '&key=' + data.key + '&urltogo=' + url);
-        }).catch(() => {
-            // Couldn't get autologin key, open the final URL without auto-login.
-            return open(url);
+                return new Promise<InAppBrowserObject | void>((resolve, reject): void => {
+                    alert.onDidDismiss(() => {
+                        if (inApp) {
+                            resolve(this.utils.openInApp(url, options));
+                        } else {
+                            resolve(this.utils.openInBrowser(url));
+                        }
+                    });
+                });
+            });
         });
     }
 
@@ -1459,6 +1430,44 @@ export class CoreSite {
         return false;
     }
 
+    /**
+     * Given a URL, convert it to a URL that will auto-login if supported.
+     *
+     * @param {string} url The URL to convert.
+     * @return {Promise<string>} Promise resolved with the converted URL.
+     */
+    getAutoLoginUrl(url: string): Promise<string> {
+
+        if (!this.privateToken || !this.wsAvailable('tool_mobile_get_autologin_key') ||
+                (this.lastAutoLogin && this.timeUtils.timestamp() - this.lastAutoLogin < CoreConstants.SECONDS_MINUTE * 6)) {
+            // No private token, WS not available or last auto-login was less than 6 minutes ago. Don't change the URL.
+            return Promise.resolve(url);
+        }
+
+        const userId = this.getUserId(),
+            params = {
+                privatetoken: this.privateToken
+            },
+            modal = this.domUtils.showModalLoading();
+
+        // Use write to not use cache.
+        return this.write('tool_mobile_get_autologin_key', params).then((data) => {
+            if (!data.autologinurl || !data.key) {
+                // Not valid data, return the same URL.
+                return url;
+            }
+
+            this.lastAutoLogin = this.timeUtils.timestamp();
+
+            return data.autologinurl + '?userid=' + userId + '&key=' + data.key + '&urltogo=' + url;
+        }).catch(() => {
+            // Couldn't get autologin key, return the same URL.
+            return url;
+        }).finally(() => {
+            modal.dismiss();
+        });
+    }
+
     /**
      * Get a version number from a release version.
      * If release version is valid but not found in the list of Moodle releases, it will use the last released major version.
diff --git a/src/components/loading/core-loading.html b/src/components/loading/core-loading.html
index 26ba42d78..22b9c6ef8 100644
--- a/src/components/loading/core-loading.html
+++ b/src/components/loading/core-loading.html
@@ -4,7 +4,7 @@
         <p class="core-loading-message" *ngIf="message">{{message}}</p>
     </span>
 </div>
-<div #content>
+<div #content class="core-loading-content">
     <ng-content [@coreShowHideAnimation] *ngIf="hideUntil">
     </ng-content>
 </div>
\ No newline at end of file
diff --git a/src/core/mainmenu/providers/mainmenu.ts b/src/core/mainmenu/providers/mainmenu.ts
index abcec6f65..ac38ef92b 100644
--- a/src/core/mainmenu/providers/mainmenu.ts
+++ b/src/core/mainmenu/providers/mainmenu.ts
@@ -139,7 +139,7 @@ export class CoreMainMenuProvider {
 
                         if (!data) {
                             // No valid label, ignore this entry.
-                            return;
+                            continue;
                         }
                     }
 
@@ -151,7 +151,10 @@ export class CoreMainMenuProvider {
                     };
                 }
 
-                return result;
+                // Remove undefined values.
+                return result.filter((entry) => {
+                    return typeof entry != 'undefined';
+                });
             });
         });
     }
diff --git a/src/core/viewer/pages/iframe/iframe.html b/src/core/viewer/pages/iframe/iframe.html
index 52707ab5c..ec6955fb0 100644
--- a/src/core/viewer/pages/iframe/iframe.html
+++ b/src/core/viewer/pages/iframe/iframe.html
@@ -4,5 +4,7 @@
     </ion-navbar>
 </ion-header>
 <ion-content>
-    <core-iframe [src]="url"></core-iframe>
+    <core-loading [hideUntil]="url">
+        <core-iframe *ngIf="url" [src]="url"></core-iframe>
+    </core-loading>
 </ion-content>
diff --git a/src/core/viewer/pages/iframe/iframe.scss b/src/core/viewer/pages/iframe/iframe.scss
new file mode 100644
index 000000000..a22e7a5eb
--- /dev/null
+++ b/src/core/viewer/pages/iframe/iframe.scss
@@ -0,0 +1,5 @@
+page-core-viewer-iframe {
+    core-loading .core-loading-content {
+        height: 100%;
+    }
+}
\ No newline at end of file
diff --git a/src/core/viewer/pages/iframe/iframe.ts b/src/core/viewer/pages/iframe/iframe.ts
index 63fda7f3f..c8df18a24 100644
--- a/src/core/viewer/pages/iframe/iframe.ts
+++ b/src/core/viewer/pages/iframe/iframe.ts
@@ -14,6 +14,7 @@
 
 import { Component } from '@angular/core';
 import { IonicPage, NavParams } from 'ionic-angular';
+import { CoreSitesProvider } from '@providers/sites';
 
 /**
  * Page to display a URL in an iframe.
@@ -27,8 +28,25 @@ export class CoreViewerIframePage {
     title: string; // Page title.
     url: string; // Iframe URL.
 
-    constructor(params: NavParams) {
+    protected autoLogin; // Whether the URL should be open with auto-login. Accepts the following values:
+                         //   "yes" -> Always auto-login.
+                         //   "no" -> Never auto-login.
+                         //   "check" -> Auto-login only if it points to the current site. Default value.
+
+    constructor(params: NavParams, sitesProvider: CoreSitesProvider) {
         this.title = params.get('title');
-        this.url = params.get('url');
+        this.autoLogin = params.get('autoLogin') || 'check';
+
+        const url = params.get('url'),
+            currentSite = sitesProvider.getCurrentSite();
+
+        if (currentSite && (this.autoLogin == 'yes' || (this.autoLogin == 'check' && currentSite.containsUrl(url)))) {
+            // Format the URL to add auto-login.
+            currentSite.getAutoLoginUrl(url).then((url) => {
+                this.url = url;
+            });
+        } else {
+            this.url = url;
+        }
     }
 }