// (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 { CoreSitesProvider } from '@providers/sites'; import { CoreSite } from '@classes/site'; import * as moment from 'moment'; /** * Service that provides some features regarding course overview. */ @Injectable() export class CoreCoursesMyOverviewProvider { static EVENTS_LIMIT = 20; static EVENTS_LIMIT_PER_COURSE = 10; protected ROOT_CACHE_KEY = 'myoverview:'; constructor(private sitesProvider: CoreSitesProvider) { } /** * Get calendar action events for the given course. * * @param {number} courseId Only events in this course. * @param {number} [afterEventId] The last seen event id. * @param {string} [siteId] Site ID. If not defined, use current site. * @return {Promise<{events: any[], canLoadMore: number}>} Promise resolved when the info is retrieved. */ getActionEventsByCourse(courseId: number, afterEventId?: number, siteId?: string): Promise<{ events: any[], canLoadMore: number }> { return this.sitesProvider.getSite(siteId).then((site) => { const time = moment().subtract(14, 'days').unix(), // Check two weeks ago. data: any = { timesortfrom: time, courseid: courseId, limitnum: CoreCoursesMyOverviewProvider.EVENTS_LIMIT_PER_COURSE }, preSets = { cacheKey: this.getActionEventsByCourseCacheKey(courseId) }; if (afterEventId) { data.aftereventid = afterEventId; } return site.read('core_calendar_get_action_events_by_course', data, preSets).then((courseEvents): any => { if (courseEvents && courseEvents.events) { return this.treatCourseEvents(courseEvents, time); } return Promise.reject(null); }); }); } /** * Get cache key for get calendar action events for the given course value WS call. * * @param {number} courseId Only events in this course. * @return {string} Cache key. */ protected getActionEventsByCourseCacheKey(courseId: number): string { return this.getActionEventsByCoursesCacheKey() + ':' + courseId; } /** * Get calendar action events for a given list of courses. * * @param {number[]} courseIds Course IDs. * @param {string} [siteId] Site ID. If not defined, use current site. * @return {Promise<{[s: string]: {events: any[], canLoadMore: number}}>} Promise resolved when the info is retrieved. */ getActionEventsByCourses(courseIds: number[], siteId?: string): Promise<{ [s: string]: { events: any[], canLoadMore: number } }> { return this.sitesProvider.getSite(siteId).then((site) => { const time = moment().subtract(14, 'days').unix(), // Check two weeks ago. data = { timesortfrom: time, courseids: courseIds, limitnum: CoreCoursesMyOverviewProvider.EVENTS_LIMIT_PER_COURSE }, preSets = { cacheKey: this.getActionEventsByCoursesCacheKey() }; return site.read('core_calendar_get_action_events_by_courses', data, preSets).then((events): any => { if (events && events.groupedbycourse) { const courseEvents = {}; events.groupedbycourse.forEach((course) => { courseEvents[course.courseid] = this.treatCourseEvents(course, time); }); return courseEvents; } return Promise.reject(null); }); }); } /** * Get cache key for get calendar action events for a given list of courses value WS call. * * @return {string} Cache key. */ protected getActionEventsByCoursesCacheKey(): string { return this.ROOT_CACHE_KEY + 'bycourse'; } /** * Get calendar action events based on the timesort value. * * @param {number} [afterEventId] The last seen event id. * @param {string} [siteId] Site ID. If not defined, use current site. * @return {Promise<{events: any[], canLoadMore: number}>} Promise resolved when the info is retrieved. */ getActionEventsByTimesort(afterEventId: number, siteId?: string): Promise<{ events: any[], canLoadMore: number }> { return this.sitesProvider.getSite(siteId).then((site) => { const time = moment().subtract(14, 'days').unix(), // Check two weeks ago. data: any = { timesortfrom: time, limitnum: CoreCoursesMyOverviewProvider.EVENTS_LIMIT }, preSets = { cacheKey: this.getActionEventsByTimesortCacheKey(afterEventId, data.limitnum), getCacheUsingCacheKey: true, uniqueCacheKey: true }; if (afterEventId) { data.aftereventid = afterEventId; } return site.read('core_calendar_get_action_events_by_timesort', data, preSets).then((events): any => { if (events && events.events) { const canLoadMore = events.events.length >= data.limitnum ? events.lastid : undefined; // Filter events by time in case it uses cache. events = events.events.filter((element) => { return element.timesort >= time; }); return { events: events, canLoadMore: canLoadMore }; } return Promise.reject(null); }); }); } /** * Get prefix cache key for calendar action events based on the timesort value WS calls. * * @return {string} Cache key. */ protected getActionEventsByTimesortPrefixCacheKey(): string { return this.ROOT_CACHE_KEY + 'bytimesort:'; } /** * Get cache key for get calendar action events based on the timesort value WS call. * * @param {number} [afterEventId] The last seen event id. * @param {number} [limit] Limit num of the call. * @return {string} Cache key. */ protected getActionEventsByTimesortCacheKey(afterEventId?: number, limit?: number): string { afterEventId = afterEventId || 0; limit = limit || 0; return this.getActionEventsByTimesortPrefixCacheKey() + afterEventId + ':' + limit; } /** * Invalidates get calendar action events for a given list of courses WS call. * * @param {string} [siteId] Site ID to invalidate. If not defined, use current site. * @return {Promise} Promise resolved when the data is invalidated. */ invalidateActionEventsByCourses(siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { return site.invalidateWsCacheForKeyStartingWith(this.getActionEventsByCoursesCacheKey()); }); } /** * Invalidates get calendar action events based on the timesort value WS call. * * @param {string} [siteId] Site ID to invalidate. If not defined, use current site. * @return {Promise} Promise resolved when the data is invalidated. */ invalidateActionEventsByTimesort(siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { return site.invalidateWsCacheForKeyStartingWith(this.getActionEventsByTimesortPrefixCacheKey()); }); } /** * Returns whether or not My Overview is available for a certain site. * * @param {string} [siteId] Site ID. If not defined, current site. * @return {Promise} Promise resolved with true if available, resolved with false or rejected otherwise. */ isAvailable(siteId?: string): Promise { return this.sitesProvider.getSite(siteId).then((site) => { return site.wsAvailable('core_calendar_get_action_events_by_courses'); }); } /** * Check if My Overview is disabled in a certain site. * * @param {CoreSite} [site] Site. If not defined, use current site. * @return {boolean} Whether it's disabled. */ isDisabledInSite(site?: CoreSite): boolean { site = site || this.sitesProvider.getCurrentSite(); return site.isFeatureDisabled('CoreMainMenuDelegate_CoreCourses'); } /** * Check if My Overview is available and not disabled. * * @return {Promise} Promise resolved with true if enabled, resolved with false otherwise. */ isEnabled(): Promise { if (!this.isDisabledInSite()) { return this.isAvailable().catch(() => { return false; }); } return Promise.resolve(false); } /** * Handles course events, filtering and treating if more can be loaded. * * @param {any} course Object containing response course events info. * @param {number} timeFrom Current time to filter events from. * @return {{events: any[], canLoadMore: number}} Object with course events and last loaded event id if more can be loaded. */ protected treatCourseEvents(course: any, timeFrom: number): { events: any[], canLoadMore: number } { const canLoadMore: number = course.events.length >= CoreCoursesMyOverviewProvider.EVENTS_LIMIT_PER_COURSE ? course.lastid : undefined; // Filter events by time in case it uses cache. course.events = course.events.filter((element) => { return element.timesort >= timeFrom; }); return { events: course.events, canLoadMore: canLoadMore }; } }