diff --git a/src/components/user-avatar/user-avatar.ts b/src/components/user-avatar/user-avatar.ts index 057d1a251..20aab67fd 100644 --- a/src/components/user-avatar/user-avatar.ts +++ b/src/components/user-avatar/user-avatar.ts @@ -66,18 +66,21 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges { * Set fields from user. */ protected setFields(): void { - if (this.user) { - this.profileUrl = this.profileUrl || this.user.profileimageurl || this.user.userprofileimageurl || - this.user.userpictureurl || this.user.profileimageurlsmall; + this.profileUrl = this.profileUrl || (this.user && (this.user.profileimageurl || this.user.userprofileimageurl || + this.user.userpictureurl || this.user.profileimageurlsmall)); - this.fullname = this.fullname || this.user.fullname || this.user.userfullname; - - this.userId = this.userId || this.user.userid; - this.courseId = this.courseId || this.user.courseid; - - // If not available we cannot ensure the avatar is from the current user. - this.myUser = this.userId && this.userId == this.currentUserId; + if (typeof this.profileUrl != 'string') { + this.profileUrl = ''; } + + this.fullname = this.fullname || (this.user && (this.user.fullname || this.user.userfullname)); + + this.userId = this.userId || (this.user && this.user.userid); + this.courseId = this.courseId || (this.user && this.user.courseid); + + // If not available we cannot ensure the avatar is from the current user. + this.myUser = this.userId && this.userId == this.currentUserId; + } /** @@ -95,7 +98,6 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges { * Function executed image clicked. */ gotoProfile(event: any): void { - // If the event prevented default action, do nothing. if (this.linkProfile && this.userId) { event.preventDefault(); event.stopPropagation(); diff --git a/src/core/course/course.module.ts b/src/core/course/course.module.ts index 541c4333b..e6e01a772 100644 --- a/src/core/course/course.module.ts +++ b/src/core/course/course.module.ts @@ -13,7 +13,9 @@ // limitations under the License. import { NgModule } from '@angular/core'; +import { Platform } from 'ionic-angular'; import { CoreCronDelegate } from '@providers/cron'; +import { CoreEventsProvider } from '@providers/events'; import { CoreCourseProvider } from './providers/course'; import { CoreCourseHelperProvider } from './providers/helper'; import { CoreCourseFormatDelegate } from './providers/format-delegate'; @@ -29,6 +31,7 @@ import { CoreCourseFormatTopicsModule } from './formats/topics/topics.module'; import { CoreCourseFormatWeeksModule } from './formats/weeks/weeks.module'; import { CoreCourseSyncProvider } from './providers/sync'; import { CoreCourseSyncCronHandler } from './providers/sync-cron-handler'; +import { CoreCourseLogCronHandler } from './providers/log-cron-handler'; // List of providers (without handlers). export const CORE_COURSE_PROVIDERS: any[] = [ @@ -61,12 +64,29 @@ export const CORE_COURSE_PROVIDERS: any[] = [ CoreCourseSyncProvider, CoreCourseFormatDefaultHandler, CoreCourseModuleDefaultHandler, - CoreCourseSyncCronHandler + CoreCourseSyncCronHandler, + CoreCourseLogCronHandler ], exports: [] }) export class CoreCourseModule { - constructor(cronDelegate: CoreCronDelegate, syncHandler: CoreCourseSyncCronHandler) { + constructor(cronDelegate: CoreCronDelegate, syncHandler: CoreCourseSyncCronHandler, logHandler: CoreCourseLogCronHandler, + platform: Platform, eventsProvider: CoreEventsProvider) { cronDelegate.register(syncHandler); + cronDelegate.register(logHandler); + + platform.resume.subscribe(() => { + // Log the app is open to keep user in online status. + setTimeout(() => { + cronDelegate.forceCronHandlerExecution(logHandler.name); + }, 1000); + }); + + eventsProvider.on(CoreEventsProvider.LOGIN, () => { + // Log the app is open to keep user in online status. + setTimeout(() => { + cronDelegate.forceCronHandlerExecution(logHandler.name); + }, 1000); + }); } } diff --git a/src/core/course/pages/section/section.ts b/src/core/course/pages/section/section.ts index c915b4b4e..1a048fc84 100644 --- a/src/core/course/pages/section/section.ts +++ b/src/core/course/pages/section/section.ts @@ -202,6 +202,11 @@ export class CoreCourseSectionPage implements OnDestroy { }).then((sections) => { let promise; + // Add log in Moodle. + this.courseProvider.logView(this.course.id, this.sectionNumber).catch(() => { + // Ignore errors. + }); + // Get the completion status. if (this.course.enablecompletion === false) { // Completion not enabled. diff --git a/src/core/course/providers/log-cron-handler.ts b/src/core/course/providers/log-cron-handler.ts new file mode 100644 index 000000000..108c8765d --- /dev/null +++ b/src/core/course/providers/log-cron-handler.ts @@ -0,0 +1,59 @@ +// (C) Copyright 2015 Martin Dougiamas +// +// 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'; +import { CoreCourseProvider } from '@core/course/providers/course'; + +/** + * Log cron handler. It will update last access of the user while app is open. + */ +@Injectable() +export class CoreCourseLogCronHandler implements CoreCronHandler { + name = 'CoreCourseLogCronHandler'; + + constructor(private coreProvider: CoreCourseProvider, private sitesProvider: CoreSitesProvider) {} + + /** + * Execute the process. + * Receives the ID of the site affected, undefined for the current site. + * + * @param {string} [siteId] ID of the site affected, undefined for the current site. + * @return {Promise} Promise resolved when done, rejected if failure. + */ + execute(siteId?: string): Promise { + return this.sitesProvider.getSite(siteId).then((site) => { + return this.coreProvider.logView(site.getSiteHomeId(), undefined, site.getId()); + }); + } + + /** + * Check whether it's a synchronization process or not. + * + * @return {boolean} Whether it's a synchronization process or not. + */ + isSync(): boolean { + return false; + } + + /** + * Get the time between consecutive executions. + * + * @return {number} Time between consecutive executions (in ms). + */ + getInterval(): number { + return 240000; // 4 minutes. By default platform will see the user as online if lastaccess is less than 5 minutes. + } +} diff --git a/src/core/user/pages/profile/profile.html b/src/core/user/pages/profile/profile.html index 8b1293c50..57d96674e 100644 --- a/src/core/user/pages/profile/profile.html +++ b/src/core/user/pages/profile/profile.html @@ -10,7 +10,7 @@ - +

diff --git a/src/core/user/pages/profile/profile.scss b/src/core/user/pages/profile/profile.scss index 647c39a36..edee0fc71 100644 --- a/src/core/user/pages/profile/profile.scss +++ b/src/core/user/pages/profile/profile.scss @@ -11,7 +11,7 @@ ion-app.app-root page-core-user-profile { border-radius: 50%; background-color: white; } - .user-avatar.item-avatar-center { + [core-user-avatar].item-avatar-center { display: inline-block; img { margin: 0; diff --git a/src/providers/cron.ts b/src/providers/cron.ts index 74eae363e..b82335476 100644 --- a/src/providers/cron.ts +++ b/src/providers/cron.ts @@ -236,23 +236,37 @@ export class CoreCronDelegate { const promises = []; for (const name in this.handlers) { - const handler = this.handlers[name]; if (this.isHandlerManualSync(name)) { - // Mark the handler as running (it might be running already). - handler.running = true; - - // Cancel pending timeout. - clearTimeout(handler.timeout); - delete handler.timeout; - // Now force the execution of the handler. - promises.push(this.checkAndExecuteHandler(name, true, siteId)); + promises.push(this.forceCronHandlerExecution(name, siteId)); } } return this.utils.allPromises(promises); } + /** + * Force execution of a cron tasks without waiting for the scheduled time. + * Please notice that some tasks may not be executed depending on the network connection and sync settings. + * + * @param {string} [name] If provided, the name of the handler. + * @param {string} [siteId] Site ID. If not defined, all sites. + * @return {Promise} Promise resolved if handler has been executed successfully, rejected otherwise. + */ + forceCronHandlerExecution(name?: string, siteId?: string): Promise { + const handler = this.handlers[name]; + + // Mark the handler as running (it might be running already). + handler.running = true; + + // Cancel pending timeout. + clearTimeout(handler.timeout); + delete handler.timeout; + + // Now force the execution of the handler. + return this.checkAndExecuteHandler(name, true, siteId); + } + /** * Get a handler's interval. *