MOBILE-3109 addon: Add return types to all addons except mod
parent
0c6c1b6383
commit
b2497a1dd0
|
@ -1,6 +1,6 @@
|
||||||
<ion-header>
|
<ion-header>
|
||||||
<ion-navbar core-back-button>
|
<ion-navbar core-back-button>
|
||||||
<ion-title>{{badge.name}}</ion-title>
|
<ion-title>{{badge && badge.name}}</ion-title>
|
||||||
</ion-navbar>
|
</ion-navbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
</ion-refresher>
|
</ion-refresher>
|
||||||
<core-loading [hideUntil]="badgeLoaded">
|
<core-loading [hideUntil]="badgeLoaded">
|
||||||
|
|
||||||
<ion-item-group>
|
<ion-item-group *ngIf="badge">
|
||||||
<ion-item text-wrap class="item-avatar-center">
|
<ion-item text-wrap class="item-avatar-center">
|
||||||
<img *ngIf="badge.badgeurl" class="avatar" [src]="badge.badgeurl" core-external-content [alt]="badge.name">
|
<img *ngIf="badge.badgeurl" class="avatar" [src]="badge.badgeurl" core-external-content [alt]="badge.name">
|
||||||
<ion-badge color="danger" *ngIf="badge.dateexpire && currentTime >= badge.dateexpire">
|
<ion-badge color="danger" *ngIf="badge.dateexpire && currentTime >= badge.dateexpire">
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
|
|
||||||
<ion-item-group>
|
<ion-item-group *ngIf="badge">
|
||||||
<ion-item-divider>
|
<ion-item-divider>
|
||||||
<h2>{{ 'addon.badges.issuerdetails' | translate}}</h2>
|
<h2>{{ 'addon.badges.issuerdetails' | translate}}</h2>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
|
|
||||||
<ion-item-group>
|
<ion-item-group *ngIf="badge">
|
||||||
<ion-item-divider>
|
<ion-item-divider>
|
||||||
<h2>{{ 'addon.badges.badgedetails' | translate}}</h2>
|
<h2>{{ 'addon.badges.badgedetails' | translate}}</h2>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
<!-- Criteria (not yet avalaible) -->
|
<!-- Criteria (not yet avalaible) -->
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
|
|
||||||
<ion-item-group>
|
<ion-item-group *ngIf="badge">
|
||||||
<ion-item-divider>
|
<ion-item-divider>
|
||||||
<h2>{{ 'addon.badges.issuancedetails' | translate}}</h2>
|
<h2>{{ 'addon.badges.issuancedetails' | translate}}</h2>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
|
@ -120,7 +120,7 @@
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
|
|
||||||
<!-- Endorsement -->
|
<!-- Endorsement -->
|
||||||
<ion-item-group *ngIf="badge.endorsement">
|
<ion-item-group *ngIf="badge && badge.endorsement">
|
||||||
<ion-item-divider>
|
<ion-item-divider>
|
||||||
<h2>{{ 'addon.badges.bendorsement' | translate}}</h2>
|
<h2>{{ 'addon.badges.bendorsement' | translate}}</h2>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
|
@ -159,7 +159,7 @@
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
|
|
||||||
<!-- Related badges -->
|
<!-- Related badges -->
|
||||||
<ion-item-group *ngIf="badge.relatedbadges">
|
<ion-item-group *ngIf="badge && badge.relatedbadges">
|
||||||
<ion-item-divider>
|
<ion-item-divider>
|
||||||
<h2>{{ 'addon.badges.relatedbages' | translate}}</h2>
|
<h2>{{ 'addon.badges.relatedbages' | translate}}</h2>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
|
@ -172,7 +172,7 @@
|
||||||
</ion-item-group>
|
</ion-item-group>
|
||||||
|
|
||||||
<!-- Competencies alignment -->
|
<!-- Competencies alignment -->
|
||||||
<ion-item-group *ngIf="badge.competencies">
|
<ion-item-group *ngIf="badge && badge.competencies">
|
||||||
<ion-item-divider>
|
<ion-item-divider>
|
||||||
<h2>{{ 'addon.badges.alignment' | translate}}</h2>
|
<h2>{{ 'addon.badges.alignment' | translate}}</h2>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreUserProvider } from '@core/user/providers/user';
|
import { CoreUserProvider } from '@core/user/providers/user';
|
||||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
import { AddonBadgesProvider } from '../../providers/badges';
|
import { AddonBadgesProvider, AddonBadgesUserBadge } from '../../providers/badges';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the list of calendar events.
|
* Page that displays the list of calendar events.
|
||||||
|
@ -38,7 +38,7 @@ export class AddonBadgesIssuedBadgePage {
|
||||||
|
|
||||||
user: any = {};
|
user: any = {};
|
||||||
course: any = {};
|
course: any = {};
|
||||||
badge: any = {};
|
badge: AddonBadgesUserBadge;
|
||||||
|
|
||||||
badgeLoaded = false;
|
badgeLoaded = false;
|
||||||
currentTime = 0;
|
currentTime = 0;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
import { Component, ViewChild } from '@angular/core';
|
import { Component, ViewChild } from '@angular/core';
|
||||||
import { IonicPage, Content, NavParams } from 'ionic-angular';
|
import { IonicPage, Content, NavParams } from 'ionic-angular';
|
||||||
import { AddonBadgesProvider } from '../../providers/badges';
|
import { AddonBadgesProvider, AddonBadgesUserBadge } from '../../providers/badges';
|
||||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
|
@ -36,7 +36,7 @@ export class AddonBadgesUserBadgesPage {
|
||||||
userId: number;
|
userId: number;
|
||||||
|
|
||||||
badgesLoaded = false;
|
badgesLoaded = false;
|
||||||
badges = [];
|
badges: AddonBadgesUserBadge[] = [];
|
||||||
currentTime = 0;
|
currentTime = 0;
|
||||||
badgeHash: string;
|
badgeHash: string;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
|
import { CoreWSExternalWarning } from '@providers/ws';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,7 +71,7 @@ export class AddonBadgesProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise to be resolved when the badges are retrieved.
|
* @return Promise to be resolved when the badges are retrieved.
|
||||||
*/
|
*/
|
||||||
getUserBadges(courseId: number, userId: number, siteId?: string): Promise<any> {
|
getUserBadges(courseId: number, userId: number, siteId?: string): Promise<AddonBadgesUserBadge[]> {
|
||||||
|
|
||||||
this.logger.debug('Get badges for course ' + courseId);
|
this.logger.debug('Get badges for course ' + courseId);
|
||||||
|
|
||||||
|
@ -110,3 +111,76 @@ export class AddonBadgesProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_badges_get_user_badges.
|
||||||
|
*/
|
||||||
|
export type AddonBadgesGetUserBadgesResult = {
|
||||||
|
badges: AddonBadgesUserBadge[]; // List of badges.
|
||||||
|
warnings?: CoreWSExternalWarning[]; // List of warnings.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Badge data returned by WS core_badges_get_user_badges.
|
||||||
|
*/
|
||||||
|
export type AddonBadgesUserBadge = {
|
||||||
|
id?: number; // Badge id.
|
||||||
|
name: string; // Badge name.
|
||||||
|
description: string; // Badge description.
|
||||||
|
timecreated?: number; // Time created.
|
||||||
|
timemodified?: number; // Time modified.
|
||||||
|
usercreated?: number; // User created.
|
||||||
|
usermodified?: number; // User modified.
|
||||||
|
issuername: string; // Issuer name.
|
||||||
|
issuerurl: string; // Issuer URL.
|
||||||
|
issuercontact: string; // Issuer contact.
|
||||||
|
expiredate?: number; // Expire date.
|
||||||
|
expireperiod?: number; // Expire period.
|
||||||
|
type?: number; // Type.
|
||||||
|
courseid?: number; // Course id.
|
||||||
|
message?: string; // Message.
|
||||||
|
messagesubject?: string; // Message subject.
|
||||||
|
attachment?: number; // Attachment.
|
||||||
|
notification?: number; // @since 3.6. Whether to notify when badge is awarded.
|
||||||
|
nextcron?: number; // @since 3.6. Next cron.
|
||||||
|
status?: number; // Status.
|
||||||
|
issuedid?: number; // Issued id.
|
||||||
|
uniquehash: string; // Unique hash.
|
||||||
|
dateissued: number; // Date issued.
|
||||||
|
dateexpire: number; // Date expire.
|
||||||
|
visible?: number; // Visible.
|
||||||
|
email?: string; // @since 3.6. User email.
|
||||||
|
version?: string; // @since 3.6. Version.
|
||||||
|
language?: string; // @since 3.6. Language.
|
||||||
|
imageauthorname?: string; // @since 3.6. Name of the image author.
|
||||||
|
imageauthoremail?: string; // @since 3.6. Email of the image author.
|
||||||
|
imageauthorurl?: string; // @since 3.6. URL of the image author.
|
||||||
|
imagecaption?: string; // @since 3.6. Caption of the image.
|
||||||
|
badgeurl: string; // Badge URL.
|
||||||
|
endorsement?: { // @since 3.6.
|
||||||
|
id: number; // Endorsement id.
|
||||||
|
badgeid: number; // Badge id.
|
||||||
|
issuername: string; // Endorsement issuer name.
|
||||||
|
issuerurl: string; // Endorsement issuer URL.
|
||||||
|
issueremail: string; // Endorsement issuer email.
|
||||||
|
claimid: string; // Claim URL.
|
||||||
|
claimcomment: string; // Claim comment.
|
||||||
|
dateissued: number; // Date issued.
|
||||||
|
};
|
||||||
|
alignment: { // @since 3.6. Badge alignments.
|
||||||
|
id?: number; // Alignment id.
|
||||||
|
badgeid?: number; // Badge id.
|
||||||
|
targetName?: string; // Target name.
|
||||||
|
targetUrl?: string; // Target URL.
|
||||||
|
targetDescription?: string; // Target description.
|
||||||
|
targetFramework?: string; // Target framework.
|
||||||
|
targetCode?: string; // Target code.
|
||||||
|
}[];
|
||||||
|
relatedbadges: { // @since 3.6. Related badges.
|
||||||
|
id: number; // Badge id.
|
||||||
|
name: string; // Badge name.
|
||||||
|
version?: string; // Version.
|
||||||
|
language?: string; // Language.
|
||||||
|
type?: number; // Type.
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
|
@ -16,7 +16,9 @@ import { Component, OnInit, Injector, Optional } from '@angular/core';
|
||||||
import { NavController } from 'ionic-angular';
|
import { NavController } from 'ionic-angular';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component';
|
import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component';
|
||||||
import { AddonBlockRecentlyAccessedItemsProvider } from '../../providers/recentlyaccesseditems';
|
import {
|
||||||
|
AddonBlockRecentlyAccessedItemsProvider, AddonBlockRecentlyAccessedItemsItem
|
||||||
|
} from '../../providers/recentlyaccesseditems';
|
||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
||||||
|
|
||||||
|
@ -28,7 +30,7 @@ import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/hel
|
||||||
templateUrl: 'addon-block-recentlyaccesseditems.html'
|
templateUrl: 'addon-block-recentlyaccesseditems.html'
|
||||||
})
|
})
|
||||||
export class AddonBlockRecentlyAccessedItemsComponent extends CoreBlockBaseComponent implements OnInit {
|
export class AddonBlockRecentlyAccessedItemsComponent extends CoreBlockBaseComponent implements OnInit {
|
||||||
items = [];
|
items: AddonBlockRecentlyAccessedItemsItem[] = [];
|
||||||
|
|
||||||
protected fetchContentDefaultError = 'Error getting recently accessed items data.';
|
protected fetchContentDefaultError = 'Error getting recently accessed items data.';
|
||||||
|
|
||||||
|
|
|
@ -42,14 +42,16 @@ export class AddonBlockRecentlyAccessedItemsProvider {
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Promise resolved when the info is retrieved.
|
* @return Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getRecentItems(siteId?: string): Promise<any[]> {
|
getRecentItems(siteId?: string): Promise<AddonBlockRecentlyAccessedItemsItem[]> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const preSets = {
|
const preSets = {
|
||||||
cacheKey: this.getRecentItemsCacheKey()
|
cacheKey: this.getRecentItemsCacheKey()
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('block_recentlyaccesseditems_get_recent_items', undefined, preSets).then((items) => {
|
return site.read('block_recentlyaccesseditems_get_recent_items', undefined, preSets)
|
||||||
|
.then((items: AddonBlockRecentlyAccessedItemsItem[]) => {
|
||||||
|
|
||||||
return items.map((item) => {
|
return items.map((item) => {
|
||||||
const modicon = item.icon && this.domUtils.getHTMLElementAttribute(item.icon, 'src');
|
const modicon = item.icon && this.domUtils.getHTMLElementAttribute(item.icon, 'src');
|
||||||
item.iconUrl = this.courseProvider.getModuleIconSrc(item.modname, modicon);
|
item.iconUrl = this.courseProvider.getModuleIconSrc(item.modname, modicon);
|
||||||
|
@ -72,3 +74,27 @@ export class AddonBlockRecentlyAccessedItemsProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS block_recentlyaccesseditems_get_recent_items.
|
||||||
|
*/
|
||||||
|
export type AddonBlockRecentlyAccessedItemsItem = {
|
||||||
|
id: number; // Id.
|
||||||
|
courseid: number; // Courseid.
|
||||||
|
cmid: number; // Cmid.
|
||||||
|
userid: number; // Userid.
|
||||||
|
modname: string; // Modname.
|
||||||
|
name: string; // Name.
|
||||||
|
coursename: string; // Coursename.
|
||||||
|
timeaccess: number; // Timeaccess.
|
||||||
|
viewurl: string; // Viewurl.
|
||||||
|
courseviewurl: string; // Courseviewurl.
|
||||||
|
icon: string; // Icon.
|
||||||
|
} & AddonBlockRecentlyAccessedItemsItemCalculatedData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated data for recently accessed item.
|
||||||
|
*/
|
||||||
|
export type AddonBlockRecentlyAccessedItemsItemCalculatedData = {
|
||||||
|
iconUrl: string; // Icon URL. Calculated by the app.
|
||||||
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { CoreCoursesHelperProvider } from '@core/courses/providers/helper';
|
||||||
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
|
import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate';
|
||||||
import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component';
|
import { CoreBlockBaseComponent } from '@core/block/classes/base-block-component';
|
||||||
import { AddonBlockTimelineProvider } from '../../providers/timeline';
|
import { AddonBlockTimelineProvider } from '../../providers/timeline';
|
||||||
|
import { AddonCalendarEvent } from '@addon/calendar/providers/calendar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to render a timeline block.
|
* Component to render a timeline block.
|
||||||
|
@ -34,9 +35,9 @@ export class AddonBlockTimelineComponent extends CoreBlockBaseComponent implemen
|
||||||
filter = 'next30days';
|
filter = 'next30days';
|
||||||
currentSite: any;
|
currentSite: any;
|
||||||
timeline = {
|
timeline = {
|
||||||
events: [],
|
events: <AddonCalendarEvent[]> [],
|
||||||
loaded: false,
|
loaded: false,
|
||||||
canLoadMore: undefined
|
canLoadMore: <number> undefined
|
||||||
};
|
};
|
||||||
timelineCourses = {
|
timelineCourses = {
|
||||||
courses: [],
|
courses: [],
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreCoursesDashboardProvider } from '@core/courses/providers/dashboard';
|
import { CoreCoursesDashboardProvider } from '@core/courses/providers/dashboard';
|
||||||
|
import { AddonCalendarEvents, AddonCalendarEventsGroupedByCourse, AddonCalendarEvent } from '@addon/calendar/providers/calendar';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,7 +39,7 @@ export class AddonBlockTimelineProvider {
|
||||||
* @return Promise resolved when the info is retrieved.
|
* @return Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getActionEventsByCourse(courseId: number, afterEventId?: number, siteId?: string):
|
getActionEventsByCourse(courseId: number, afterEventId?: number, siteId?: string):
|
||||||
Promise<{ events: any[], canLoadMore: number }> {
|
Promise<{ events: AddonCalendarEvent[], canLoadMore: number }> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
|
const time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
|
||||||
|
@ -55,7 +56,9 @@ export class AddonBlockTimelineProvider {
|
||||||
data.aftereventid = afterEventId;
|
data.aftereventid = afterEventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('core_calendar_get_action_events_by_course', data, preSets).then((courseEvents): any => {
|
return site.read('core_calendar_get_action_events_by_course', data, preSets)
|
||||||
|
.then((courseEvents: AddonCalendarEvents): any => {
|
||||||
|
|
||||||
if (courseEvents && courseEvents.events) {
|
if (courseEvents && courseEvents.events) {
|
||||||
return this.treatCourseEvents(courseEvents, time);
|
return this.treatCourseEvents(courseEvents, time);
|
||||||
}
|
}
|
||||||
|
@ -82,8 +85,9 @@ export class AddonBlockTimelineProvider {
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Promise resolved when the info is retrieved.
|
* @return Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getActionEventsByCourses(courseIds: number[], siteId?: string): Promise<{ [s: string]:
|
getActionEventsByCourses(courseIds: number[], siteId?: string): Promise<{ [courseId: string]:
|
||||||
{ events: any[], canLoadMore: number } }> {
|
{ events: AddonCalendarEvent[], canLoadMore: number } }> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
|
const time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
|
||||||
data = {
|
data = {
|
||||||
|
@ -95,7 +99,9 @@ export class AddonBlockTimelineProvider {
|
||||||
cacheKey: this.getActionEventsByCoursesCacheKey()
|
cacheKey: this.getActionEventsByCoursesCacheKey()
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_calendar_get_action_events_by_courses', data, preSets).then((events): any => {
|
return site.read('core_calendar_get_action_events_by_courses', data, preSets)
|
||||||
|
.then((events: AddonCalendarEventsGroupedByCourse): any => {
|
||||||
|
|
||||||
if (events && events.groupedbycourse) {
|
if (events && events.groupedbycourse) {
|
||||||
const courseEvents = {};
|
const courseEvents = {};
|
||||||
|
|
||||||
|
@ -127,7 +133,9 @@ export class AddonBlockTimelineProvider {
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Promise resolved when the info is retrieved.
|
* @return Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getActionEventsByTimesort(afterEventId: number, siteId?: string): Promise<{ events: any[], canLoadMore: number }> {
|
getActionEventsByTimesort(afterEventId: number, siteId?: string):
|
||||||
|
Promise<{ events: AddonCalendarEvent[], canLoadMore: number }> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
|
const time = moment().subtract(14, 'days').unix(), // Check two weeks ago.
|
||||||
data: any = {
|
data: any = {
|
||||||
|
@ -144,12 +152,14 @@ export class AddonBlockTimelineProvider {
|
||||||
data.aftereventid = afterEventId;
|
data.aftereventid = afterEventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('core_calendar_get_action_events_by_timesort', data, preSets).then((events): any => {
|
return site.read('core_calendar_get_action_events_by_timesort', data, preSets)
|
||||||
if (events && events.events) {
|
.then((result: AddonCalendarEvents): any => {
|
||||||
const canLoadMore = events.events.length >= data.limitnum ? events.lastid : undefined;
|
|
||||||
|
if (result && result.events) {
|
||||||
|
const canLoadMore = result.events.length >= data.limitnum ? result.lastid : undefined;
|
||||||
|
|
||||||
// Filter events by time in case it uses cache.
|
// Filter events by time in case it uses cache.
|
||||||
events = events.events.filter((element) => {
|
const events = result.events.filter((element) => {
|
||||||
return element.timesort >= time;
|
return element.timesort >= time;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -236,7 +246,9 @@ export class AddonBlockTimelineProvider {
|
||||||
* @param timeFrom Current time to filter events from.
|
* @param timeFrom Current time to filter events from.
|
||||||
* @return Object with course events and last loaded event id if more can be loaded.
|
* @return Object with course events and last loaded event id if more can be loaded.
|
||||||
*/
|
*/
|
||||||
protected treatCourseEvents(course: any, timeFrom: number): { events: any[], canLoadMore: number } {
|
protected treatCourseEvents(course: AddonCalendarEvents, timeFrom: number):
|
||||||
|
{ events: AddonCalendarEvent[], canLoadMore: number } {
|
||||||
|
|
||||||
const canLoadMore: number =
|
const canLoadMore: number =
|
||||||
course.events.length >= AddonBlockTimelineProvider.EVENTS_LIMIT_PER_COURSE ? course.lastid : undefined;
|
course.events.length >= AddonBlockTimelineProvider.EVENTS_LIMIT_PER_COURSE ? course.lastid : undefined;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreUserProvider } from '@core/user/providers/user';
|
import { CoreUserProvider } from '@core/user/providers/user';
|
||||||
import { AddonBlogProvider } from '../../providers/blog';
|
import { AddonBlogProvider, AddonBlogPost } from '../../providers/blog';
|
||||||
import { CoreCommentsProvider } from '@core/comments/providers/comments';
|
import { CoreCommentsProvider } from '@core/comments/providers/comments';
|
||||||
import { CoreTagProvider } from '@core/tag/providers/tag';
|
import { CoreTagProvider } from '@core/tag/providers/tag';
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ export class AddonBlogEntriesComponent implements OnInit {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
canLoadMore = false;
|
canLoadMore = false;
|
||||||
loadMoreError = false;
|
loadMoreError = false;
|
||||||
entries = [];
|
entries: AddonBlogPostFormatted[] = [];
|
||||||
currentUserId: number;
|
currentUserId: number;
|
||||||
showMyEntriesToggle = false;
|
showMyEntriesToggle = false;
|
||||||
onlyMyEntries = false;
|
onlyMyEntries = false;
|
||||||
|
@ -118,7 +118,7 @@ export class AddonBlogEntriesComponent implements OnInit {
|
||||||
const loadPage = this.onlyMyEntries ? this.userPageLoaded : this.pageLoaded;
|
const loadPage = this.onlyMyEntries ? this.userPageLoaded : this.pageLoaded;
|
||||||
|
|
||||||
return this.blogProvider.getEntries(this.filter, loadPage).then((result) => {
|
return this.blogProvider.getEntries(this.filter, loadPage).then((result) => {
|
||||||
const promises = result.entries.map((entry) => {
|
const promises = result.entries.map((entry: AddonBlogPostFormatted) => {
|
||||||
switch (entry.publishstate) {
|
switch (entry.publishstate) {
|
||||||
case 'draft':
|
case 'draft':
|
||||||
entry.publishTranslated = 'publishtonoone';
|
entry.publishTranslated = 'publishtonoone';
|
||||||
|
@ -237,5 +237,12 @@ export class AddonBlogEntriesComponent implements OnInit {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blog post with some calculated data.
|
||||||
|
*/
|
||||||
|
type AddonBlogPostFormatted = AddonBlogPost & {
|
||||||
|
publishTranslated?: string; // Calculated in the app. Key of the string to translate the publish state of the post.
|
||||||
|
user?: any; // Calculated in the app. Data of the user that wrote the post.
|
||||||
|
};
|
||||||
|
|
|
@ -18,6 +18,8 @@ import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
|
import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws';
|
||||||
|
import { CoreTagItem } from '@core/tag/providers/tag';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle blog entries.
|
* Service to handle blog entries.
|
||||||
|
@ -68,7 +70,7 @@ export class AddonBlogProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise to be resolved when the entries are retrieved.
|
* @return Promise to be resolved when the entries are retrieved.
|
||||||
*/
|
*/
|
||||||
getEntries(filter: any = {}, page: number = 0, siteId?: string): Promise<any> {
|
getEntries(filter: any = {}, page: number = 0, siteId?: string): Promise<AddonBlogGetEntriesResult> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const data = {
|
const data = {
|
||||||
filters: this.utils.objectToArrayOfObjects(filter, 'name', 'value'),
|
filters: this.utils.objectToArrayOfObjects(filter, 'name', 'value'),
|
||||||
|
@ -105,7 +107,7 @@ export class AddonBlogProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise to be resolved when done.
|
* @return Promise to be resolved when done.
|
||||||
*/
|
*/
|
||||||
logView(filter: any = {}, siteId?: string): Promise<any> {
|
logView(filter: any = {}, siteId?: string): Promise<AddonBlogViewEntriesResult> {
|
||||||
this.pushNotificationsProvider.logViewListEvent('blog', 'core_blog_view_entries', filter, siteId);
|
this.pushNotificationsProvider.logViewListEvent('blog', 'core_blog_view_entries', filter, siteId);
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
@ -117,3 +119,48 @@ export class AddonBlogProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by blog's post_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonBlogPost = {
|
||||||
|
id: number; // Post/entry id.
|
||||||
|
module: string; // Where it was published the post (blog, blog_external...).
|
||||||
|
userid: number; // Post author.
|
||||||
|
courseid: number; // Course where the post was created.
|
||||||
|
groupid: number; // Group post was created for.
|
||||||
|
moduleid: number; // Module id where the post was created (not used anymore).
|
||||||
|
coursemoduleid: number; // Course module id where the post was created.
|
||||||
|
subject: string; // Post subject.
|
||||||
|
summary: string; // Post summary.
|
||||||
|
summaryformat: number; // Summary format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
content: string; // Post content.
|
||||||
|
uniquehash: string; // Post unique hash.
|
||||||
|
rating: number; // Post rating.
|
||||||
|
format: number; // Post content format.
|
||||||
|
attachment: string; // Post atachment.
|
||||||
|
publishstate: string; // Post publish state.
|
||||||
|
lastmodified: number; // When it was last modified.
|
||||||
|
created: number; // When it was created.
|
||||||
|
usermodified: number; // User that updated the post.
|
||||||
|
summaryfiles: CoreWSExternalFile[]; // Summaryfiles.
|
||||||
|
attachmentfiles?: CoreWSExternalFile[]; // Attachmentfiles.
|
||||||
|
tags?: CoreTagItem[]; // @since 3.7. Tags.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_blog_get_entries.
|
||||||
|
*/
|
||||||
|
export type AddonBlogGetEntriesResult = {
|
||||||
|
entries: AddonBlogPost[];
|
||||||
|
totalentries: number; // The total number of entries found.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_blog_view_entries.
|
||||||
|
*/
|
||||||
|
export type AddonBlogViewEntriesResult = {
|
||||||
|
status: boolean; // Status: true if success.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
|
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
|
||||||
import { AddonBlogEntriesComponent } from '../components/entries/entries';
|
import { AddonBlogEntriesComponent } from '../components/entries/entries';
|
||||||
import { AddonBlogProvider } from './blog';
|
import { AddonBlogProvider } from './blog';
|
||||||
|
import { CoreWSExternalFile } from '@providers/ws';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Course nav handler.
|
* Course nav handler.
|
||||||
|
@ -100,7 +101,7 @@ export class AddonBlogCourseOptionHandler implements CoreCourseOptionsHandler {
|
||||||
|
|
||||||
return this.blogProvider.getEntries({courseid: course.id}).then((result) => {
|
return this.blogProvider.getEntries({courseid: course.id}).then((result) => {
|
||||||
return result.entries.map((entry) => {
|
return result.entries.map((entry) => {
|
||||||
let files = [];
|
let files: CoreWSExternalFile[] = [];
|
||||||
|
|
||||||
if (entry.attachmentfiles && entry.attachmentfiles.length) {
|
if (entry.attachmentfiles && entry.attachmentfiles.length) {
|
||||||
files = entry.attachmentfiles;
|
files = entry.attachmentfiles;
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { AddonCalendarProvider } from '../../providers/calendar';
|
import { AddonCalendarProvider, AddonCalendarWeek } from '../../providers/calendar';
|
||||||
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
||||||
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
||||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
|
@ -44,7 +44,7 @@ export class AddonCalendarCalendarComponent implements OnInit, OnChanges, OnDest
|
||||||
|
|
||||||
periodName: string;
|
periodName: string;
|
||||||
weekDays: any[];
|
weekDays: any[];
|
||||||
weeks: any[];
|
weeks: AddonCalendarWeek[];
|
||||||
loaded = false;
|
loaded = false;
|
||||||
timeFormat: string;
|
timeFormat: string;
|
||||||
isCurrentMonth: boolean;
|
isCurrentMonth: boolean;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<ng-container *ngFor="let event of filteredEvents">
|
<ng-container *ngFor="let event of filteredEvents">
|
||||||
<a ion-item text-wrap [title]="event.name" (click)="eventClicked(event)" [class.core-split-item-selected]="event.id == eventId" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]">
|
<a ion-item text-wrap [title]="event.name" (click)="eventClicked(event)" [class.core-split-item-selected]="event.id == eventId" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]">
|
||||||
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
||||||
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
<core-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" item-start></core-icon>
|
||||||
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
||||||
<p><core-format-text [text]="event.formattedtime"></core-format-text></p>
|
<p><core-format-text [text]="event.formattedtime"></core-format-text></p>
|
||||||
<ion-note *ngIf="event.offline && !event.deleted" item-end>
|
<ion-note *ngIf="event.offline && !event.deleted" item-end>
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { AddonCalendarProvider } from '../../providers/calendar';
|
import { AddonCalendarProvider, AddonCalendarCalendarEvent } from '../../providers/calendar';
|
||||||
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
||||||
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
||||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
|
@ -43,8 +43,8 @@ export class AddonCalendarUpcomingEventsComponent implements OnInit, OnChanges,
|
||||||
protected categoriesRetrieved = false;
|
protected categoriesRetrieved = false;
|
||||||
protected categories = {};
|
protected categories = {};
|
||||||
protected currentSiteId: string;
|
protected currentSiteId: string;
|
||||||
protected events = []; // Events (both online and offline).
|
protected events: AddonCalendarCalendarEvent[] = []; // Events (both online and offline).
|
||||||
protected onlineEvents = [];
|
protected onlineEvents: AddonCalendarCalendarEvent[] = [];
|
||||||
protected offlineEvents = []; // Offline events.
|
protected offlineEvents = []; // Offline events.
|
||||||
protected deletedEvents = []; // Events deleted in offline.
|
protected deletedEvents = []; // Events deleted in offline.
|
||||||
protected lookAhead: number;
|
protected lookAhead: number;
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
<ng-container *ngFor="let event of filteredEvents">
|
<ng-container *ngFor="let event of filteredEvents">
|
||||||
<ion-item text-wrap [title]="event.name" (click)="gotoEvent(event.id)" [class.item-dimmed]="event.ispast" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]">
|
<ion-item text-wrap [title]="event.name" (click)="gotoEvent(event.id)" [class.item-dimmed]="event.ispast" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]">
|
||||||
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
||||||
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
<core-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" item-start></core-icon>
|
||||||
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
||||||
<p><core-format-text [text]="event.formattedtime"></core-format-text></p>
|
<p><core-format-text [text]="event.formattedtime"></core-format-text></p>
|
||||||
<ion-note *ngIf="event.offline && !event.deleted" item-end>
|
<ion-note *ngIf="event.offline && !event.deleted" item-end>
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { CoreLocalNotificationsProvider } from '@providers/local-notifications';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
import { AddonCalendarProvider } from '../../providers/calendar';
|
import { AddonCalendarProvider, AddonCalendarCalendarEvent } from '../../providers/calendar';
|
||||||
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
||||||
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
||||||
import { AddonCalendarSyncProvider } from '../../providers/calendar-sync';
|
import { AddonCalendarSyncProvider } from '../../providers/calendar-sync';
|
||||||
|
@ -45,7 +45,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
||||||
protected day: number;
|
protected day: number;
|
||||||
protected categories = {};
|
protected categories = {};
|
||||||
protected events = []; // Events (both online and offline).
|
protected events = []; // Events (both online and offline).
|
||||||
protected onlineEvents = [];
|
protected onlineEvents: AddonCalendarCalendarEvent[] = [];
|
||||||
protected offlineEvents = {}; // Offline events.
|
protected offlineEvents = {}; // Offline events.
|
||||||
protected offlineEditedEventsIds = []; // IDs of events edited in offline.
|
protected offlineEditedEventsIds = []; // IDs of events edited in offline.
|
||||||
protected deletedEvents = []; // Events deleted in offline.
|
protected deletedEvents = []; // Events deleted in offline.
|
||||||
|
@ -287,7 +287,7 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy {
|
||||||
return this.calendarProvider.getDayEvents(this.year, this.month, this.day).catch((error) => {
|
return this.calendarProvider.getDayEvents(this.year, this.month, this.day).catch((error) => {
|
||||||
if (!this.appProvider.isOnline()) {
|
if (!this.appProvider.isOnline()) {
|
||||||
// Allow navigating to non-cached days in offline (behave as if using emergency cache).
|
// Allow navigating to non-cached days in offline (behave as if using emergency cache).
|
||||||
return Promise.resolve({ events: [] });
|
return Promise.resolve({ events: <AddonCalendarCalendarEvent[]> [] });
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@
|
||||||
<div *ngIf="event && event.repeatid" text-wrap radio-group [formControlName]="'repeateditall'" class="addon-calendar-radio-container">
|
<div *ngIf="event && event.repeatid" text-wrap radio-group [formControlName]="'repeateditall'" class="addon-calendar-radio-container">
|
||||||
<ion-item class="addon-calendar-radio-title"><h2>{{ 'addon.calendar.repeatedevents' | translate }}</h2></ion-item>
|
<ion-item class="addon-calendar-radio-title"><h2>{{ 'addon.calendar.repeatedevents' | translate }}</h2></ion-item>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
<ion-label>{{ 'addon.calendar.repeateditall' | translate:{$a: event.othereventscount} }}</ion-label>
|
<ion-label>{{ 'addon.calendar.repeateditall' | translate:{$a: otherEventsCount} }}</ion-label>
|
||||||
<ion-radio [value]="1"></ion-radio>
|
<ion-radio [value]="1"></ion-radio>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { CoreRichTextEditorComponent } from '@components/rich-text-editor/rich-text-editor.ts';
|
import { CoreRichTextEditorComponent } from '@components/rich-text-editor/rich-text-editor.ts';
|
||||||
import { AddonCalendarProvider } from '../../providers/calendar';
|
import { AddonCalendarProvider, AddonCalendarGetAccessInfoResult, AddonCalendarEvent } from '../../providers/calendar';
|
||||||
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
||||||
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
||||||
import { AddonCalendarSyncProvider } from '../../providers/calendar-sync';
|
import { AddonCalendarSyncProvider } from '../../providers/calendar-sync';
|
||||||
|
@ -58,7 +58,8 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
||||||
courseGroupSet = false;
|
courseGroupSet = false;
|
||||||
advanced = false;
|
advanced = false;
|
||||||
errors: any;
|
errors: any;
|
||||||
event: any; // The event object (when editing an event).
|
event: AddonCalendarEvent; // The event object (when editing an event).
|
||||||
|
otherEventsCount: number;
|
||||||
|
|
||||||
// Form variables.
|
// Form variables.
|
||||||
eventForm: FormGroup;
|
eventForm: FormGroup;
|
||||||
|
@ -70,7 +71,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
||||||
protected courseId: number;
|
protected courseId: number;
|
||||||
protected originalData: any;
|
protected originalData: any;
|
||||||
protected currentSite: CoreSite;
|
protected currentSite: CoreSite;
|
||||||
protected types: any; // Object with the supported types.
|
protected types: {[name: string]: boolean}; // Object with the supported types.
|
||||||
protected showAll: boolean;
|
protected showAll: boolean;
|
||||||
protected isDestroyed = false;
|
protected isDestroyed = false;
|
||||||
protected error = false;
|
protected error = false;
|
||||||
|
@ -152,7 +153,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected fetchData(refresh?: boolean): Promise<any> {
|
protected fetchData(refresh?: boolean): Promise<any> {
|
||||||
let accessInfo;
|
let accessInfo: AddonCalendarGetAccessInfoResult;
|
||||||
|
|
||||||
this.error = false;
|
this.error = false;
|
||||||
|
|
||||||
|
@ -197,7 +198,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
||||||
promises.push(this.calendarProvider.getEventById(this.eventId).then((event) => {
|
promises.push(this.calendarProvider.getEventById(this.eventId).then((event) => {
|
||||||
this.event = event;
|
this.event = event;
|
||||||
if (event && event.repeatid) {
|
if (event && event.repeatid) {
|
||||||
event.othereventscount = event.eventcount ? event.eventcount - 1 : '';
|
this.otherEventsCount = event.eventcount ? event.eventcount - 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return event;
|
return event;
|
||||||
|
@ -489,7 +490,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
||||||
|
|
||||||
// Send the data.
|
// Send the data.
|
||||||
const modal = this.domUtils.showModalLoading('core.sending', true);
|
const modal = this.domUtils.showModalLoading('core.sending', true);
|
||||||
let event;
|
let event: AddonCalendarEvent;
|
||||||
|
|
||||||
this.calendarProvider.submitEvent(this.eventId, data).then((result) => {
|
this.calendarProvider.submitEvent(this.eventId, data).then((result) => {
|
||||||
event = result.event;
|
event = result.event;
|
||||||
|
@ -497,7 +498,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy {
|
||||||
if (result.sent) {
|
if (result.sent) {
|
||||||
// Event created or edited, invalidate right days & months.
|
// Event created or edited, invalidate right days & months.
|
||||||
const numberOfRepetitions = formData.repeat ? formData.repeats :
|
const numberOfRepetitions = formData.repeat ? formData.repeats :
|
||||||
(data.repeateditall && this.event.othereventscount ? this.event.othereventscount + 1 : 1);
|
(data.repeateditall && this.otherEventsCount ? this.otherEventsCount + 1 : 1);
|
||||||
|
|
||||||
return this.calendarHelper.refreshAfterChangeEvent(result.event, numberOfRepetitions).catch(() => {
|
return this.calendarHelper.refreshAfterChangeEvent(result.event, numberOfRepetitions).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<ion-navbar core-back-button>
|
<ion-navbar core-back-button>
|
||||||
<ion-title>
|
<ion-title>
|
||||||
<img *ngIf="event && event.moduleIcon" src="{{event.moduleIcon}}" alt="" role="presentation" class="core-module-icon">
|
<img *ngIf="event && event.moduleIcon" src="{{event.moduleIcon}}" alt="" role="presentation" class="core-module-icon">
|
||||||
<core-icon *ngIf="event && event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
<core-icon *ngIf="event && event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" item-start></core-icon>
|
||||||
<core-format-text *ngIf="event" [text]="event.name"></core-format-text>
|
<core-format-text *ngIf="event" [text]="event.name"></core-format-text>
|
||||||
</ion-title>
|
</ion-title>
|
||||||
<ion-buttons end>
|
<ion-buttons end>
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
<ion-card-content *ngIf="event">
|
<ion-card-content *ngIf="event">
|
||||||
<ion-item text-wrap *ngIf="isSplitViewOn">
|
<ion-item text-wrap *ngIf="isSplitViewOn">
|
||||||
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start alt="" role="presentation" class="core-module-icon">
|
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start alt="" role="presentation" class="core-module-icon">
|
||||||
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
<core-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" item-start></core-icon>
|
||||||
<h2>{{ 'addon.calendar.eventname' | translate }}</h2>
|
<h2>{{ 'addon.calendar.eventname' | translate }}</h2>
|
||||||
<p><core-format-text [text]="event.name"></core-format-text></p>
|
<p><core-format-text [text]="event.name"></core-format-text></p>
|
||||||
<ion-note item-end *ngIf="event.deleted">
|
<ion-note item-end *ngIf="event.deleted">
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
<a ion-item text-wrap [title]="event.name" (click)="gotoEvent(event.id)" [class.core-split-item-selected]="event.id == eventId" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]">
|
<a ion-item text-wrap [title]="event.name" (click)="gotoEvent(event.id)" [class.core-split-item-selected]="event.id == eventId" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]">
|
||||||
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" item-start class="core-module-icon">
|
||||||
<core-icon *ngIf="event.icon && !event.moduleIcon" [name]="event.icon" item-start></core-icon>
|
<core-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" item-start></core-icon>
|
||||||
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
<h2><core-format-text [text]="event.name"></core-format-text></h2>
|
||||||
<p>
|
<p>
|
||||||
{{ event.timestart * 1000 | coreFormatDate: "strftimetime" }}
|
{{ event.timestart * 1000 | coreFormatDate: "strftimetime" }}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
import { Component, ViewChild, OnDestroy, NgZone } from '@angular/core';
|
import { Component, ViewChild, OnDestroy, NgZone } from '@angular/core';
|
||||||
import { IonicPage, Content, NavParams, NavController } from 'ionic-angular';
|
import { IonicPage, Content, NavParams, NavController } from 'ionic-angular';
|
||||||
import { AddonCalendarProvider } from '../../providers/calendar';
|
import { AddonCalendarProvider, AddonCalendarGetEventsEvent } from '../../providers/calendar';
|
||||||
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
import { AddonCalendarOfflineProvider } from '../../providers/calendar-offline';
|
||||||
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
import { AddonCalendarHelperProvider } from '../../providers/helper';
|
||||||
import { AddonCalendarSyncProvider } from '../../providers/calendar-sync';
|
import { AddonCalendarSyncProvider } from '../../providers/calendar-sync';
|
||||||
|
@ -62,7 +62,7 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
protected manualSyncObserver: any;
|
protected manualSyncObserver: any;
|
||||||
protected onlineObserver: any;
|
protected onlineObserver: any;
|
||||||
protected currentSiteId: string;
|
protected currentSiteId: string;
|
||||||
protected onlineEvents = [];
|
protected onlineEvents: AddonCalendarGetEventsEvent[] = [];
|
||||||
protected offlineEvents = [];
|
protected offlineEvents = [];
|
||||||
protected deletedEvents = [];
|
protected deletedEvents = [];
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
eventsLoaded = false;
|
eventsLoaded = false;
|
||||||
events = []; // Events (both online and offline).
|
events = []; // Events (both online and offline).
|
||||||
notificationsEnabled = false;
|
notificationsEnabled = false;
|
||||||
filteredEvents = [];
|
filteredEvents: AddonCalendarGetEventsEvent[] = [];
|
||||||
canLoadMore = false;
|
canLoadMore = false;
|
||||||
loadMoreError = false;
|
loadMoreError = false;
|
||||||
courseId: number;
|
courseId: number;
|
||||||
|
@ -402,7 +402,7 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
*
|
*
|
||||||
* @return Filtered events.
|
* @return Filtered events.
|
||||||
*/
|
*/
|
||||||
protected getFilteredEvents(): any[] {
|
protected getFilteredEvents(): AddonCalendarGetEventsEvent[] {
|
||||||
if (!this.courseId) {
|
if (!this.courseId) {
|
||||||
// No filter, display everything.
|
// No filter, display everything.
|
||||||
return this.events;
|
return this.events;
|
||||||
|
@ -581,7 +581,7 @@ export class AddonCalendarListPage implements OnDestroy {
|
||||||
* @param event Event info.
|
* @param event Event info.
|
||||||
* @return If date has changed and should be shown.
|
* @return If date has changed and should be shown.
|
||||||
*/
|
*/
|
||||||
protected endsSameDay(event: any): boolean {
|
protected endsSameDay(event: AddonCalendarGetEventsEvent): boolean {
|
||||||
if (!event.timeduration) {
|
if (!event.timeduration) {
|
||||||
// No duration.
|
// No duration.
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -31,6 +31,7 @@ import { SQLiteDB } from '@classes/sqlitedb';
|
||||||
import { AddonCalendarOfflineProvider } from './calendar-offline';
|
import { AddonCalendarOfflineProvider } from './calendar-offline';
|
||||||
import { CoreUserProvider } from '@core/user/providers/user';
|
import { CoreUserProvider } from '@core/user/providers/user';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { CoreWSExternalWarning, CoreWSDate } from '@providers/ws';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -489,7 +490,7 @@ export class AddonCalendarProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
deleteEventOnline(eventId: number, deleteAll?: boolean, siteId?: string): Promise<any> {
|
deleteEventOnline(eventId: number, deleteAll?: boolean, siteId?: string): Promise<null> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
|
@ -535,22 +536,6 @@ export class AddonCalendarProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if event ends the same day or not.
|
|
||||||
*
|
|
||||||
* @param event Event info.
|
|
||||||
* @return If the .
|
|
||||||
*/
|
|
||||||
endsSameDay(event: any): boolean {
|
|
||||||
if (!event.timeduration) {
|
|
||||||
// No duration.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if day has changed.
|
|
||||||
return moment(event.timestart * 1000).isSame((event.timestart + event.timeduration) * 1000, 'day');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format event time. Similar to calendar_format_event_time.
|
* Format event time. Similar to calendar_format_event_time.
|
||||||
*
|
*
|
||||||
|
@ -562,8 +547,8 @@ export class AddonCalendarProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved with the formatted event time.
|
* @return Promise resolved with the formatted event time.
|
||||||
*/
|
*/
|
||||||
formatEventTime(event: any, format: string, useCommonWords: boolean = true, seenDay?: number, showTime: number = 0,
|
formatEventTime(event: AddonCalendarAnyEvent, format: string, useCommonWords: boolean = true, seenDay?: number,
|
||||||
siteId?: string): Promise<string> {
|
showTime: number = 0, siteId?: string): Promise<string> {
|
||||||
|
|
||||||
const start = event.timestart * 1000,
|
const start = event.timestart * 1000,
|
||||||
end = (event.timestart + event.timeduration) * 1000;
|
end = (event.timestart + event.timeduration) * 1000;
|
||||||
|
@ -635,7 +620,7 @@ export class AddonCalendarProvider {
|
||||||
* @return Promise resolved with object with access information.
|
* @return Promise resolved with object with access information.
|
||||||
* @since 3.7
|
* @since 3.7
|
||||||
*/
|
*/
|
||||||
getAccessInformation(courseId?: number, siteId?: string): Promise<any> {
|
getAccessInformation(courseId?: number, siteId?: string): Promise<AddonCalendarGetAccessInfoResult> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params: any = {},
|
const params: any = {},
|
||||||
preSets = {
|
preSets = {
|
||||||
|
@ -680,7 +665,7 @@ export class AddonCalendarProvider {
|
||||||
* @return Promise resolved with an object indicating the types.
|
* @return Promise resolved with an object indicating the types.
|
||||||
* @since 3.7
|
* @since 3.7
|
||||||
*/
|
*/
|
||||||
getAllowedEventTypes(courseId?: number, siteId?: string): Promise<any> {
|
getAllowedEventTypes(courseId?: number, siteId?: string): Promise<{[name: string]: boolean}> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params: any = {},
|
const params: any = {},
|
||||||
preSets = {
|
preSets = {
|
||||||
|
@ -691,7 +676,8 @@ export class AddonCalendarProvider {
|
||||||
params.courseid = courseId;
|
params.courseid = courseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('core_calendar_get_allowed_event_types', params, preSets).then((response) => {
|
return site.read('core_calendar_get_allowed_event_types', params, preSets)
|
||||||
|
.then((response: AddonCalendarGetAllowedEventTypesResult) => {
|
||||||
// Convert the array to an object.
|
// Convert the array to an object.
|
||||||
const result = {};
|
const result = {};
|
||||||
|
|
||||||
|
@ -812,11 +798,10 @@ export class AddonCalendarProvider {
|
||||||
* Get a calendar event. If the server request fails and data is not cached, try to get it from local DB.
|
* Get a calendar event. If the server request fails and data is not cached, try to get it from local DB.
|
||||||
*
|
*
|
||||||
* @param id Event ID.
|
* @param id Event ID.
|
||||||
* @param refresh True when we should update the event data.
|
|
||||||
* @param siteId ID of the site. If not defined, use current site.
|
* @param siteId ID of the site. If not defined, use current site.
|
||||||
* @return Promise resolved when the event data is retrieved.
|
* @return Promise resolved when the event data is retrieved.
|
||||||
*/
|
*/
|
||||||
getEvent(id: number, siteId?: string): Promise<any> {
|
getEvent(id: number, siteId?: string): Promise<AddonCalendarGetEventsEvent> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const preSets = {
|
const preSets = {
|
||||||
cacheKey: this.getEventCacheKey(id),
|
cacheKey: this.getEventCacheKey(id),
|
||||||
|
@ -834,7 +819,8 @@ export class AddonCalendarProvider {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_calendar_get_calendar_events', data, preSets).then((response) => {
|
return site.read('core_calendar_get_calendar_events', data, preSets)
|
||||||
|
.then((response: AddonCalendarGetEventsResult) => {
|
||||||
// The WebService returns all category events. Check the response to search for the event we want.
|
// The WebService returns all category events. Check the response to search for the event we want.
|
||||||
const event = response.events.find((e) => { return e.id == id; });
|
const event = response.events.find((e) => { return e.id == id; });
|
||||||
|
|
||||||
|
@ -849,12 +835,11 @@ export class AddonCalendarProvider {
|
||||||
* Get a calendar event by ID. This function returns more data than getEvent, but it isn't available in all Moodles.
|
* Get a calendar event by ID. This function returns more data than getEvent, but it isn't available in all Moodles.
|
||||||
*
|
*
|
||||||
* @param id Event ID.
|
* @param id Event ID.
|
||||||
* @param refresh True when we should update the event data.
|
|
||||||
* @param siteId ID of the site. If not defined, use current site.
|
* @param siteId ID of the site. If not defined, use current site.
|
||||||
* @return Promise resolved when the event data is retrieved.
|
* @return Promise resolved when the event data is retrieved.
|
||||||
* @since 3.4
|
* @since 3.4
|
||||||
*/
|
*/
|
||||||
getEventById(id: number, siteId?: string): Promise<any> {
|
getEventById(id: number, siteId?: string): Promise<AddonCalendarEvent> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const preSets = {
|
const preSets = {
|
||||||
cacheKey: this.getEventCacheKey(id),
|
cacheKey: this.getEventCacheKey(id),
|
||||||
|
@ -864,7 +849,8 @@ export class AddonCalendarProvider {
|
||||||
eventid: id
|
eventid: id
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_calendar_get_calendar_event_by_id', data, preSets).then((response) => {
|
return site.read('core_calendar_get_calendar_event_by_id', data, preSets)
|
||||||
|
.then((response: AddonCalendarGetEventByIdResult) => {
|
||||||
return response.event;
|
return response.event;
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
return this.getEventFromLocalDb(id).catch(() => {
|
return this.getEventFromLocalDb(id).catch(() => {
|
||||||
|
@ -918,7 +904,7 @@ export class AddonCalendarProvider {
|
||||||
* @param siteId ID of the site the event belongs to. If not defined, use current site.
|
* @param siteId ID of the site the event belongs to. If not defined, use current site.
|
||||||
* @return Promise resolved when the notification is updated.
|
* @return Promise resolved when the notification is updated.
|
||||||
*/
|
*/
|
||||||
addEventReminder(event: any, time: number, siteId?: string): Promise<any> {
|
addEventReminder(event: AddonCalendarAnyEvent, time: number, siteId?: string): Promise<any> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const reminder = {
|
const reminder = {
|
||||||
eventid: event.id,
|
eventid: event.id,
|
||||||
|
@ -976,7 +962,7 @@ export class AddonCalendarProvider {
|
||||||
* @return Promise resolved with the response.
|
* @return Promise resolved with the response.
|
||||||
*/
|
*/
|
||||||
getDayEvents(year: number, month: number, day: number, courseId?: number, categoryId?: number, ignoreCache?: boolean,
|
getDayEvents(year: number, month: number, day: number, courseId?: number, categoryId?: number, ignoreCache?: boolean,
|
||||||
siteId?: string): Promise<any> {
|
siteId?: string): Promise<AddonCalendarCalendarDay> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
|
||||||
|
@ -1003,7 +989,7 @@ export class AddonCalendarProvider {
|
||||||
preSets.emergencyCache = false;
|
preSets.emergencyCache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('core_calendar_get_calendar_day_view', data, preSets).then((response) => {
|
return site.read('core_calendar_get_calendar_day_view', data, preSets).then((response: AddonCalendarCalendarDay) => {
|
||||||
this.storeEventsInLocalDB(response.events, siteId);
|
this.storeEventsInLocalDB(response.events, siteId);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
@ -1071,10 +1057,10 @@ export class AddonCalendarProvider {
|
||||||
* @param daysToStart Number of days from now to start getting events.
|
* @param daysToStart Number of days from now to start getting events.
|
||||||
* @param daysInterval Number of days between timestart and timeend.
|
* @param daysInterval Number of days between timestart and timeend.
|
||||||
* @param siteId Site to get the events from. If not defined, use current site.
|
* @param siteId Site to get the events from. If not defined, use current site.
|
||||||
* @return Promise to be resolved when the participants are retrieved.
|
* @return Promise to be resolved when the events are retrieved.
|
||||||
*/
|
*/
|
||||||
getEventsList(initialTime?: number, daysToStart: number = 0, daysInterval: number = AddonCalendarProvider.DAYS_INTERVAL,
|
getEventsList(initialTime?: number, daysToStart: number = 0, daysInterval: number = AddonCalendarProvider.DAYS_INTERVAL,
|
||||||
siteId?: string): Promise<any[]> {
|
siteId?: string): Promise<AddonCalendarGetEventsEvent[]> {
|
||||||
|
|
||||||
initialTime = initialTime || this.timeUtils.timestamp();
|
initialTime = initialTime || this.timeUtils.timestamp();
|
||||||
|
|
||||||
|
@ -1122,7 +1108,9 @@ export class AddonCalendarProvider {
|
||||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_calendar_get_calendar_events', data, preSets).then((response) => {
|
return site.read('core_calendar_get_calendar_events', data, preSets)
|
||||||
|
.then((response: AddonCalendarGetEventsResult) => {
|
||||||
|
|
||||||
if (!this.canViewMonthInSite(site)) {
|
if (!this.canViewMonthInSite(site)) {
|
||||||
// Store events only in 3.1-3.3. In 3.4+ we'll use the new WS that return more info.
|
// Store events only in 3.1-3.3. In 3.4+ we'll use the new WS that return more info.
|
||||||
this.storeEventsInLocalDB(response.events, siteId);
|
this.storeEventsInLocalDB(response.events, siteId);
|
||||||
|
@ -1178,7 +1166,7 @@ export class AddonCalendarProvider {
|
||||||
* @return Promise resolved with the response.
|
* @return Promise resolved with the response.
|
||||||
*/
|
*/
|
||||||
getMonthlyEvents(year: number, month: number, courseId?: number, categoryId?: number, ignoreCache?: boolean, siteId?: string)
|
getMonthlyEvents(year: number, month: number, courseId?: number, categoryId?: number, ignoreCache?: boolean, siteId?: string)
|
||||||
: Promise<any> {
|
: Promise<AddonCalendarMonth> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
|
||||||
|
@ -1210,7 +1198,9 @@ export class AddonCalendarProvider {
|
||||||
preSets.emergencyCache = false;
|
preSets.emergencyCache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('core_calendar_get_calendar_monthly_view', data, preSets).then((response) => {
|
return site.read('core_calendar_get_calendar_monthly_view', data, preSets)
|
||||||
|
.then((response: AddonCalendarMonth) => {
|
||||||
|
|
||||||
response.weeks.forEach((week) => {
|
response.weeks.forEach((week) => {
|
||||||
week.days.forEach((day) => {
|
week.days.forEach((day) => {
|
||||||
this.storeEventsInLocalDB(day.events, siteId);
|
this.storeEventsInLocalDB(day.events, siteId);
|
||||||
|
@ -1270,7 +1260,8 @@ export class AddonCalendarProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved with the response.
|
* @return Promise resolved with the response.
|
||||||
*/
|
*/
|
||||||
getUpcomingEvents(courseId?: number, categoryId?: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
getUpcomingEvents(courseId?: number, categoryId?: number, ignoreCache?: boolean, siteId?: string)
|
||||||
|
: Promise<AddonCalendarUpcoming> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
|
||||||
|
@ -1293,7 +1284,7 @@ export class AddonCalendarProvider {
|
||||||
preSets.emergencyCache = false;
|
preSets.emergencyCache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('core_calendar_get_calendar_upcoming_view', data, preSets).then((response) => {
|
return site.read('core_calendar_get_calendar_upcoming_view', data, preSets).then((response: AddonCalendarUpcoming) => {
|
||||||
this.storeEventsInLocalDB(response.events, siteId);
|
this.storeEventsInLocalDB(response.events, siteId);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
@ -1604,11 +1595,14 @@ export class AddonCalendarProvider {
|
||||||
* If local notification plugin is not enabled, resolve the promise.
|
* If local notification plugin is not enabled, resolve the promise.
|
||||||
*
|
*
|
||||||
* @param event Event to schedule.
|
* @param event Event to schedule.
|
||||||
|
* @param reminderId The reminder ID.
|
||||||
* @param time Notification setting time (in minutes). E.g. 10 means "notificate 10 minutes before start".
|
* @param time Notification setting time (in minutes). E.g. 10 means "notificate 10 minutes before start".
|
||||||
* @param siteId Site ID the event belongs to. If not defined, use current site.
|
* @param siteId Site ID the event belongs to. If not defined, use current site.
|
||||||
* @return Promise resolved when the notification is scheduled.
|
* @return Promise resolved when the notification is scheduled.
|
||||||
*/
|
*/
|
||||||
protected scheduleEventNotification(event: any, reminderId: number, time: number, siteId?: string): Promise<void> {
|
protected scheduleEventNotification(event: AddonCalendarAnyEvent, reminderId: number, time: number, siteId?: string)
|
||||||
|
: Promise<void> {
|
||||||
|
|
||||||
if (this.localNotificationsProvider.isAvailable()) {
|
if (this.localNotificationsProvider.isAvailable()) {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
|
@ -1672,7 +1666,7 @@ export class AddonCalendarProvider {
|
||||||
* @param siteId ID of the site the events belong to. If not defined, use current site.
|
* @param siteId ID of the site the events belong to. If not defined, use current site.
|
||||||
* @return Promise resolved when all the notifications have been scheduled.
|
* @return Promise resolved when all the notifications have been scheduled.
|
||||||
*/
|
*/
|
||||||
scheduleEventsNotifications(events: any[], siteId?: string): Promise<any[]> {
|
scheduleEventsNotifications(events: AddonCalendarAnyEvent[], siteId?: string): Promise<any[]> {
|
||||||
|
|
||||||
if (this.localNotificationsProvider.isAvailable()) {
|
if (this.localNotificationsProvider.isAvailable()) {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
@ -1803,11 +1797,10 @@ export class AddonCalendarProvider {
|
||||||
* @param timeCreated The time the event was created. Only if modifying a new offline event.
|
* @param timeCreated The time the event was created. Only if modifying a new offline event.
|
||||||
* @param forceOffline True to always save it in offline.
|
* @param forceOffline True to always save it in offline.
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved with the event and a boolean indicating if data was
|
* @return Promise resolved with the event and a boolean indicating if data was sent to server or stored in offline.
|
||||||
* sent to server or stored in offline.
|
|
||||||
*/
|
*/
|
||||||
submitEvent(eventId: number, formData: any, timeCreated?: number, forceOffline?: boolean, siteId?: string):
|
submitEvent(eventId: number, formData: any, timeCreated?: number, forceOffline?: boolean, siteId?: string):
|
||||||
Promise<{sent: boolean, event: any}> {
|
Promise<{sent: boolean, event: AddonCalendarEvent}> {
|
||||||
|
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
|
@ -1847,7 +1840,7 @@ export class AddonCalendarProvider {
|
||||||
* @param siteId Site ID. If not provided, current site.
|
* @param siteId Site ID. If not provided, current site.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
submitEventOnline(eventId: number, formData: any, siteId?: string): Promise<any> {
|
submitEventOnline(eventId: number, formData: any, siteId?: string): Promise<AddonCalendarEvent> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
// Add data that is "hidden" in web.
|
// Add data that is "hidden" in web.
|
||||||
formData.id = eventId || 0;
|
formData.id = eventId || 0;
|
||||||
|
@ -1865,10 +1858,12 @@ export class AddonCalendarProvider {
|
||||||
formdata: this.utils.objectToGetParams(formData)
|
formdata: this.utils.objectToGetParams(formData)
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.write('core_calendar_submit_create_update_form', params).then((result) => {
|
return site.write('core_calendar_submit_create_update_form', params)
|
||||||
|
.then((result: AddonCalendarSubmitCreateUpdateFormResult): AddonCalendarEvent => {
|
||||||
|
|
||||||
if (result.validationerror) {
|
if (result.validationerror) {
|
||||||
// Simulate a WS error.
|
// Simulate a WS error.
|
||||||
return Promise.reject({
|
return <any> Promise.reject({
|
||||||
message: this.translate.instant('core.invalidformdata'),
|
message: this.translate.instant('core.invalidformdata'),
|
||||||
errorcode: 'validationerror'
|
errorcode: 'validationerror'
|
||||||
});
|
});
|
||||||
|
@ -1879,3 +1874,337 @@ export class AddonCalendarProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's events_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarEvents = {
|
||||||
|
events: AddonCalendarEvent[]; // Events.
|
||||||
|
firstid: number; // Firstid.
|
||||||
|
lastid: number; // Lastid.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's events_grouped_by_course_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarEventsGroupedByCourse = {
|
||||||
|
groupedbycourse: AddonCalendarEventsSameCourse[]; // Groupped by course.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's events_same_course_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarEventsSameCourse = AddonCalendarEvents & {
|
||||||
|
courseid: number; // Courseid.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's event_exporter_base.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarEventBase = {
|
||||||
|
id: number; // Id.
|
||||||
|
name: string; // Name.
|
||||||
|
description?: string; // Description.
|
||||||
|
descriptionformat: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
location?: string; // Location.
|
||||||
|
categoryid?: number; // Categoryid.
|
||||||
|
groupid?: number; // Groupid.
|
||||||
|
userid?: number; // Userid.
|
||||||
|
repeatid?: number; // Repeatid.
|
||||||
|
eventcount?: number; // Eventcount.
|
||||||
|
modulename?: string; // Modulename.
|
||||||
|
instance?: number; // Instance.
|
||||||
|
eventtype: string; // Eventtype.
|
||||||
|
timestart: number; // Timestart.
|
||||||
|
timeduration: number; // Timeduration.
|
||||||
|
timesort: number; // Timesort.
|
||||||
|
visible: number; // Visible.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
icon: {
|
||||||
|
key: string; // Key.
|
||||||
|
component: string; // Component.
|
||||||
|
alttext: string; // Alttext.
|
||||||
|
};
|
||||||
|
category?: {
|
||||||
|
id: number; // Id.
|
||||||
|
name: string; // Name.
|
||||||
|
idnumber: string; // Idnumber.
|
||||||
|
description?: string; // Description.
|
||||||
|
parent: number; // Parent.
|
||||||
|
coursecount: number; // Coursecount.
|
||||||
|
visible: number; // Visible.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
depth: number; // Depth.
|
||||||
|
nestedname: string; // Nestedname.
|
||||||
|
url: string; // Url.
|
||||||
|
};
|
||||||
|
course?: {
|
||||||
|
id: number; // Id.
|
||||||
|
fullname: string; // Fullname.
|
||||||
|
shortname: string; // Shortname.
|
||||||
|
idnumber: string; // Idnumber.
|
||||||
|
summary: string; // Summary.
|
||||||
|
summaryformat: number; // Summary format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
startdate: number; // Startdate.
|
||||||
|
enddate: number; // Enddate.
|
||||||
|
visible: boolean; // Visible.
|
||||||
|
fullnamedisplay: string; // Fullnamedisplay.
|
||||||
|
viewurl: string; // Viewurl.
|
||||||
|
courseimage: string; // Courseimage.
|
||||||
|
progress?: number; // Progress.
|
||||||
|
hasprogress: boolean; // Hasprogress.
|
||||||
|
isfavourite: boolean; // Isfavourite.
|
||||||
|
hidden: boolean; // Hidden.
|
||||||
|
timeaccess?: number; // Timeaccess.
|
||||||
|
showshortname: boolean; // Showshortname.
|
||||||
|
coursecategory: string; // Coursecategory.
|
||||||
|
};
|
||||||
|
subscription?: {
|
||||||
|
displayeventsource: boolean; // Displayeventsource.
|
||||||
|
subscriptionname?: string; // Subscriptionname.
|
||||||
|
subscriptionurl?: string; // Subscriptionurl.
|
||||||
|
};
|
||||||
|
canedit: boolean; // Canedit.
|
||||||
|
candelete: boolean; // Candelete.
|
||||||
|
deleteurl: string; // Deleteurl.
|
||||||
|
editurl: string; // Editurl.
|
||||||
|
viewurl: string; // Viewurl.
|
||||||
|
formattedtime: string; // Formattedtime.
|
||||||
|
isactionevent: boolean; // Isactionevent.
|
||||||
|
iscourseevent: boolean; // Iscourseevent.
|
||||||
|
iscategoryevent: boolean; // Iscategoryevent.
|
||||||
|
groupname?: string; // Groupname.
|
||||||
|
normalisedeventtype: string; // Normalisedeventtype.
|
||||||
|
normalisedeventtypetext: string; // Normalisedeventtypetext.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's event_exporter. Don't confuse it with AddonCalendarCalendarEvent.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarEvent = AddonCalendarEventBase & {
|
||||||
|
url: string; // Url.
|
||||||
|
action?: {
|
||||||
|
name: string; // Name.
|
||||||
|
url: string; // Url.
|
||||||
|
itemcount: number; // Itemcount.
|
||||||
|
actionable: boolean; // Actionable.
|
||||||
|
showitemcount: boolean; // Showitemcount.
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's calendar_event_exporter. Don't confuse it with AddonCalendarEvent.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarCalendarEvent = AddonCalendarEventBase & {
|
||||||
|
url: string; // Url.
|
||||||
|
islastday: boolean; // Islastday.
|
||||||
|
popupname: string; // Popupname.
|
||||||
|
mindaytimestamp?: number; // Mindaytimestamp.
|
||||||
|
mindayerror?: string; // Mindayerror.
|
||||||
|
maxdaytimestamp?: number; // Maxdaytimestamp.
|
||||||
|
maxdayerror?: string; // Maxdayerror.
|
||||||
|
draggable: boolean; // Draggable.
|
||||||
|
} & AddonCalendarCalendarEventCalculatedData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any of the possible types of events.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarAnyEvent = AddonCalendarGetEventsEvent | AddonCalendarEvent | AddonCalendarCalendarEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's calendar_day_exporter. Don't confuse it with AddonCalendarDay.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarCalendarDay = {
|
||||||
|
events: AddonCalendarCalendarEvent[]; // Events.
|
||||||
|
defaulteventcontext: number; // Defaulteventcontext.
|
||||||
|
filter_selector: string; // Filter_selector.
|
||||||
|
courseid: number; // Courseid.
|
||||||
|
categoryid?: number; // Categoryid.
|
||||||
|
neweventtimestamp: number; // Neweventtimestamp.
|
||||||
|
date: CoreWSDate;
|
||||||
|
periodname: string; // Periodname.
|
||||||
|
previousperiod: CoreWSDate;
|
||||||
|
previousperiodlink: string; // Previousperiodlink.
|
||||||
|
previousperiodname: string; // Previousperiodname.
|
||||||
|
nextperiod: CoreWSDate;
|
||||||
|
nextperiodname: string; // Nextperiodname.
|
||||||
|
nextperiodlink: string; // Nextperiodlink.
|
||||||
|
larrow: string; // Larrow.
|
||||||
|
rarrow: string; // Rarrow.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's month_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarMonth = {
|
||||||
|
url: string; // Url.
|
||||||
|
courseid: number; // Courseid.
|
||||||
|
categoryid?: number; // Categoryid.
|
||||||
|
filter_selector?: string; // Filter_selector.
|
||||||
|
weeks: AddonCalendarWeek[]; // Weeks.
|
||||||
|
daynames: AddonCalendarDayName[]; // Daynames.
|
||||||
|
view: string; // View.
|
||||||
|
date: CoreWSDate;
|
||||||
|
periodname: string; // Periodname.
|
||||||
|
includenavigation: boolean; // Includenavigation.
|
||||||
|
initialeventsloaded: boolean; // Initialeventsloaded.
|
||||||
|
previousperiod: CoreWSDate;
|
||||||
|
previousperiodlink: string; // Previousperiodlink.
|
||||||
|
previousperiodname: string; // Previousperiodname.
|
||||||
|
nextperiod: CoreWSDate;
|
||||||
|
nextperiodname: string; // Nextperiodname.
|
||||||
|
nextperiodlink: string; // Nextperiodlink.
|
||||||
|
larrow: string; // Larrow.
|
||||||
|
rarrow: string; // Rarrow.
|
||||||
|
defaulteventcontext: number; // Defaulteventcontext.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's week_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarWeek = {
|
||||||
|
prepadding: number[]; // Prepadding.
|
||||||
|
postpadding: number[]; // Postpadding.
|
||||||
|
days: AddonCalendarWeekDay[]; // Days.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's week_day_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarWeekDay = AddonCalendarDay & {
|
||||||
|
istoday: boolean; // Istoday.
|
||||||
|
isweekend: boolean; // Isweekend.
|
||||||
|
popovertitle: string; // Popovertitle.
|
||||||
|
ispast?: boolean; // Calculated in the app. Whether the day is in the past.
|
||||||
|
filteredEvents?: AddonCalendarCalendarEvent[]; // Calculated in the app. Filtered events.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's day_exporter. Don't confuse it with AddonCalendarCalendarDay.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarDay = {
|
||||||
|
seconds: number; // Seconds.
|
||||||
|
minutes: number; // Minutes.
|
||||||
|
hours: number; // Hours.
|
||||||
|
mday: number; // Mday.
|
||||||
|
wday: number; // Wday.
|
||||||
|
year: number; // Year.
|
||||||
|
yday: number; // Yday.
|
||||||
|
timestamp: number; // Timestamp.
|
||||||
|
neweventtimestamp: number; // Neweventtimestamp.
|
||||||
|
viewdaylink?: string; // Viewdaylink.
|
||||||
|
events: AddonCalendarCalendarEvent[]; // Events.
|
||||||
|
hasevents: boolean; // Hasevents.
|
||||||
|
calendareventtypes: string[]; // Calendareventtypes.
|
||||||
|
previousperiod: number; // Previousperiod.
|
||||||
|
nextperiod: number; // Nextperiod.
|
||||||
|
navigation: string; // Navigation.
|
||||||
|
haslastdayofevent: boolean; // Haslastdayofevent.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's day_name_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarDayName = {
|
||||||
|
dayno: number; // Dayno.
|
||||||
|
shortname: string; // Shortname.
|
||||||
|
fullname: string; // Fullname.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by calendar's calendar_upcoming_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarUpcoming = {
|
||||||
|
events: AddonCalendarCalendarEvent[]; // Events.
|
||||||
|
defaulteventcontext: number; // Defaulteventcontext.
|
||||||
|
filter_selector: string; // Filter_selector.
|
||||||
|
courseid: number; // Courseid.
|
||||||
|
categoryid?: number; // Categoryid.
|
||||||
|
isloggedin: boolean; // Isloggedin.
|
||||||
|
date: CoreWSDate; // Date.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_calendar_get_calendar_access_information.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarGetAccessInfoResult = {
|
||||||
|
canmanageentries: boolean; // Whether the user can manage entries.
|
||||||
|
canmanageownentries: boolean; // Whether the user can manage its own entries.
|
||||||
|
canmanagegroupentries: boolean; // Whether the user can manage group entries.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_calendar_get_allowed_event_types.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarGetAllowedEventTypesResult = {
|
||||||
|
allowedeventtypes: string[];
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_calendar_get_calendar_events.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarGetEventsResult = {
|
||||||
|
events: AddonCalendarGetEventsEvent[];
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event data returned by WS core_calendar_get_calendar_events.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarGetEventsEvent = {
|
||||||
|
id: number; // Event id.
|
||||||
|
name: string; // Event name.
|
||||||
|
description?: string; // Description.
|
||||||
|
format: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
courseid: number; // Course id.
|
||||||
|
categoryid?: number; // @since 3.4. Category id (only for category events).
|
||||||
|
groupid: number; // Group id.
|
||||||
|
userid: number; // User id.
|
||||||
|
repeatid: number; // Repeat id.
|
||||||
|
modulename?: string; // Module name.
|
||||||
|
instance: number; // Instance id.
|
||||||
|
eventtype: string; // Event type.
|
||||||
|
timestart: number; // Timestart.
|
||||||
|
timeduration: number; // Time duration.
|
||||||
|
visible: number; // Visible.
|
||||||
|
uuid?: string; // Unique id of ical events.
|
||||||
|
sequence: number; // Sequence.
|
||||||
|
timemodified: number; // Time modified.
|
||||||
|
subscriptionid?: number; // Subscription id.
|
||||||
|
showDate?: boolean; // Calculated in the app. Whether date should be shown before this event.
|
||||||
|
endsSameDay?: boolean; // Calculated in the app. Whether the event finishes the same day it starts.
|
||||||
|
deleted?: boolean; // Calculated in the app. Whether it has been deleted in offline.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_calendar_get_calendar_event_by_id.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarGetEventByIdResult = {
|
||||||
|
event: AddonCalendarEvent; // Event.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_calendar_submit_create_update_form.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarSubmitCreateUpdateFormResult = {
|
||||||
|
event?: AddonCalendarEvent; // Event.
|
||||||
|
validationerror: boolean; // Invalid form data.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated data for AddonCalendarCalendarEvent.
|
||||||
|
*/
|
||||||
|
export type AddonCalendarCalendarEventCalculatedData = {
|
||||||
|
eventIcon?: string; // Calculated in the app. Event icon.
|
||||||
|
moduleIcon?: string; // Calculated in the app. Module icon.
|
||||||
|
formattedType?: string; // Calculated in the app. Formatted type.
|
||||||
|
duration?: number; // Calculated in the app. Duration of offline event.
|
||||||
|
format?: number; // Calculated in the app. Format of offline event.
|
||||||
|
timedurationuntil?: number; // Calculated in the app. Time duration until of offline event.
|
||||||
|
timedurationminutes?: number; // Calculated in the app. Time duration in minutes of offline event.
|
||||||
|
deleted?: boolean; // Calculated in the app. Whether it has been deleted in offline.
|
||||||
|
ispast?: boolean; // Calculated in the app. Whether the event is in the past.
|
||||||
|
};
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { AddonCalendarProvider } from './calendar';
|
import { AddonCalendarProvider, AddonCalendarCalendarEvent } from './calendar';
|
||||||
import { CoreConstants } from '@core/constants';
|
import { CoreConstants } from '@core/constants';
|
||||||
import { CoreConfigProvider } from '@providers/config';
|
import { CoreConfigProvider } from '@providers/config';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
|
@ -130,11 +130,11 @@ export class AddonCalendarHelperProvider {
|
||||||
*
|
*
|
||||||
* @param e Event to format.
|
* @param e Event to format.
|
||||||
*/
|
*/
|
||||||
formatEventData(e: any): void {
|
formatEventData(e: AddonCalendarCalendarEvent): void {
|
||||||
e.icon = this.EVENTICONS[e.eventtype] || false;
|
e.eventIcon = this.EVENTICONS[e.eventtype] || '';
|
||||||
if (!e.icon) {
|
if (!e.eventIcon) {
|
||||||
e.icon = this.courseProvider.getModuleIconSrc(e.modulename);
|
e.eventIcon = this.courseProvider.getModuleIconSrc(e.modulename);
|
||||||
e.moduleIcon = e.icon;
|
e.moduleIcon = e.eventIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.formattedType = this.calendarProvider.getEventType(e);
|
e.formattedType = this.calendarProvider.getEventType(e);
|
||||||
|
@ -160,7 +160,7 @@ export class AddonCalendarHelperProvider {
|
||||||
* @param eventTypes Result of getAllowedEventTypes.
|
* @param eventTypes Result of getAllowedEventTypes.
|
||||||
* @return Options.
|
* @return Options.
|
||||||
*/
|
*/
|
||||||
getEventTypeOptions(eventTypes: any): {name: string, value: string}[] {
|
getEventTypeOptions(eventTypes: {[name: string]: boolean}): {name: string, value: string}[] {
|
||||||
const options = [];
|
const options = [];
|
||||||
|
|
||||||
if (eventTypes.user) {
|
if (eventTypes.user) {
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Component, ViewChild, Input } from '@angular/core';
|
||||||
import { Content, NavController } from 'ionic-angular';
|
import { Content, NavController } from 'ionic-angular';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { AddonCompetencyProvider } from '../../providers/competency';
|
import { AddonCompetencyProvider, AddonCompetencyDataForCourseCompetenciesPageResult } from '../../providers/competency';
|
||||||
import { AddonCompetencyHelperProvider } from '../../providers/helper';
|
import { AddonCompetencyHelperProvider } from '../../providers/helper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,7 +33,7 @@ export class AddonCompetencyCourseComponent {
|
||||||
@Input() userId: number;
|
@Input() userId: number;
|
||||||
|
|
||||||
competenciesLoaded = false;
|
competenciesLoaded = false;
|
||||||
competencies: any;
|
competencies: AddonCompetencyDataForCourseCompetenciesPageResult;
|
||||||
user: any;
|
user: any;
|
||||||
|
|
||||||
constructor(private navCtrl: NavController, private appProvider: CoreAppProvider, private domUtils: CoreDomUtilsProvider,
|
constructor(private navCtrl: NavController, private appProvider: CoreAppProvider, private domUtils: CoreDomUtilsProvider,
|
||||||
|
|
|
@ -17,7 +17,10 @@ import { IonicPage, NavParams } from 'ionic-angular';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { AddonCompetencyProvider } from '../../providers/competency';
|
import {
|
||||||
|
AddonCompetencyProvider, AddonCompetencyDataForCourseCompetenciesPageResult, AddonCompetencyDataForPlanPageResult,
|
||||||
|
AddonCompetencyDataForPlanPageCompetency, AddonCompetencyDataForCourseCompetenciesPageCompetency
|
||||||
|
} from '../../providers/competency';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the list of competencies of a learning plan.
|
* Page that displays the list of competencies of a learning plan.
|
||||||
|
@ -36,7 +39,7 @@ export class AddonCompetencyCompetenciesPage {
|
||||||
protected userId: number;
|
protected userId: number;
|
||||||
|
|
||||||
competenciesLoaded = false;
|
competenciesLoaded = false;
|
||||||
competencies = [];
|
competencies: AddonCompetencyDataForPlanPageCompetency[] | AddonCompetencyDataForCourseCompetenciesPageCompetency[] = [];
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
constructor(navParams: NavParams, private translate: TranslateService, private domUtils: CoreDomUtilsProvider,
|
constructor(navParams: NavParams, private translate: TranslateService, private domUtils: CoreDomUtilsProvider,
|
||||||
|
@ -59,7 +62,7 @@ export class AddonCompetencyCompetenciesPage {
|
||||||
this.fetchCompetencies().then(() => {
|
this.fetchCompetencies().then(() => {
|
||||||
if (!this.competencyId && this.splitviewCtrl.isOn() && this.competencies.length > 0) {
|
if (!this.competencyId && this.splitviewCtrl.isOn() && this.competencies.length > 0) {
|
||||||
// Take first and load it.
|
// Take first and load it.
|
||||||
this.openCompetency(this.competencies[0].id);
|
this.openCompetency(this.competencies[0].competency.id);
|
||||||
}
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.competenciesLoaded = true;
|
this.competenciesLoaded = true;
|
||||||
|
@ -72,7 +75,7 @@ export class AddonCompetencyCompetenciesPage {
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected fetchCompetencies(): Promise<void> {
|
protected fetchCompetencies(): Promise<void> {
|
||||||
let promise;
|
let promise: Promise<AddonCompetencyDataForPlanPageResult | AddonCompetencyDataForCourseCompetenciesPageResult>;
|
||||||
|
|
||||||
if (this.planId) {
|
if (this.planId) {
|
||||||
promise = this.competencyProvider.getLearningPlan(this.planId);
|
promise = this.competencyProvider.getLearningPlan(this.planId);
|
||||||
|
@ -83,13 +86,16 @@ export class AddonCompetencyCompetenciesPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise.then((response) => {
|
return promise.then((response) => {
|
||||||
if (response.competencycount <= 0) {
|
|
||||||
|
if (this.planId) {
|
||||||
|
const resp = <AddonCompetencyDataForPlanPageResult> response;
|
||||||
|
|
||||||
|
if (resp.competencycount <= 0) {
|
||||||
return Promise.reject(this.translate.instant('addon.competency.errornocompetenciesfound'));
|
return Promise.reject(this.translate.instant('addon.competency.errornocompetenciesfound'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.planId) {
|
this.title = resp.plan.name;
|
||||||
this.title = response.plan.name;
|
this.userId = resp.plan.userid;
|
||||||
this.userId = response.plan.userid;
|
|
||||||
} else {
|
} else {
|
||||||
this.title = this.translate.instant('addon.competency.coursecompetencies');
|
this.title = this.translate.instant('addon.competency.coursecompetencies');
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,22 +51,22 @@
|
||||||
<core-format-text [text]="activity.name"></core-format-text>
|
<core-format-text [text]="activity.name"></core-format-text>
|
||||||
</a>
|
</a>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item text-wrap *ngIf="competency.usercompetency.status">
|
<ion-item text-wrap *ngIf="userCompetency.status">
|
||||||
<strong>{{ 'addon.competency.reviewstatus' | translate }}</strong>
|
<strong>{{ 'addon.competency.reviewstatus' | translate }}</strong>
|
||||||
{{ competency.usercompetency.statusname }}
|
{{ userCompetency.statusname }}
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item text-wrap>
|
<ion-item text-wrap>
|
||||||
<strong>{{ 'addon.competency.proficient' | translate }}</strong>
|
<strong>{{ 'addon.competency.proficient' | translate }}</strong>
|
||||||
<ion-badge color="success" *ngIf="competency.usercompetency.proficiency">
|
<ion-badge color="success" *ngIf="userCompetency.proficiency">
|
||||||
{{ 'core.yes' | translate }}
|
{{ 'core.yes' | translate }}
|
||||||
</ion-badge>
|
</ion-badge>
|
||||||
<ion-badge color="danger" *ngIf="!competency.usercompetency.proficiency">
|
<ion-badge color="danger" *ngIf="!userCompetency.proficiency">
|
||||||
{{ 'core.no' | translate }}
|
{{ 'core.no' | translate }}
|
||||||
</ion-badge>
|
</ion-badge>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item text-wrap>
|
<ion-item text-wrap>
|
||||||
<strong>{{ 'addon.competency.rating' | translate }}</strong>
|
<strong>{{ 'addon.competency.rating' | translate }}</strong>
|
||||||
<ion-badge color="dark">{{ competency.usercompetency.gradename }}</ion-badge>
|
<ion-badge color="dark">{{ userCompetency.gradename }}</ion-badge>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
</ion-card>
|
</ion-card>
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,14 @@ import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { AddonCompetencyProvider } from '../../providers/competency';
|
import {
|
||||||
|
AddonCompetencyProvider, AddonCompetencyUserCompetencySummary, AddonCompetencyUserCompetencySummaryInPlan,
|
||||||
|
AddonCompetencyUserCompetencySummaryInCourse, AddonCompetencyUserCompetencyPlan,
|
||||||
|
AddonCompetencyUserCompetency, AddonCompetencyUserCompetencyCourse
|
||||||
|
} from '../../providers/competency';
|
||||||
import { AddonCompetencyHelperProvider } from '../../providers/helper';
|
import { AddonCompetencyHelperProvider } from '../../providers/helper';
|
||||||
|
import { CoreUserSummary } from '@core/user/providers/user';
|
||||||
|
import { CoreCourseModuleSummary } from '@core/course/providers/course';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays a learning plan.
|
* Page that displays a learning plan.
|
||||||
|
@ -36,9 +42,10 @@ export class AddonCompetencyCompetencyPage {
|
||||||
courseId: number;
|
courseId: number;
|
||||||
userId: number;
|
userId: number;
|
||||||
planStatus: number;
|
planStatus: number;
|
||||||
coursemodules: any;
|
coursemodules: CoreCourseModuleSummary[];
|
||||||
user: any;
|
user: CoreUserSummary;
|
||||||
competency: any;
|
competency: AddonCompetencyUserCompetencySummary;
|
||||||
|
userCompetency: AddonCompetencyUserCompetencyPlan | AddonCompetencyUserCompetency | AddonCompetencyUserCompetencyCourse;
|
||||||
|
|
||||||
constructor(private navCtrl: NavController, navParams: NavParams, private translate: TranslateService,
|
constructor(private navCtrl: NavController, navParams: NavParams, private translate: TranslateService,
|
||||||
private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider,
|
private sitesProvider: CoreSitesProvider, private domUtils: CoreDomUtilsProvider,
|
||||||
|
@ -79,7 +86,8 @@ export class AddonCompetencyCompetencyPage {
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected fetchCompetency(): Promise<void> {
|
protected fetchCompetency(): Promise<void> {
|
||||||
let promise;
|
let promise: Promise<AddonCompetencyUserCompetencySummaryInPlan | AddonCompetencyUserCompetencySummaryInCourse>;
|
||||||
|
|
||||||
if (this.planId) {
|
if (this.planId) {
|
||||||
this.planStatus = null;
|
this.planStatus = null;
|
||||||
promise = this.competencyProvider.getCompetencyInPlan(this.planId, this.competencyId);
|
promise = this.competencyProvider.getCompetencyInPlan(this.planId, this.competencyId);
|
||||||
|
@ -90,23 +98,21 @@ export class AddonCompetencyCompetencyPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise.then((competency) => {
|
return promise.then((competency) => {
|
||||||
competency.usercompetencysummary.usercompetency = competency.usercompetencysummary.usercompetencyplan ||
|
|
||||||
competency.usercompetencysummary.usercompetency;
|
|
||||||
this.competency = competency.usercompetencysummary;
|
this.competency = competency.usercompetencysummary;
|
||||||
|
this.userCompetency = this.competency.usercompetencyplan || this.competency.usercompetency;
|
||||||
|
|
||||||
if (this.planId) {
|
if (this.planId) {
|
||||||
this.planStatus = competency.plan.status;
|
this.planStatus = (<AddonCompetencyUserCompetencySummaryInPlan> competency).plan.status;
|
||||||
this.competency.usercompetency.statusname =
|
this.competency.usercompetency.statusname =
|
||||||
this.competencyHelperProvider.getCompetencyStatusName(this.competency.usercompetency.status);
|
this.competencyHelperProvider.getCompetencyStatusName(this.competency.usercompetency.status);
|
||||||
} else {
|
} else {
|
||||||
this.competency.usercompetency = this.competency.usercompetencycourse;
|
this.userCompetency = this.competency.usercompetencycourse;
|
||||||
this.coursemodules = competency.coursemodules;
|
this.coursemodules = (<AddonCompetencyUserCompetencySummaryInCourse> competency).coursemodules;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.competency.user.id != this.sitesProvider.getCurrentSiteUserId()) {
|
if (this.competency.user.id != this.sitesProvider.getCurrentSiteUserId()) {
|
||||||
this.competency.user.profileimageurl = this.competency.user.profileimageurl || true;
|
// Get the user profile from the returned object.
|
||||||
|
|
||||||
// Get the user profile image from the returned object.
|
|
||||||
this.user = this.competency.user;
|
this.user = this.competency.user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Component, Optional } from '@angular/core';
|
||||||
import { IonicPage, NavController, NavParams } from 'ionic-angular';
|
import { IonicPage, NavController, NavParams } from 'ionic-angular';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { AddonCompetencyProvider } from '../../providers/competency';
|
import { AddonCompetencyProvider, AddonCompetencySummary } from '../../providers/competency';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays a learning plan.
|
* Page that displays a learning plan.
|
||||||
|
@ -29,7 +29,7 @@ import { AddonCompetencyProvider } from '../../providers/competency';
|
||||||
export class AddonCompetencyCompetencySummaryPage {
|
export class AddonCompetencyCompetencySummaryPage {
|
||||||
competencyLoaded = false;
|
competencyLoaded = false;
|
||||||
competencyId: number;
|
competencyId: number;
|
||||||
competency: any;
|
competency: AddonCompetencySummary;
|
||||||
|
|
||||||
constructor(private navCtrl: NavController, navParams: NavParams, private domUtils: CoreDomUtilsProvider,
|
constructor(private navCtrl: NavController, navParams: NavParams, private domUtils: CoreDomUtilsProvider,
|
||||||
@Optional() private svComponent: CoreSplitViewComponent, private competencyProvider: AddonCompetencyProvider) {
|
@Optional() private svComponent: CoreSplitViewComponent, private competencyProvider: AddonCompetencyProvider) {
|
||||||
|
@ -41,8 +41,7 @@ export class AddonCompetencyCompetencySummaryPage {
|
||||||
*/
|
*/
|
||||||
ionViewDidLoad(): void {
|
ionViewDidLoad(): void {
|
||||||
this.fetchCompetency().then(() => {
|
this.fetchCompetency().then(() => {
|
||||||
const name = this.competency.competency && this.competency.competency.competency &&
|
const name = this.competency.competency && this.competency.competency.shortname;
|
||||||
this.competency.competency.competency.shortname;
|
|
||||||
|
|
||||||
this.competencyProvider.logCompetencyView(this.competencyId, name).catch(() => {
|
this.competencyProvider.logCompetencyView(this.competencyId, name).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
|
|
|
@ -46,7 +46,8 @@
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<a ion-item text-wrap *ngFor="let competency of plan.competencies" (click)="openCompetency(competency.competency.id)" [title]="competency.competency.shortname">
|
<a ion-item text-wrap *ngFor="let competency of plan.competencies" (click)="openCompetency(competency.competency.id)" [title]="competency.competency.shortname">
|
||||||
<h2>{{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em></h2>
|
<h2>{{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em></h2>
|
||||||
<ion-badge item-end [color]="competency.usercompetency.proficiency ? 'success' : 'danger'">{{ competency.usercompetency.gradename }}</ion-badge>
|
<ion-badge *ngIf="competency.usercompetencyplan" item-end [color]="competency.usercompetencyplan.proficiency ? 'success' : 'danger'">{{ competency.usercompetencyplan.gradename }}</ion-badge>
|
||||||
|
<ion-badge *ngIf="!competency.usercompetencyplan" item-end [color]="competency.usercompetency.proficiency ? 'success' : 'danger'">{{ competency.usercompetency.gradename }}</ion-badge>
|
||||||
</a>
|
</a>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
</ion-card>
|
</ion-card>
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { IonicPage, NavController, NavParams } from 'ionic-angular';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { AddonCompetencyProvider } from '../../providers/competency';
|
import { AddonCompetencyProvider, AddonCompetencyDataForPlanPageResult } from '../../providers/competency';
|
||||||
import { AddonCompetencyHelperProvider } from '../../providers/helper';
|
import { AddonCompetencyHelperProvider } from '../../providers/helper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,7 +31,7 @@ import { AddonCompetencyHelperProvider } from '../../providers/helper';
|
||||||
export class AddonCompetencyPlanPage {
|
export class AddonCompetencyPlanPage {
|
||||||
protected planId: number;
|
protected planId: number;
|
||||||
planLoaded = false;
|
planLoaded = false;
|
||||||
plan: any;
|
plan: AddonCompetencyDataForPlanPageResult;
|
||||||
user: any;
|
user: any;
|
||||||
|
|
||||||
constructor(private navCtrl: NavController, navParams: NavParams, private appProvider: CoreAppProvider,
|
constructor(private navCtrl: NavController, navParams: NavParams, private appProvider: CoreAppProvider,
|
||||||
|
@ -62,9 +62,6 @@ export class AddonCompetencyPlanPage {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
});
|
});
|
||||||
|
|
||||||
plan.competencies.forEach((competency) => {
|
|
||||||
competency.usercompetency = competency.usercompetencyplan || competency.usercompetency;
|
|
||||||
});
|
|
||||||
this.plan = plan;
|
this.plan = plan;
|
||||||
}).catch((message) => {
|
}).catch((message) => {
|
||||||
this.domUtils.showErrorModalDefault(message, 'Error getting learning plan data.');
|
this.domUtils.showErrorModalDefault(message, 'Error getting learning plan data.');
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Component, ViewChild } from '@angular/core';
|
||||||
import { IonicPage, NavParams } from 'ionic-angular';
|
import { IonicPage, NavParams } from 'ionic-angular';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { AddonCompetencyProvider } from '../../providers/competency';
|
import { AddonCompetencyProvider, AddonCompetencyPlan } from '../../providers/competency';
|
||||||
import { AddonCompetencyHelperProvider } from '../../providers/helper';
|
import { AddonCompetencyHelperProvider } from '../../providers/helper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,7 +33,7 @@ export class AddonCompetencyPlanListPage {
|
||||||
protected userId: number;
|
protected userId: number;
|
||||||
protected planId: number;
|
protected planId: number;
|
||||||
plansLoaded = false;
|
plansLoaded = false;
|
||||||
plans = [];
|
plans: AddonCompetencyPlan[] = [];
|
||||||
|
|
||||||
constructor(navParams: NavParams, private domUtils: CoreDomUtilsProvider, private competencyProvider: AddonCompetencyProvider,
|
constructor(navParams: NavParams, private domUtils: CoreDomUtilsProvider, private competencyProvider: AddonCompetencyProvider,
|
||||||
private competencyHelperProvider: AddonCompetencyHelperProvider) {
|
private competencyHelperProvider: AddonCompetencyHelperProvider) {
|
||||||
|
@ -66,7 +66,7 @@ export class AddonCompetencyPlanListPage {
|
||||||
*/
|
*/
|
||||||
protected fetchLearningPlans(): Promise<void> {
|
protected fetchLearningPlans(): Promise<void> {
|
||||||
return this.competencyProvider.getLearningPlans(this.userId).then((plans) => {
|
return this.competencyProvider.getLearningPlans(this.userId).then((plans) => {
|
||||||
plans.forEach((plan) => {
|
plans.forEach((plan: AddonCompetencyPlanFormatted) => {
|
||||||
plan.statusname = this.competencyHelperProvider.getPlanStatusName(plan.status);
|
plan.statusname = this.competencyHelperProvider.getPlanStatusName(plan.status);
|
||||||
switch (plan.status) {
|
switch (plan.status) {
|
||||||
case AddonCompetencyProvider.STATUS_ACTIVE:
|
case AddonCompetencyProvider.STATUS_ACTIVE:
|
||||||
|
@ -109,3 +109,10 @@ export class AddonCompetencyPlanListPage {
|
||||||
this.splitviewCtrl.push('AddonCompetencyPlanPage', { planId });
|
this.splitviewCtrl.push('AddonCompetencyPlanPage', { planId });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Competency plan with some calculated data.
|
||||||
|
*/
|
||||||
|
type AddonCompetencyPlanFormatted = AddonCompetencyPlan & {
|
||||||
|
statuscolor?: string; // Calculated in the app. Color of the plan's status.
|
||||||
|
};
|
||||||
|
|
|
@ -17,6 +17,9 @@ import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
|
import { CoreCommentsArea } from '@core/comments/providers/comments';
|
||||||
|
import { CoreUserSummary } from '@core/user/providers/user';
|
||||||
|
import { CoreCourseSummary, CoreCourseModuleSummary } from '@core/course/providers/course';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle caompetency learning plans.
|
* Service to handle caompetency learning plans.
|
||||||
|
@ -147,7 +150,7 @@ export class AddonCompetencyProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise to be resolved when the plans are retrieved.
|
* @return Promise to be resolved when the plans are retrieved.
|
||||||
*/
|
*/
|
||||||
getLearningPlans(userId?: number, siteId?: string): Promise<any> {
|
getLearningPlans(userId?: number, siteId?: string): Promise<AddonCompetencyPlan[]> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
|
||||||
|
@ -161,7 +164,9 @@ export class AddonCompetencyProvider {
|
||||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('tool_lp_data_for_plans_page', params, preSets).then((response) => {
|
return site.read('tool_lp_data_for_plans_page', params, preSets)
|
||||||
|
.then((response: AddonCompetencyDataForPlansPageResult): any => {
|
||||||
|
|
||||||
if (response.plans) {
|
if (response.plans) {
|
||||||
return response.plans;
|
return response.plans;
|
||||||
}
|
}
|
||||||
|
@ -176,9 +181,9 @@ export class AddonCompetencyProvider {
|
||||||
*
|
*
|
||||||
* @param planId ID of the plan.
|
* @param planId ID of the plan.
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise to be resolved when the plans are retrieved.
|
* @return Promise to be resolved when the plan is retrieved.
|
||||||
*/
|
*/
|
||||||
getLearningPlan(planId: number, siteId?: string): Promise<any> {
|
getLearningPlan(planId: number, siteId?: string): Promise<AddonCompetencyDataForPlanPageResult> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
|
||||||
this.logger.debug('Get plan ' + planId);
|
this.logger.debug('Get plan ' + planId);
|
||||||
|
@ -191,7 +196,9 @@ export class AddonCompetencyProvider {
|
||||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('tool_lp_data_for_plan_page', params, preSets).then((response) => {
|
return site.read('tool_lp_data_for_plan_page', params, preSets)
|
||||||
|
.then((response: AddonCompetencyDataForPlanPageResult): any => {
|
||||||
|
|
||||||
if (response.plan) {
|
if (response.plan) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
@ -207,9 +214,11 @@ export class AddonCompetencyProvider {
|
||||||
* @param planId ID of the plan.
|
* @param planId ID of the plan.
|
||||||
* @param competencyId ID of the competency.
|
* @param competencyId ID of the competency.
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise to be resolved when the plans are retrieved.
|
* @return Promise to be resolved when the competency is retrieved.
|
||||||
*/
|
*/
|
||||||
getCompetencyInPlan(planId: number, competencyId: number, siteId?: string): Promise<any> {
|
getCompetencyInPlan(planId: number, competencyId: number, siteId?: string)
|
||||||
|
: Promise<AddonCompetencyUserCompetencySummaryInPlan> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
|
||||||
this.logger.debug('Get competency ' + competencyId + ' in plan ' + planId);
|
this.logger.debug('Get competency ' + competencyId + ' in plan ' + planId);
|
||||||
|
@ -223,7 +232,9 @@ export class AddonCompetencyProvider {
|
||||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('tool_lp_data_for_user_competency_summary_in_plan', params, preSets).then((response) => {
|
return site.read('tool_lp_data_for_user_competency_summary_in_plan', params, preSets)
|
||||||
|
.then((response: AddonCompetencyUserCompetencySummaryInPlan): any => {
|
||||||
|
|
||||||
if (response.usercompetencysummary) {
|
if (response.usercompetencysummary) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
@ -241,10 +252,10 @@ export class AddonCompetencyProvider {
|
||||||
* @param userId ID of the user. If not defined, current user.
|
* @param userId ID of the user. If not defined, current user.
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return Promise to be resolved when the plans are retrieved.
|
* @return Promise to be resolved when the competency is retrieved.
|
||||||
*/
|
*/
|
||||||
getCompetencyInCourse(courseId: number, competencyId: number, userId?: number, siteId?: string, ignoreCache?: boolean)
|
getCompetencyInCourse(courseId: number, competencyId: number, userId?: number, siteId?: string, ignoreCache?: boolean)
|
||||||
: Promise<any> {
|
: Promise<AddonCompetencyUserCompetencySummaryInCourse> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
@ -266,7 +277,9 @@ export class AddonCompetencyProvider {
|
||||||
preSets.emergencyCache = false;
|
preSets.emergencyCache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('tool_lp_data_for_user_competency_summary_in_course', params, preSets).then((response) => {
|
return site.read('tool_lp_data_for_user_competency_summary_in_course', params, preSets)
|
||||||
|
.then((response: AddonCompetencyUserCompetencySummaryInCourse): any => {
|
||||||
|
|
||||||
if (response.usercompetencysummary) {
|
if (response.usercompetencysummary) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
@ -283,9 +296,11 @@ export class AddonCompetencyProvider {
|
||||||
* @param userId ID of the user. If not defined, current user.
|
* @param userId ID of the user. If not defined, current user.
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return Promise to be resolved when the plans are retrieved.
|
* @return Promise to be resolved when the competency summary is retrieved.
|
||||||
*/
|
*/
|
||||||
getCompetencySummary(competencyId: number, userId?: number, siteId?: string, ignoreCache?: boolean): Promise<any> {
|
getCompetencySummary(competencyId: number, userId?: number, siteId?: string, ignoreCache?: boolean)
|
||||||
|
: Promise<AddonCompetencySummary> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
|
||||||
|
@ -305,7 +320,9 @@ export class AddonCompetencyProvider {
|
||||||
preSets.emergencyCache = false;
|
preSets.emergencyCache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('tool_lp_data_for_user_competency_summary', params, preSets).then((response) => {
|
return site.read('tool_lp_data_for_user_competency_summary', params, preSets)
|
||||||
|
.then((response: AddonCompetencyUserCompetencySummary): any => {
|
||||||
|
|
||||||
if (response.competency) {
|
if (response.competency) {
|
||||||
return response.competency;
|
return response.competency;
|
||||||
}
|
}
|
||||||
|
@ -324,7 +341,9 @@ export class AddonCompetencyProvider {
|
||||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return Promise to be resolved when the course competencies are retrieved.
|
* @return Promise to be resolved when the course competencies are retrieved.
|
||||||
*/
|
*/
|
||||||
getCourseCompetencies(courseId: number, userId?: number, siteId?: string, ignoreCache?: boolean): Promise<any> {
|
getCourseCompetencies(courseId: number, userId?: number, siteId?: string, ignoreCache?: boolean)
|
||||||
|
: Promise<AddonCompetencyDataForCourseCompetenciesPageResult> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
|
||||||
this.logger.debug('Get course competencies for course ' + courseId);
|
this.logger.debug('Get course competencies for course ' + courseId);
|
||||||
|
@ -342,7 +361,9 @@ export class AddonCompetencyProvider {
|
||||||
preSets.emergencyCache = false;
|
preSets.emergencyCache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('tool_lp_data_for_course_competencies_page', params, preSets).then((response) => {
|
return site.read('tool_lp_data_for_course_competencies_page', params, preSets)
|
||||||
|
.then((response: AddonCompetencyDataForCourseCompetenciesPageResult): any => {
|
||||||
|
|
||||||
if (response.competencies) {
|
if (response.competencies) {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
@ -356,11 +377,13 @@ export class AddonCompetencyProvider {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
const promises = response.competencies.map((competency) =>
|
let promises: Promise<AddonCompetencyUserCompetencySummaryInCourse>[];
|
||||||
|
|
||||||
|
promises = response.competencies.map((competency) =>
|
||||||
this.getCompetencyInCourse(courseId, competency.competency.id, userId, siteId)
|
this.getCompetencyInCourse(courseId, competency.competency.id, userId, siteId)
|
||||||
);
|
);
|
||||||
|
|
||||||
return Promise.all(promises).then((responses: any[]) => {
|
return Promise.all(promises).then((responses: AddonCompetencyUserCompetencySummaryInCourse[]) => {
|
||||||
responses.forEach((resp, index) => {
|
responses.forEach((resp, index) => {
|
||||||
response.competencies[index].usercompetencycourse = resp.usercompetencysummary.usercompetencycourse;
|
response.competencies[index].usercompetencycourse = resp.usercompetencysummary.usercompetencycourse;
|
||||||
});
|
});
|
||||||
|
@ -486,7 +509,7 @@ export class AddonCompetencyProvider {
|
||||||
* @return Promise resolved when the WS call is successful.
|
* @return Promise resolved when the WS call is successful.
|
||||||
*/
|
*/
|
||||||
logCompetencyInPlanView(planId: number, competencyId: number, planStatus: number, name?: string, userId?: number,
|
logCompetencyInPlanView(planId: number, competencyId: number, planStatus: number, name?: string, userId?: number,
|
||||||
siteId?: string): Promise<any> {
|
siteId?: string): Promise<void> {
|
||||||
if (planId && competencyId) {
|
if (planId && competencyId) {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
@ -509,7 +532,11 @@ export class AddonCompetencyProvider {
|
||||||
userid: userId
|
userid: userId
|
||||||
}, siteId);
|
}, siteId);
|
||||||
|
|
||||||
return site.write(wsName, params, preSets);
|
return site.write(wsName, params, preSets).then((success: boolean) => {
|
||||||
|
if (!success) {
|
||||||
|
return Promise.reject(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,7 +554,7 @@ export class AddonCompetencyProvider {
|
||||||
* @return Promise resolved when the WS call is successful.
|
* @return Promise resolved when the WS call is successful.
|
||||||
*/
|
*/
|
||||||
logCompetencyInCourseView(courseId: number, competencyId: number, name?: string, userId?: number, siteId?: string)
|
logCompetencyInCourseView(courseId: number, competencyId: number, name?: string, userId?: number, siteId?: string)
|
||||||
: Promise<any> {
|
: Promise<void> {
|
||||||
|
|
||||||
if (courseId && competencyId) {
|
if (courseId && competencyId) {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
@ -548,7 +575,11 @@ export class AddonCompetencyProvider {
|
||||||
userid: userId
|
userid: userId
|
||||||
}, siteId);
|
}, siteId);
|
||||||
|
|
||||||
return site.write(wsName, params, preSets);
|
return site.write(wsName, params, preSets).then((success: boolean) => {
|
||||||
|
if (!success) {
|
||||||
|
return Promise.reject(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,7 +594,7 @@ export class AddonCompetencyProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved when the WS call is successful.
|
* @return Promise resolved when the WS call is successful.
|
||||||
*/
|
*/
|
||||||
logCompetencyView(competencyId: number, name?: string, siteId?: string): Promise<any> {
|
logCompetencyView(competencyId: number, name?: string, siteId?: string): Promise<void> {
|
||||||
if (competencyId) {
|
if (competencyId) {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
|
@ -576,10 +607,401 @@ export class AddonCompetencyProvider {
|
||||||
|
|
||||||
this.pushNotificationsProvider.logViewEvent(competencyId, name, 'competency', wsName, {}, siteId);
|
this.pushNotificationsProvider.logViewEvent(competencyId, name, 'competency', wsName, {}, siteId);
|
||||||
|
|
||||||
return site.write('core_competency_competency_viewed', params, preSets);
|
return site.write(wsName, params, preSets).then((success: boolean) => {
|
||||||
|
if (!success) {
|
||||||
|
return Promise.reject(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(null);
|
return Promise.reject(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's plan_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyPlan = {
|
||||||
|
name: string; // Name.
|
||||||
|
description: string; // Description.
|
||||||
|
descriptionformat: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
userid: number; // Userid.
|
||||||
|
templateid: number; // Templateid.
|
||||||
|
origtemplateid: number; // Origtemplateid.
|
||||||
|
status: number; // Status.
|
||||||
|
duedate: number; // Duedate.
|
||||||
|
reviewerid: number; // Reviewerid.
|
||||||
|
id: number; // Id.
|
||||||
|
timecreated: number; // Timecreated.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
usermodified: number; // Usermodified.
|
||||||
|
statusname: string; // Statusname.
|
||||||
|
isbasedontemplate: boolean; // Isbasedontemplate.
|
||||||
|
canmanage: boolean; // Canmanage.
|
||||||
|
canrequestreview: boolean; // Canrequestreview.
|
||||||
|
canreview: boolean; // Canreview.
|
||||||
|
canbeedited: boolean; // Canbeedited.
|
||||||
|
isactive: boolean; // Isactive.
|
||||||
|
isdraft: boolean; // Isdraft.
|
||||||
|
iscompleted: boolean; // Iscompleted.
|
||||||
|
isinreview: boolean; // Isinreview.
|
||||||
|
iswaitingforreview: boolean; // Iswaitingforreview.
|
||||||
|
isreopenallowed: boolean; // Isreopenallowed.
|
||||||
|
iscompleteallowed: boolean; // Iscompleteallowed.
|
||||||
|
isunlinkallowed: boolean; // Isunlinkallowed.
|
||||||
|
isrequestreviewallowed: boolean; // Isrequestreviewallowed.
|
||||||
|
iscancelreviewrequestallowed: boolean; // Iscancelreviewrequestallowed.
|
||||||
|
isstartreviewallowed: boolean; // Isstartreviewallowed.
|
||||||
|
isstopreviewallowed: boolean; // Isstopreviewallowed.
|
||||||
|
isapproveallowed: boolean; // Isapproveallowed.
|
||||||
|
isunapproveallowed: boolean; // Isunapproveallowed.
|
||||||
|
duedateformatted: string; // Duedateformatted.
|
||||||
|
commentarea: CoreCommentsArea;
|
||||||
|
reviewer?: CoreUserSummary;
|
||||||
|
template?: AddonCompetencyTemplate;
|
||||||
|
url: string; // Url.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's template_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyTemplate = {
|
||||||
|
shortname: string; // Shortname.
|
||||||
|
description: string; // Description.
|
||||||
|
descriptionformat: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
duedate: number; // Duedate.
|
||||||
|
visible: boolean; // Visible.
|
||||||
|
contextid: number; // Contextid.
|
||||||
|
id: number; // Id.
|
||||||
|
timecreated: number; // Timecreated.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
usermodified: number; // Usermodified.
|
||||||
|
duedateformatted: string; // Duedateformatted.
|
||||||
|
cohortscount: number; // Cohortscount.
|
||||||
|
planscount: number; // Planscount.
|
||||||
|
canmanage: boolean; // Canmanage.
|
||||||
|
canread: boolean; // Canread.
|
||||||
|
contextname: string; // Contextname.
|
||||||
|
contextnamenoprefix: string; // Contextnamenoprefix.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's competency_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyCompetency = {
|
||||||
|
shortname: string; // Shortname.
|
||||||
|
idnumber: string; // Idnumber.
|
||||||
|
description: string; // Description.
|
||||||
|
descriptionformat: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
sortorder: number; // Sortorder.
|
||||||
|
parentid: number; // Parentid.
|
||||||
|
path: string; // Path.
|
||||||
|
ruleoutcome: number; // Ruleoutcome.
|
||||||
|
ruletype: string; // Ruletype.
|
||||||
|
ruleconfig: string; // Ruleconfig.
|
||||||
|
scaleid: number; // Scaleid.
|
||||||
|
scaleconfiguration: string; // Scaleconfiguration.
|
||||||
|
competencyframeworkid: number; // Competencyframeworkid.
|
||||||
|
id: number; // Id.
|
||||||
|
timecreated: number; // Timecreated.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
usermodified: number; // Usermodified.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's competency_path_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyPath = {
|
||||||
|
ancestors: AddonCompetencyPathNode[]; // Ancestors.
|
||||||
|
framework: AddonCompetencyPathNode;
|
||||||
|
pluginbaseurl: string; // Pluginbaseurl.
|
||||||
|
pagecontextid: number; // Pagecontextid.
|
||||||
|
showlinks: boolean; // Showlinks.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's path_node_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyPathNode = {
|
||||||
|
id: number; // Id.
|
||||||
|
name: string; // Name.
|
||||||
|
first: boolean; // First.
|
||||||
|
last: boolean; // Last.
|
||||||
|
position: number; // Position.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's user_competency_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyUserCompetency = {
|
||||||
|
userid: number; // Userid.
|
||||||
|
competencyid: number; // Competencyid.
|
||||||
|
status: number; // Status.
|
||||||
|
reviewerid: number; // Reviewerid.
|
||||||
|
proficiency: boolean; // Proficiency.
|
||||||
|
grade: number; // Grade.
|
||||||
|
id: number; // Id.
|
||||||
|
timecreated: number; // Timecreated.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
usermodified: number; // Usermodified.
|
||||||
|
canrequestreview: boolean; // Canrequestreview.
|
||||||
|
canreview: boolean; // Canreview.
|
||||||
|
gradename: string; // Gradename.
|
||||||
|
isrequestreviewallowed: boolean; // Isrequestreviewallowed.
|
||||||
|
iscancelreviewrequestallowed: boolean; // Iscancelreviewrequestallowed.
|
||||||
|
isstartreviewallowed: boolean; // Isstartreviewallowed.
|
||||||
|
isstopreviewallowed: boolean; // Isstopreviewallowed.
|
||||||
|
isstatusidle: boolean; // Isstatusidle.
|
||||||
|
isstatusinreview: boolean; // Isstatusinreview.
|
||||||
|
isstatuswaitingforreview: boolean; // Isstatuswaitingforreview.
|
||||||
|
proficiencyname: string; // Proficiencyname.
|
||||||
|
reviewer?: CoreUserSummary;
|
||||||
|
statusname: string; // Statusname.
|
||||||
|
url: string; // Url.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's user_competency_plan_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyUserCompetencyPlan = {
|
||||||
|
userid: number; // Userid.
|
||||||
|
competencyid: number; // Competencyid.
|
||||||
|
proficiency: boolean; // Proficiency.
|
||||||
|
grade: number; // Grade.
|
||||||
|
planid: number; // Planid.
|
||||||
|
sortorder: number; // Sortorder.
|
||||||
|
id: number; // Id.
|
||||||
|
timecreated: number; // Timecreated.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
usermodified: number; // Usermodified.
|
||||||
|
gradename: string; // Gradename.
|
||||||
|
proficiencyname: string; // Proficiencyname.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's user_competency_summary_in_plan_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyUserCompetencySummaryInPlan = {
|
||||||
|
usercompetencysummary: AddonCompetencyUserCompetencySummary;
|
||||||
|
plan: AddonCompetencyPlan;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's user_competency_summary_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyUserCompetencySummary = {
|
||||||
|
showrelatedcompetencies: boolean; // Showrelatedcompetencies.
|
||||||
|
cangrade: boolean; // Cangrade.
|
||||||
|
competency: AddonCompetencySummary;
|
||||||
|
user: CoreUserSummary;
|
||||||
|
usercompetency?: AddonCompetencyUserCompetency;
|
||||||
|
usercompetencyplan?: AddonCompetencyUserCompetencyPlan;
|
||||||
|
usercompetencycourse?: AddonCompetencyUserCompetencyCourse;
|
||||||
|
evidence: AddonCompetencyEvidence[]; // Evidence.
|
||||||
|
commentarea?: CoreCommentsArea;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's competency_summary_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencySummary = {
|
||||||
|
linkedcourses: CoreCourseSummary; // Linkedcourses.
|
||||||
|
relatedcompetencies: AddonCompetencyCompetency[]; // Relatedcompetencies.
|
||||||
|
competency: AddonCompetencyCompetency;
|
||||||
|
framework: AddonCompetencyFramework;
|
||||||
|
hascourses: boolean; // Hascourses.
|
||||||
|
hasrelatedcompetencies: boolean; // Hasrelatedcompetencies.
|
||||||
|
scaleid: number; // Scaleid.
|
||||||
|
scaleconfiguration: string; // Scaleconfiguration.
|
||||||
|
taxonomyterm: string; // Taxonomyterm.
|
||||||
|
comppath: AddonCompetencyPath;
|
||||||
|
pluginbaseurl: string; // Pluginbaseurl.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's competency_framework_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyFramework = {
|
||||||
|
shortname: string; // Shortname.
|
||||||
|
idnumber: string; // Idnumber.
|
||||||
|
description: string; // Description.
|
||||||
|
descriptionformat: number; // Description format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
visible: boolean; // Visible.
|
||||||
|
scaleid: number; // Scaleid.
|
||||||
|
scaleconfiguration: string; // Scaleconfiguration.
|
||||||
|
contextid: number; // Contextid.
|
||||||
|
taxonomies: string; // Taxonomies.
|
||||||
|
id: number; // Id.
|
||||||
|
timecreated: number; // Timecreated.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
usermodified: number; // Usermodified.
|
||||||
|
canmanage: boolean; // Canmanage.
|
||||||
|
competenciescount: number; // Competenciescount.
|
||||||
|
contextname: string; // Contextname.
|
||||||
|
contextnamenoprefix: string; // Contextnamenoprefix.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's user_competency_course_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyUserCompetencyCourse = {
|
||||||
|
userid: number; // Userid.
|
||||||
|
courseid: number; // Courseid.
|
||||||
|
competencyid: number; // Competencyid.
|
||||||
|
proficiency: boolean; // Proficiency.
|
||||||
|
grade: number; // Grade.
|
||||||
|
id: number; // Id.
|
||||||
|
timecreated: number; // Timecreated.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
usermodified: number; // Usermodified.
|
||||||
|
gradename: string; // Gradename.
|
||||||
|
proficiencyname: string; // Proficiencyname.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's evidence_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyEvidence = {
|
||||||
|
usercompetencyid: number; // Usercompetencyid.
|
||||||
|
contextid: number; // Contextid.
|
||||||
|
action: number; // Action.
|
||||||
|
actionuserid: number; // Actionuserid.
|
||||||
|
descidentifier: string; // Descidentifier.
|
||||||
|
desccomponent: string; // Desccomponent.
|
||||||
|
desca: string; // Desca.
|
||||||
|
url: string; // Url.
|
||||||
|
grade: number; // Grade.
|
||||||
|
note: string; // Note.
|
||||||
|
id: number; // Id.
|
||||||
|
timecreated: number; // Timecreated.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
usermodified: number; // Usermodified.
|
||||||
|
actionuser?: CoreUserSummary;
|
||||||
|
description: string; // Description.
|
||||||
|
gradename: string; // Gradename.
|
||||||
|
userdate: string; // Userdate.
|
||||||
|
candelete: boolean; // Candelete.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's user_competency_summary_in_course_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyUserCompetencySummaryInCourse = {
|
||||||
|
usercompetencysummary: AddonCompetencyUserCompetencySummary;
|
||||||
|
course: CoreCourseSummary;
|
||||||
|
coursemodules: CoreCourseModuleSummary[]; // Coursemodules.
|
||||||
|
plans: AddonCompetencyPlan[]; // Plans.
|
||||||
|
pluginbaseurl: string; // Pluginbaseurl.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's course_competency_settings_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyCourseCompetencySettings = {
|
||||||
|
courseid: number; // Courseid.
|
||||||
|
pushratingstouserplans: boolean; // Pushratingstouserplans.
|
||||||
|
id: number; // Id.
|
||||||
|
timecreated: number; // Timecreated.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
usermodified: number; // Usermodified.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's course_competency_statistics_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyCourseCompetencyStatistics = {
|
||||||
|
competencycount: number; // Competencycount.
|
||||||
|
proficientcompetencycount: number; // Proficientcompetencycount.
|
||||||
|
proficientcompetencypercentage: number; // Proficientcompetencypercentage.
|
||||||
|
proficientcompetencypercentageformatted: string; // Proficientcompetencypercentageformatted.
|
||||||
|
leastproficient: AddonCompetencyCompetency[]; // Leastproficient.
|
||||||
|
leastproficientcount: number; // Leastproficientcount.
|
||||||
|
canbegradedincourse: boolean; // Canbegradedincourse.
|
||||||
|
canmanagecoursecompetencies: boolean; // Canmanagecoursecompetencies.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by competency's course_competency_exporter.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyCourseCompetency = {
|
||||||
|
courseid: number; // Courseid.
|
||||||
|
competencyid: number; // Competencyid.
|
||||||
|
sortorder: number; // Sortorder.
|
||||||
|
ruleoutcome: number; // Ruleoutcome.
|
||||||
|
id: number; // Id.
|
||||||
|
timecreated: number; // Timecreated.
|
||||||
|
timemodified: number; // Timemodified.
|
||||||
|
usermodified: number; // Usermodified.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS tool_lp_data_for_plans_page.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyDataForPlansPageResult = {
|
||||||
|
userid: number; // The learning plan user id.
|
||||||
|
plans: AddonCompetencyPlan[];
|
||||||
|
pluginbaseurl: string; // Url to the tool_lp plugin folder on this Moodle site.
|
||||||
|
navigation: string[];
|
||||||
|
canreaduserevidence: boolean; // Can the current user view the user's evidence.
|
||||||
|
canmanageuserplans: boolean; // Can the current user manage the user's plans.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS tool_lp_data_for_plan_page.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyDataForPlanPageResult = {
|
||||||
|
plan: AddonCompetencyPlan;
|
||||||
|
contextid: number; // Context ID.
|
||||||
|
pluginbaseurl: string; // Plugin base URL.
|
||||||
|
competencies: AddonCompetencyDataForPlanPageCompetency[];
|
||||||
|
competencycount: number; // Count of competencies.
|
||||||
|
proficientcompetencycount: number; // Count of proficientcompetencies.
|
||||||
|
proficientcompetencypercentage: number; // Percentage of competencies proficient.
|
||||||
|
proficientcompetencypercentageformatted: string; // Displayable percentage.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Competency data returned by tool_lp_data_for_plan_page.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyDataForPlanPageCompetency = {
|
||||||
|
competency: AddonCompetencyCompetency;
|
||||||
|
comppath: AddonCompetencyPath;
|
||||||
|
usercompetency?: AddonCompetencyUserCompetency;
|
||||||
|
usercompetencyplan?: AddonCompetencyUserCompetencyPlan;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS tool_lp_data_for_course_competencies_page.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyDataForCourseCompetenciesPageResult = {
|
||||||
|
courseid: number; // The current course id.
|
||||||
|
pagecontextid: number; // The current page context ID.
|
||||||
|
gradableuserid?: number; // Current user id, if the user is a gradable user.
|
||||||
|
canmanagecompetencyframeworks: boolean; // User can manage competency frameworks.
|
||||||
|
canmanagecoursecompetencies: boolean; // User can manage linked course competencies.
|
||||||
|
canconfigurecoursecompetencies: boolean; // User can configure course competency settings.
|
||||||
|
cangradecompetencies: boolean; // User can grade competencies.
|
||||||
|
settings: AddonCompetencyCourseCompetencySettings;
|
||||||
|
statistics: AddonCompetencyCourseCompetencyStatistics;
|
||||||
|
competencies: AddonCompetencyDataForCourseCompetenciesPageCompetency[];
|
||||||
|
manageurl: string; // Url to the manage competencies page.
|
||||||
|
pluginbaseurl: string; // Url to the course competencies page.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Competency data returned by tool_lp_data_for_course_competencies_page.
|
||||||
|
*/
|
||||||
|
export type AddonCompetencyDataForCourseCompetenciesPageCompetency = {
|
||||||
|
competency: AddonCompetencyCompetency;
|
||||||
|
coursecompetency: AddonCompetencyCourseCompetency;
|
||||||
|
coursemodules: CoreCourseModuleSummary[];
|
||||||
|
usercompetencycourse?: AddonCompetencyUserCompetencyCourse;
|
||||||
|
ruleoutcomeoptions: {
|
||||||
|
value: number; // The option value.
|
||||||
|
text: string; // The name of the option.
|
||||||
|
selected: boolean; // If this is the currently selected option.
|
||||||
|
}[];
|
||||||
|
comppath: AddonCompetencyPath;
|
||||||
|
plans: AddonCompetencyPlan[];
|
||||||
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<ion-card *ngIf="completion && tracked">
|
<ion-card *ngIf="completion && tracked">
|
||||||
<ion-item text-wrap>
|
<ion-item text-wrap>
|
||||||
<h2>{{ 'addon.coursecompletion.status' | translate }}</h2>
|
<h2>{{ 'addon.coursecompletion.status' | translate }}</h2>
|
||||||
<p>{{ completion.statusText | translate }}</p>
|
<p>{{ statusText | translate }}</p>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item text-wrap>
|
<ion-item text-wrap>
|
||||||
<h2>{{ 'addon.coursecompletion.required' | translate }}</h2>
|
<h2>{{ 'addon.coursecompletion.required' | translate }}</h2>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { AddonCourseCompletionProvider } from '../../providers/coursecompletion';
|
import { AddonCourseCompletionProvider, AddonCourseCompletionCourseCompletionStatus } from '../../providers/coursecompletion';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that displays the course completion report.
|
* Component that displays the course completion report.
|
||||||
|
@ -29,9 +29,10 @@ export class AddonCourseCompletionReportComponent implements OnInit {
|
||||||
@Input() userId: number;
|
@Input() userId: number;
|
||||||
|
|
||||||
completionLoaded = false;
|
completionLoaded = false;
|
||||||
completion: any;
|
completion: AddonCourseCompletionCourseCompletionStatus;
|
||||||
showSelfComplete: boolean;
|
showSelfComplete: boolean;
|
||||||
tracked = true; // Whether completion is tracked.
|
tracked = true; // Whether completion is tracked.
|
||||||
|
statusText: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private sitesProvider: CoreSitesProvider,
|
private sitesProvider: CoreSitesProvider,
|
||||||
|
@ -59,7 +60,7 @@ export class AddonCourseCompletionReportComponent implements OnInit {
|
||||||
protected fetchCompletion(): Promise<any> {
|
protected fetchCompletion(): Promise<any> {
|
||||||
return this.courseCompletionProvider.getCompletion(this.courseId, this.userId).then((completion) => {
|
return this.courseCompletionProvider.getCompletion(this.courseId, this.userId).then((completion) => {
|
||||||
|
|
||||||
completion.statusText = this.courseCompletionProvider.getCompletedStatusText(completion);
|
this.statusText = this.courseCompletionProvider.getCompletedStatusText(completion);
|
||||||
|
|
||||||
this.completion = completion;
|
this.completion = completion;
|
||||||
this.showSelfComplete = this.courseCompletionProvider.canMarkSelfCompleted(this.userId, completion);
|
this.showSelfComplete = this.courseCompletionProvider.canMarkSelfCompleted(this.userId, completion);
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
|
import { CoreWSExternalWarning } from '@providers/ws';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle course completion.
|
* Service to handle course completion.
|
||||||
|
@ -43,7 +44,7 @@ export class AddonCourseCompletionProvider {
|
||||||
* @param completion Course completion.
|
* @param completion Course completion.
|
||||||
* @return True if user can mark course as self completed, false otherwise.
|
* @return True if user can mark course as self completed, false otherwise.
|
||||||
*/
|
*/
|
||||||
canMarkSelfCompleted(userId: number, completion: any): boolean {
|
canMarkSelfCompleted(userId: number, completion: AddonCourseCompletionCourseCompletionStatus): boolean {
|
||||||
let selfCompletionActive = false,
|
let selfCompletionActive = false,
|
||||||
alreadyMarked = false;
|
alreadyMarked = false;
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ export class AddonCourseCompletionProvider {
|
||||||
* @param completion Course completion.
|
* @param completion Course completion.
|
||||||
* @return Language code of the text to show.
|
* @return Language code of the text to show.
|
||||||
*/
|
*/
|
||||||
getCompletedStatusText(completion: any): string {
|
getCompletedStatusText(completion: AddonCourseCompletionCourseCompletionStatus): string {
|
||||||
if (completion.completed) {
|
if (completion.completed) {
|
||||||
return 'addon.coursecompletion.completed';
|
return 'addon.coursecompletion.completed';
|
||||||
} else {
|
} else {
|
||||||
|
@ -96,7 +97,9 @@ export class AddonCourseCompletionProvider {
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Promise to be resolved when the completion is retrieved.
|
* @return Promise to be resolved when the completion is retrieved.
|
||||||
*/
|
*/
|
||||||
getCompletion(courseId: number, userId?: number, preSets?: any, siteId?: string): Promise<any> {
|
getCompletion(courseId: number, userId?: number, preSets?: any, siteId?: string)
|
||||||
|
: Promise<AddonCourseCompletionCourseCompletionStatus> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
preSets = preSets || {};
|
preSets = preSets || {};
|
||||||
|
@ -112,7 +115,9 @@ export class AddonCourseCompletionProvider {
|
||||||
preSets.updateFrequency = preSets.updateFrequency || CoreSite.FREQUENCY_SOMETIMES;
|
preSets.updateFrequency = preSets.updateFrequency || CoreSite.FREQUENCY_SOMETIMES;
|
||||||
preSets.cacheErrors = ['notenroled'];
|
preSets.cacheErrors = ['notenroled'];
|
||||||
|
|
||||||
return site.read('core_completion_get_course_completion_status', data, preSets).then((data) => {
|
return site.read('core_completion_get_course_completion_status', data, preSets)
|
||||||
|
.then((data: AddonCourseCompletionGetCourseCompletionStatusResult): any => {
|
||||||
|
|
||||||
if (data.completionstatus) {
|
if (data.completionstatus) {
|
||||||
return data.completionstatus;
|
return data.completionstatus;
|
||||||
}
|
}
|
||||||
|
@ -243,17 +248,56 @@ export class AddonCourseCompletionProvider {
|
||||||
* Mark a course as self completed.
|
* Mark a course as self completed.
|
||||||
*
|
*
|
||||||
* @param courseId Course ID.
|
* @param courseId Course ID.
|
||||||
* @return Resolved on success.
|
* @return Promise resolved on success.
|
||||||
*/
|
*/
|
||||||
markCourseAsSelfCompleted(courseId: number): Promise<any> {
|
markCourseAsSelfCompleted(courseId: number): Promise<void> {
|
||||||
const params = {
|
const params = {
|
||||||
courseid: courseId
|
courseid: courseId
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.sitesProvider.getCurrentSite().write('core_completion_mark_course_self_completed', params).then((response) => {
|
return this.sitesProvider.getCurrentSite().write('core_completion_mark_course_self_completed', params)
|
||||||
|
.then((response: AddonCourseCompletionMarkCourseSelfCompletedResult) => {
|
||||||
|
|
||||||
if (!response.status) {
|
if (!response.status) {
|
||||||
return Promise.reject(null);
|
return Promise.reject(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completion status returned by core_completion_get_course_completion_status.
|
||||||
|
*/
|
||||||
|
export type AddonCourseCompletionCourseCompletionStatus = {
|
||||||
|
completed: boolean; // True if the course is complete, false otherwise.
|
||||||
|
aggregation: number; // Aggregation method 1 means all, 2 means any.
|
||||||
|
completions: {
|
||||||
|
type: number; // Completion criteria type.
|
||||||
|
title: string; // Completion criteria Title.
|
||||||
|
status: string; // Completion status (Yes/No) a % or number.
|
||||||
|
complete: boolean; // Completion status (true/false).
|
||||||
|
timecompleted: number; // Timestamp for criteria completetion.
|
||||||
|
details: {
|
||||||
|
type: string; // Type description.
|
||||||
|
criteria: string; // Criteria description.
|
||||||
|
requirement: string; // Requirement description.
|
||||||
|
status: string; // Status description, can be anything.
|
||||||
|
}; // Details.
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_completion_get_course_completion_status.
|
||||||
|
*/
|
||||||
|
export type AddonCourseCompletionGetCourseCompletionStatusResult = {
|
||||||
|
completionstatus: AddonCourseCompletionCourseCompletionStatus; // Course status.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_completion_mark_course_self_completed.
|
||||||
|
*/
|
||||||
|
export type AddonCourseCompletionMarkCourseSelfCompletedResult = {
|
||||||
|
status: boolean; // Status, true if success.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
import { AddonFilesProvider } from '../../providers/files';
|
import { AddonFilesProvider, AddonFilesFile, AddonFilesGetUserPrivateFilesInfoResult } from '../../providers/files';
|
||||||
import { AddonFilesHelperProvider } from '../../providers/helper';
|
import { AddonFilesHelperProvider } from '../../providers/helper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,10 +40,10 @@ export class AddonFilesListPage implements OnDestroy {
|
||||||
root: string; // The root of the files loaded: 'my' or 'site'.
|
root: string; // The root of the files loaded: 'my' or 'site'.
|
||||||
path: string; // The path of the directory being loaded. If empty path it means the root is being loaded.
|
path: string; // The path of the directory being loaded. If empty path it means the root is being loaded.
|
||||||
userQuota: number; // The user quota (in bytes).
|
userQuota: number; // The user quota (in bytes).
|
||||||
filesInfo: any; // Info about private files (size, number of files, etc.).
|
filesInfo: AddonFilesGetUserPrivateFilesInfoResult; // Info about private files (size, number of files, etc.).
|
||||||
spaceUsed: string; // Space used in a readable format.
|
spaceUsed: string; // Space used in a readable format.
|
||||||
userQuotaReadable: string; // User quota in a readable format.
|
userQuotaReadable: string; // User quota in a readable format.
|
||||||
files: any[]; // List of files.
|
files: AddonFilesFile[]; // List of files.
|
||||||
component: string; // Component to link the file downloads to.
|
component: string; // Component to link the file downloads to.
|
||||||
filesLoaded: boolean; // Whether the files are loaded.
|
filesLoaded: boolean; // Whether the files are loaded.
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ export class AddonFilesListPage implements OnDestroy {
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected fetchFiles(): Promise<any> {
|
protected fetchFiles(): Promise<any> {
|
||||||
let promise;
|
let promise: Promise<AddonFilesFile[]>;
|
||||||
|
|
||||||
if (!this.path) {
|
if (!this.path) {
|
||||||
// The path is unknown, the user must be requesting a root.
|
// The path is unknown, the user must be requesting a root.
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { Injectable } from '@angular/core';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
|
import { CoreMimetypeUtilsProvider } from '@providers/utils/mimetype';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
|
import { CoreWSExternalWarning } from '@providers/ws';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle my files and site files.
|
* Service to handle my files and site files.
|
||||||
|
@ -73,7 +74,7 @@ export class AddonFilesProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved with the files.
|
* @return Promise resolved with the files.
|
||||||
*/
|
*/
|
||||||
getFiles(params: any, siteId?: string): Promise<any[]> {
|
getFiles(params: any, siteId?: string): Promise<AddonFilesFile[]> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const preSets = {
|
const preSets = {
|
||||||
|
@ -82,15 +83,15 @@ export class AddonFilesProvider {
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_files_get_files', params, preSets);
|
return site.read('core_files_get_files', params, preSets);
|
||||||
}).then((result) => {
|
}).then((result: AddonFilesGetFilesResult) => {
|
||||||
const entries = [];
|
const entries: AddonFilesFile[] = [];
|
||||||
|
|
||||||
if (result.files) {
|
if (result.files) {
|
||||||
result.files.forEach((entry) => {
|
result.files.forEach((entry) => {
|
||||||
if (entry.isdir) {
|
if (entry.isdir) {
|
||||||
// Create a "link" to load the folder.
|
// Create a "link" to load the folder.
|
||||||
entry.link = {
|
entry.link = {
|
||||||
contextid: entry.contextid || '',
|
contextid: entry.contextid || null,
|
||||||
component: entry.component || '',
|
component: entry.component || '',
|
||||||
filearea: entry.filearea || '',
|
filearea: entry.filearea || '',
|
||||||
itemid: entry.itemid || 0,
|
itemid: entry.itemid || 0,
|
||||||
|
@ -135,7 +136,7 @@ export class AddonFilesProvider {
|
||||||
*
|
*
|
||||||
* @return Promise resolved with the files.
|
* @return Promise resolved with the files.
|
||||||
*/
|
*/
|
||||||
getPrivateFiles(): Promise<any[]> {
|
getPrivateFiles(): Promise<AddonFilesFile[]> {
|
||||||
return this.getFiles(this.getPrivateFilesRootParams());
|
return this.getFiles(this.getPrivateFilesRootParams());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +165,7 @@ export class AddonFilesProvider {
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Promise resolved with the info.
|
* @return Promise resolved with the info.
|
||||||
*/
|
*/
|
||||||
getPrivateFilesInfo(userId?: number, siteId?: string): Promise<any> {
|
getPrivateFilesInfo(userId?: number, siteId?: string): Promise<AddonFilesGetUserPrivateFilesInfoResult> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
|
||||||
|
@ -204,7 +205,7 @@ export class AddonFilesProvider {
|
||||||
*
|
*
|
||||||
* @return Promise resolved with the files.
|
* @return Promise resolved with the files.
|
||||||
*/
|
*/
|
||||||
getSiteFiles(): Promise<any[]> {
|
getSiteFiles(): Promise<AddonFilesFile[]> {
|
||||||
return this.getFiles(this.getSiteFilesRootParams());
|
return this.getFiles(this.getSiteFilesRootParams());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +389,7 @@ export class AddonFilesProvider {
|
||||||
* @param siteid ID of the site. If not defined, use current site.
|
* @param siteid ID of the site. If not defined, use current site.
|
||||||
* @return Promise resolved in success, rejected otherwise.
|
* @return Promise resolved in success, rejected otherwise.
|
||||||
*/
|
*/
|
||||||
moveFromDraftToPrivate(draftId: number, siteId?: string): Promise<any> {
|
moveFromDraftToPrivate(draftId: number, siteId?: string): Promise<null> {
|
||||||
const params = {
|
const params = {
|
||||||
draftid: draftId
|
draftid: draftId
|
||||||
},
|
},
|
||||||
|
@ -414,3 +415,63 @@ export class AddonFilesProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File data returned by core_files_get_files.
|
||||||
|
*/
|
||||||
|
export type AddonFilesFile = {
|
||||||
|
contextid: number;
|
||||||
|
component: string;
|
||||||
|
filearea: string;
|
||||||
|
itemid: number;
|
||||||
|
filepath: string;
|
||||||
|
filename: string;
|
||||||
|
isdir: boolean;
|
||||||
|
url: string;
|
||||||
|
timemodified: number;
|
||||||
|
timecreated?: number; // Time created.
|
||||||
|
filesize?: number; // File size.
|
||||||
|
author?: string; // File owner.
|
||||||
|
license?: string; // File license.
|
||||||
|
} & AddonFilesFileCalculatedData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_files_get_files.
|
||||||
|
*/
|
||||||
|
export type AddonFilesGetFilesResult = {
|
||||||
|
parents: {
|
||||||
|
contextid: number;
|
||||||
|
component: string;
|
||||||
|
filearea: string;
|
||||||
|
itemid: number;
|
||||||
|
filepath: string;
|
||||||
|
filename: string;
|
||||||
|
}[];
|
||||||
|
files: AddonFilesFile[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_user_get_private_files_info.
|
||||||
|
*/
|
||||||
|
export type AddonFilesGetUserPrivateFilesInfoResult = {
|
||||||
|
filecount: number; // Number of files in the area.
|
||||||
|
foldercount: number; // Number of folders in the area.
|
||||||
|
filesize: number; // Total size of the files in the area.
|
||||||
|
filesizewithoutreferences: number; // Total size of the area excluding file references.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated data for AddonFilesFile.
|
||||||
|
*/
|
||||||
|
export type AddonFilesFileCalculatedData = {
|
||||||
|
link?: { // Calculated in the app. A link to open the folder.
|
||||||
|
contextid?: number; // Folder's contextid.
|
||||||
|
component?: string; // Folder's component.
|
||||||
|
filearea?: string; // Folder's filearea.
|
||||||
|
itemid?: number; // Folder's itemid.
|
||||||
|
filepath?: string; // Folder's filepath.
|
||||||
|
filename?: string; // Folder's filename.
|
||||||
|
};
|
||||||
|
imgPath?: string; // Path to file icon's image.
|
||||||
|
};
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Component, OnDestroy } from '@angular/core';
|
||||||
import { IonicPage } from 'ionic-angular';
|
import { IonicPage } from 'ionic-angular';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
||||||
import { AddonMessageOutputAirnotifierProvider } from '../../providers/airnotifier';
|
import { AddonMessageOutputAirnotifierProvider, AddonMessageOutputAirnotifierDevice } from '../../providers/airnotifier';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays the list of devices.
|
* Page that displays the list of devices.
|
||||||
|
@ -28,7 +28,7 @@ import { AddonMessageOutputAirnotifierProvider } from '../../providers/airnotifi
|
||||||
})
|
})
|
||||||
export class AddonMessageOutputAirnotifierDevicesPage implements OnDestroy {
|
export class AddonMessageOutputAirnotifierDevicesPage implements OnDestroy {
|
||||||
|
|
||||||
devices = [];
|
devices: AddonMessageOutputAirnotifierDeviceFormatted[] = [];
|
||||||
devicesLoaded = false;
|
devicesLoaded = false;
|
||||||
|
|
||||||
protected updateTimeout: any;
|
protected updateTimeout: any;
|
||||||
|
@ -54,7 +54,7 @@ export class AddonMessageOutputAirnotifierDevicesPage implements OnDestroy {
|
||||||
const pushId = this.pushNotificationsProvider.getPushId();
|
const pushId = this.pushNotificationsProvider.getPushId();
|
||||||
|
|
||||||
// Convert enabled to boolean and search current device.
|
// Convert enabled to boolean and search current device.
|
||||||
devices.forEach((device) => {
|
devices.forEach((device: AddonMessageOutputAirnotifierDeviceFormatted) => {
|
||||||
device.enable = !!device.enable;
|
device.enable = !!device.enable;
|
||||||
device.current = pushId && pushId == device.pushid;
|
device.current = pushId && pushId == device.pushid;
|
||||||
});
|
});
|
||||||
|
@ -110,8 +110,9 @@ export class AddonMessageOutputAirnotifierDevicesPage implements OnDestroy {
|
||||||
* @param device The device object.
|
* @param device The device object.
|
||||||
* @param enable True to enable the device, false to disable it.
|
* @param enable True to enable the device, false to disable it.
|
||||||
*/
|
*/
|
||||||
enableDevice(device: any, enable: boolean): void {
|
enableDevice(device: AddonMessageOutputAirnotifierDeviceFormatted, enable: boolean): void {
|
||||||
device.updating = true;
|
device.updating = true;
|
||||||
|
|
||||||
this.airnotifierProivder.enableDevice(device.id, enable).then(() => {
|
this.airnotifierProivder.enableDevice(device.id, enable).then(() => {
|
||||||
// Update the list of devices since it was modified.
|
// Update the list of devices since it was modified.
|
||||||
this.updateDevicesAfterDelay();
|
this.updateDevicesAfterDelay();
|
||||||
|
@ -135,3 +136,11 @@ export class AddonMessageOutputAirnotifierDevicesPage implements OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User device with some calculated data.
|
||||||
|
*/
|
||||||
|
type AddonMessageOutputAirnotifierDeviceFormatted = AddonMessageOutputAirnotifierDevice & {
|
||||||
|
current?: boolean; // Calculated in the app. Whether it's the current device.
|
||||||
|
updating?: boolean; // Calculated in the app. Whether the device enable is being updated right now.
|
||||||
|
};
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreConfigConstants } from '../../../../configconstants';
|
import { CoreConfigConstants } from '../../../../configconstants';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
|
import { CoreWSExternalWarning } from '@providers/ws';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle Airnotifier message output.
|
* Service to handle Airnotifier message output.
|
||||||
|
@ -39,14 +40,16 @@ export class AddonMessageOutputAirnotifierProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved if success.
|
* @return Promise resolved if success.
|
||||||
*/
|
*/
|
||||||
enableDevice(deviceId: number, enable: boolean, siteId?: string): Promise<any> {
|
enableDevice(deviceId: number, enable: boolean, siteId?: string): Promise<void> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const data = {
|
const data = {
|
||||||
deviceid: deviceId,
|
deviceid: deviceId,
|
||||||
enable: enable ? 1 : 0
|
enable: enable ? 1 : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.write('message_airnotifier_enable_device', data).then((result) => {
|
return site.write('message_airnotifier_enable_device', data)
|
||||||
|
.then((result: AddonMessageOutputAirnotifierEnableDeviceResult) => {
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
// Fail. Reject with warning message if any.
|
// Fail. Reject with warning message if any.
|
||||||
if (result.warnings && result.warnings.length) {
|
if (result.warnings && result.warnings.length) {
|
||||||
|
@ -74,7 +77,7 @@ export class AddonMessageOutputAirnotifierProvider {
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Promise resolved with the devices.
|
* @return Promise resolved with the devices.
|
||||||
*/
|
*/
|
||||||
getUserDevices(siteId?: string): Promise<any> {
|
getUserDevices(siteId?: string): Promise<AddonMessageOutputAirnotifierDevice[]> {
|
||||||
this.logger.debug('Get user devices');
|
this.logger.debug('Get user devices');
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
@ -86,7 +89,8 @@ export class AddonMessageOutputAirnotifierProvider {
|
||||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('message_airnotifier_get_user_devices', data, preSets).then((data) => {
|
return site.read('message_airnotifier_get_user_devices', data, preSets)
|
||||||
|
.then((data: AddonMessageOutputAirnotifierGetUserDevicesResult) => {
|
||||||
return data.devices;
|
return data.devices;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -115,3 +119,36 @@ export class AddonMessageOutputAirnotifierProvider {
|
||||||
this.sitesProvider.wsAvailableInCurrentSite('message_airnotifier_get_user_devices');
|
this.sitesProvider.wsAvailableInCurrentSite('message_airnotifier_get_user_devices');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Device data returned by WS message_airnotifier_get_user_devices.
|
||||||
|
*/
|
||||||
|
export type AddonMessageOutputAirnotifierDevice = {
|
||||||
|
id: number; // Device id (in the message_airnotifier table).
|
||||||
|
appid: string; // The app id, something like com.moodle.moodlemobile.
|
||||||
|
name: string; // The device name, 'occam' or 'iPhone' etc.
|
||||||
|
model: string; // The device model 'Nexus4' or 'iPad1,1' etc.
|
||||||
|
platform: string; // The device platform 'iOS' or 'Android' etc.
|
||||||
|
version: string; // The device version '6.1.2' or '4.2.2' etc.
|
||||||
|
pushid: string; // The device PUSH token/key/identifier/registration id.
|
||||||
|
uuid: string; // The device UUID.
|
||||||
|
enable: number | boolean; // Whether the device is enabled or not.
|
||||||
|
timecreated: number; // Time created.
|
||||||
|
timemodified: number; // Time modified.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS message_airnotifier_enable_device.
|
||||||
|
*/
|
||||||
|
export type AddonMessageOutputAirnotifierEnableDeviceResult = {
|
||||||
|
success: boolean; // True if success.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS message_airnotifier_get_user_devices.
|
||||||
|
*/
|
||||||
|
export type AddonMessageOutputAirnotifierGetUserDevicesResult = {
|
||||||
|
devices: AddonMessageOutputAirnotifierDevice[]; // List of devices.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@
|
||||||
import { Content } from 'ionic-angular';
|
import { Content } from 'ionic-angular';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { AddonMessagesProvider } from '../../providers/messages';
|
import { AddonMessagesProvider, AddonMessagesConversationMember } from '../../providers/messages';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,7 +33,7 @@ export class AddonMessagesConfirmedContactsComponent implements OnInit, OnDestro
|
||||||
loaded = false;
|
loaded = false;
|
||||||
canLoadMore = false;
|
canLoadMore = false;
|
||||||
loadMoreError = false;
|
loadMoreError = false;
|
||||||
contacts = [];
|
contacts: AddonMessagesConversationMember[] = [];
|
||||||
selectedUserId: number;
|
selectedUserId: number;
|
||||||
|
|
||||||
protected memberInfoObserver;
|
protected memberInfoObserver;
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@
|
||||||
import { Content } from 'ionic-angular';
|
import { Content } from 'ionic-angular';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { AddonMessagesProvider } from '../../providers/messages';
|
import { AddonMessagesProvider, AddonMessagesConversationMember } from '../../providers/messages';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,7 +33,7 @@ export class AddonMessagesContactRequestsComponent implements OnInit, OnDestroy
|
||||||
loaded = false;
|
loaded = false;
|
||||||
canLoadMore = false;
|
canLoadMore = false;
|
||||||
loadMoreError = false;
|
loadMoreError = false;
|
||||||
requests = [];
|
requests: AddonMessagesConversationMember[] = [];
|
||||||
selectedUserId: number;
|
selectedUserId: number;
|
||||||
|
|
||||||
protected memberInfoObserver;
|
protected memberInfoObserver;
|
||||||
|
|
|
@ -16,7 +16,9 @@ import { Component } from '@angular/core';
|
||||||
import { NavParams } from 'ionic-angular';
|
import { NavParams } from 'ionic-angular';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { AddonMessagesProvider } from '../../providers/messages';
|
import {
|
||||||
|
AddonMessagesProvider, AddonMessagesGetContactsResult, AddonMessagesSearchContactsContact
|
||||||
|
} from '../../providers/messages';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
|
@ -42,7 +44,10 @@ export class AddonMessagesContactsComponent {
|
||||||
searchType = 'search';
|
searchType = 'search';
|
||||||
loadingMessage = '';
|
loadingMessage = '';
|
||||||
hasContacts = false;
|
hasContacts = false;
|
||||||
contacts = {
|
contacts: AddonMessagesGetContactsFormatted = {
|
||||||
|
online: [],
|
||||||
|
offline: [],
|
||||||
|
strangers: [],
|
||||||
search: []
|
search: []
|
||||||
};
|
};
|
||||||
searchString = '';
|
searchString = '';
|
||||||
|
@ -205,7 +210,7 @@ export class AddonMessagesContactsComponent {
|
||||||
this.searchString = query;
|
this.searchString = query;
|
||||||
this.contactTypes = ['search'];
|
this.contactTypes = ['search'];
|
||||||
|
|
||||||
this.contacts['search'] = this.sortUsers(result);
|
this.contacts.search = this.sortUsers(result);
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingcontacts', true);
|
this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingcontacts', true);
|
||||||
});
|
});
|
||||||
|
@ -234,3 +239,10 @@ export class AddonMessagesContactsComponent {
|
||||||
this.memberInfoObserver && this.memberInfoObserver.off();
|
this.memberInfoObserver && this.memberInfoObserver.off();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contacts with some calculated data.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetContactsFormatted = AddonMessagesGetContactsResult & {
|
||||||
|
search?: AddonMessagesSearchContactsContact[]; // Calculated in the app. Result of searching users.
|
||||||
|
};
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
|
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { IonicPage, NavParams, ViewController } from 'ionic-angular';
|
import { IonicPage, NavParams, ViewController } from 'ionic-angular';
|
||||||
import { AddonMessagesProvider } from '../../providers/messages';
|
import {
|
||||||
|
AddonMessagesProvider, AddonMessagesConversationFormatted, AddonMessagesConversationMember
|
||||||
|
} from '../../providers/messages';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,8 +30,8 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
export class AddonMessagesConversationInfoPage implements OnInit {
|
export class AddonMessagesConversationInfoPage implements OnInit {
|
||||||
|
|
||||||
loaded = false;
|
loaded = false;
|
||||||
conversation: any;
|
conversation: AddonMessagesConversationFormatted;
|
||||||
members = [];
|
members: AddonMessagesConversationMember[] = [];
|
||||||
canLoadMore = false;
|
canLoadMore = false;
|
||||||
loadMoreError = false;
|
loadMoreError = false;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,10 @@ import { IonicPage, NavParams, NavController, Content, ModalController } from 'i
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { AddonMessagesProvider } from '../../providers/messages';
|
import {
|
||||||
|
AddonMessagesProvider, AddonMessagesConversationFormatted, AddonMessagesConversationMember, AddonMessagesConversationMessage,
|
||||||
|
AddonMessagesGetMessagesMessage
|
||||||
|
} from '../../providers/messages';
|
||||||
import { AddonMessagesOfflineProvider } from '../../providers/messages-offline';
|
import { AddonMessagesOfflineProvider } from '../../providers/messages-offline';
|
||||||
import { AddonMessagesSyncProvider } from '../../providers/sync';
|
import { AddonMessagesSyncProvider } from '../../providers/sync';
|
||||||
import { CoreUserProvider } from '@core/user/providers/user';
|
import { CoreUserProvider } from '@core/user/providers/user';
|
||||||
|
@ -54,7 +57,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
protected messagesBeingSent = 0;
|
protected messagesBeingSent = 0;
|
||||||
protected pagesLoaded = 1;
|
protected pagesLoaded = 1;
|
||||||
protected lastMessage = {text: '', timecreated: 0};
|
protected lastMessage = {text: '', timecreated: 0};
|
||||||
protected keepMessageMap = {};
|
protected keepMessageMap: {[hash: string]: boolean} = {};
|
||||||
protected syncObserver: any;
|
protected syncObserver: any;
|
||||||
protected oldContentHeight = 0;
|
protected oldContentHeight = 0;
|
||||||
protected keyboardObserver: any;
|
protected keyboardObserver: any;
|
||||||
|
@ -64,7 +67,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
protected showLoadingModal = false; // Whether to show a loading modal while fetching data.
|
protected showLoadingModal = false; // Whether to show a loading modal while fetching data.
|
||||||
|
|
||||||
conversationId: number; // Conversation ID. Undefined if it's a new individual conversation.
|
conversationId: number; // Conversation ID. Undefined if it's a new individual conversation.
|
||||||
conversation: any; // The conversation object (if it exists).
|
conversation: AddonMessagesConversationFormatted; // The conversation object (if it exists).
|
||||||
userId: number; // User ID you're talking to (only if group messaging not enabled or it's a new individual conversation).
|
userId: number; // User ID you're talking to (only if group messaging not enabled or it's a new individual conversation).
|
||||||
currentUserId: number;
|
currentUserId: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -74,18 +77,18 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
showKeyboard = false;
|
showKeyboard = false;
|
||||||
canLoadMore = false;
|
canLoadMore = false;
|
||||||
loadMoreError = false;
|
loadMoreError = false;
|
||||||
messages = [];
|
messages: (AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted)[] = [];
|
||||||
showDelete = false;
|
showDelete = false;
|
||||||
canDelete = false;
|
canDelete = false;
|
||||||
groupMessagingEnabled: boolean;
|
groupMessagingEnabled: boolean;
|
||||||
isGroup = false;
|
isGroup = false;
|
||||||
members: any = {}; // Members that wrote a message, indexed by ID.
|
members: {[id: number]: AddonMessagesConversationMember} = {}; // Members that wrote a message, indexed by ID.
|
||||||
favouriteIcon = 'fa-star';
|
favouriteIcon = 'fa-star';
|
||||||
favouriteIconSlash = false;
|
favouriteIconSlash = false;
|
||||||
deleteIcon = 'trash';
|
deleteIcon = 'trash';
|
||||||
blockIcon = 'close-circle';
|
blockIcon = 'close-circle';
|
||||||
addRemoveIcon = 'person';
|
addRemoveIcon = 'person';
|
||||||
otherMember: any; // Other member information (individual conversations only).
|
otherMember: AddonMessagesConversationMember; // Other member information (individual conversations only).
|
||||||
footerType: 'message' | 'blocked' | 'requiresContact' | 'requestSent' | 'requestReceived' | 'unable';
|
footerType: 'message' | 'blocked' | 'requiresContact' | 'requestSent' | 'requestReceived' | 'unable';
|
||||||
requestContactSent = false;
|
requestContactSent = false;
|
||||||
requestContactReceived = false;
|
requestContactReceived = false;
|
||||||
|
@ -139,7 +142,9 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
* @param message Message to be added.
|
* @param message Message to be added.
|
||||||
* @param keep If set the keep flag or not.
|
* @param keep If set the keep flag or not.
|
||||||
*/
|
*/
|
||||||
protected addMessage(message: any, keep: boolean = true): void {
|
protected addMessage(message: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted,
|
||||||
|
keep: boolean = true): void {
|
||||||
|
|
||||||
/* Create a hash to identify the message. The text of online messages isn't reliable because it can have random data
|
/* Create a hash to identify the message. The text of online messages isn't reliable because it can have random data
|
||||||
like VideoJS ID. Try to use id and fallback to text for offline messages. */
|
like VideoJS ID. Try to use id and fallback to text for offline messages. */
|
||||||
message.hash = Md5.hashAsciiStr(String(message.id || message.text || '')) + '#' + message.timecreated + '#' +
|
message.hash = Md5.hashAsciiStr(String(message.id || message.text || '')) + '#' + message.timecreated + '#' +
|
||||||
|
@ -158,7 +163,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
*
|
*
|
||||||
* @param hash Hash of the message to be removed.
|
* @param hash Hash of the message to be removed.
|
||||||
*/
|
*/
|
||||||
protected removeMessage(hash: any): void {
|
protected removeMessage(hash: string): void {
|
||||||
if (this.keepMessageMap[hash]) {
|
if (this.keepMessageMap[hash]) {
|
||||||
// Selected to keep it, clear the flag.
|
// Selected to keep it, clear the flag.
|
||||||
this.keepMessageMap[hash] = false;
|
this.keepMessageMap[hash] = false;
|
||||||
|
@ -261,10 +266,11 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
if (!this.title && this.messages.length) {
|
if (!this.title && this.messages.length) {
|
||||||
// Didn't receive the fullname via argument. Try to get it from messages.
|
// Didn't receive the fullname via argument. Try to get it from messages.
|
||||||
// It's possible that name cannot be resolved when no messages were yet exchanged.
|
// It's possible that name cannot be resolved when no messages were yet exchanged.
|
||||||
if (this.messages[0].useridto != this.currentUserId) {
|
const firstMessage = <AddonMessagesGetMessagesMessageFormatted> this.messages[0];
|
||||||
this.title = this.messages[0].usertofullname || '';
|
if (firstMessage.useridto != this.currentUserId) {
|
||||||
|
this.title = firstMessage.usertofullname || '';
|
||||||
} else {
|
} else {
|
||||||
this.title = this.messages[0].userfromfullname || '';
|
this.title = firstMessage.userfromfullname || '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -302,7 +308,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
*
|
*
|
||||||
* @return Resolved when done.
|
* @return Resolved when done.
|
||||||
*/
|
*/
|
||||||
protected fetchMessages(): Promise<any> {
|
protected fetchMessages(): Promise<void> {
|
||||||
this.loadMoreError = false;
|
this.loadMoreError = false;
|
||||||
|
|
||||||
if (this.messagesBeingSent > 0) {
|
if (this.messagesBeingSent > 0) {
|
||||||
|
@ -341,7 +347,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
return this.getDiscussionMessages(this.pagesLoaded);
|
return this.getDiscussionMessages(this.pagesLoaded);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).then((messages) => {
|
}).then((messages: (AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted)[]) => {
|
||||||
this.loadMessages(messages);
|
this.loadMessages(messages);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.fetching = false;
|
this.fetching = false;
|
||||||
|
@ -353,7 +359,9 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
*
|
*
|
||||||
* @param messages Messages to load.
|
* @param messages Messages to load.
|
||||||
*/
|
*/
|
||||||
protected loadMessages(messages: any[]): void {
|
protected loadMessages(messages: (AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted)[])
|
||||||
|
: void {
|
||||||
|
|
||||||
if (this.viewDestroyed) {
|
if (this.viewDestroyed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -382,7 +390,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
this.messagesProvider.sortMessages(this.messages);
|
this.messagesProvider.sortMessages(this.messages);
|
||||||
|
|
||||||
// Calculate which messages need to display the date or user data.
|
// Calculate which messages need to display the date or user data.
|
||||||
this.messages.forEach((message, index): any => {
|
this.messages.forEach((message, index) => {
|
||||||
message.showDate = this.showDate(message, this.messages[index - 1]);
|
message.showDate = this.showDate(message, this.messages[index - 1]);
|
||||||
message.showUserData = this.showUserData(message, this.messages[index - 1]);
|
message.showUserData = this.showUserData(message, this.messages[index - 1]);
|
||||||
message.showTail = this.showTail(message, this.messages[index + 1]);
|
message.showTail = this.showTail(message, this.messages[index + 1]);
|
||||||
|
@ -411,20 +419,22 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
* @return Promise resolved with a boolean: whether the conversation exists or not.
|
* @return Promise resolved with a boolean: whether the conversation exists or not.
|
||||||
*/
|
*/
|
||||||
protected getConversation(conversationId: number, userId: number): Promise<boolean> {
|
protected getConversation(conversationId: number, userId: number): Promise<boolean> {
|
||||||
let promise,
|
let promise: Promise<number>,
|
||||||
fallbackConversation;
|
fallbackConversation: AddonMessagesConversationFormatted;
|
||||||
|
|
||||||
// Try to get the conversationId if we don't have it.
|
// Try to get the conversationId if we don't have it.
|
||||||
if (conversationId) {
|
if (conversationId) {
|
||||||
promise = Promise.resolve(conversationId);
|
promise = Promise.resolve(conversationId);
|
||||||
} else {
|
} else {
|
||||||
|
let subPromise: Promise<AddonMessagesConversationFormatted>;
|
||||||
|
|
||||||
if (userId == this.currentUserId && this.messagesProvider.isSelfConversationEnabled()) {
|
if (userId == this.currentUserId && this.messagesProvider.isSelfConversationEnabled()) {
|
||||||
promise = this.messagesProvider.getSelfConversation();
|
subPromise = this.messagesProvider.getSelfConversation();
|
||||||
} else {
|
} else {
|
||||||
promise = this.messagesProvider.getConversationBetweenUsers(userId, undefined, true);
|
subPromise = this.messagesProvider.getConversationBetweenUsers(userId, undefined, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
promise = promise.then((conversation) => {
|
promise = subPromise.then((conversation) => {
|
||||||
fallbackConversation = conversation;
|
fallbackConversation = conversation;
|
||||||
|
|
||||||
return conversation.id;
|
return conversation.id;
|
||||||
|
@ -437,14 +447,14 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
return this.messagesProvider.getConversation(conversationId, undefined, true);
|
return this.messagesProvider.getConversation(conversationId, undefined, true);
|
||||||
}).catch((error) => {
|
}).catch((error): any => {
|
||||||
// Get conversation failed, use the fallback one if we have it.
|
// Get conversation failed, use the fallback one if we have it.
|
||||||
if (fallbackConversation) {
|
if (fallbackConversation) {
|
||||||
return fallbackConversation;
|
return fallbackConversation;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}).then((conversation) => {
|
}).then((conversation: AddonMessagesConversationFormatted) => {
|
||||||
this.conversation = conversation;
|
this.conversation = conversation;
|
||||||
|
|
||||||
if (conversation) {
|
if (conversation) {
|
||||||
|
@ -495,7 +505,9 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
* @param offset Offset for message list.
|
* @param offset Offset for message list.
|
||||||
* @return Promise resolved with the list of messages.
|
* @return Promise resolved with the list of messages.
|
||||||
*/
|
*/
|
||||||
protected getConversationMessages(pagesToLoad: number, offset: number = 0): Promise<any[]> {
|
protected getConversationMessages(pagesToLoad: number, offset: number = 0)
|
||||||
|
: Promise<AddonMessagesConversationMessageFormatted[]> {
|
||||||
|
|
||||||
const excludePending = offset > 0;
|
const excludePending = offset > 0;
|
||||||
|
|
||||||
return this.messagesProvider.getConversationMessages(this.conversationId, excludePending, offset).then((result) => {
|
return this.messagesProvider.getConversationMessages(this.conversationId, excludePending, offset).then((result) => {
|
||||||
|
@ -535,7 +547,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
* @return Resolved when done.
|
* @return Resolved when done.
|
||||||
*/
|
*/
|
||||||
protected getDiscussionMessages(pagesToLoad: number, lfReceivedUnread: number = 0, lfReceivedRead: number = 0,
|
protected getDiscussionMessages(pagesToLoad: number, lfReceivedUnread: number = 0, lfReceivedRead: number = 0,
|
||||||
lfSentUnread: number = 0, lfSentRead: number = 0): Promise<any> {
|
lfSentUnread: number = 0, lfSentRead: number = 0): Promise<AddonMessagesGetMessagesMessageFormatted[]> {
|
||||||
|
|
||||||
// Only get offline messages if we're loading the first "page".
|
// Only get offline messages if we're loading the first "page".
|
||||||
const excludePending = lfReceivedUnread > 0 || lfReceivedRead > 0 || lfSentUnread > 0 || lfSentRead > 0;
|
const excludePending = lfReceivedUnread > 0 || lfReceivedRead > 0 || lfSentUnread > 0 || lfSentRead > 0;
|
||||||
|
@ -547,7 +559,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
pagesToLoad--;
|
pagesToLoad--;
|
||||||
if (pagesToLoad > 0 && result.canLoadMore) {
|
if (pagesToLoad > 0 && result.canLoadMore) {
|
||||||
// More pages to load. Calculate new limit froms.
|
// More pages to load. Calculate new limit froms.
|
||||||
result.messages.forEach((message) => {
|
result.messages.forEach((message: AddonMessagesGetMessagesMessageFormatted) => {
|
||||||
if (!message.pending) {
|
if (!message.pending) {
|
||||||
if (message.useridfrom == this.userId) {
|
if (message.useridfrom == this.userId) {
|
||||||
if (message.read) {
|
if (message.read) {
|
||||||
|
@ -598,7 +610,8 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
for (const x in this.messages) {
|
for (const x in this.messages) {
|
||||||
const message = this.messages[x];
|
const message = this.messages[x];
|
||||||
// If an unread message is found, mark all messages as read.
|
// If an unread message is found, mark all messages as read.
|
||||||
if (message.useridfrom != this.currentUserId && message.read == 0) {
|
if (message.useridfrom != this.currentUserId &&
|
||||||
|
(<AddonMessagesGetMessagesMessageFormatted> message).read == 0) {
|
||||||
messageUnreadFound = true;
|
messageUnreadFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -616,7 +629,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
promise = this.messagesProvider.markAllMessagesRead(this.userId).then(() => {
|
promise = this.messagesProvider.markAllMessagesRead(this.userId).then(() => {
|
||||||
// Mark all messages as read.
|
// Mark all messages as read.
|
||||||
this.messages.forEach((message) => {
|
this.messages.forEach((message) => {
|
||||||
message.read = 1;
|
(<AddonMessagesGetMessagesMessageFormatted> message).read = 1;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -630,10 +643,10 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
// Mark each message as read one by one.
|
// Mark each message as read one by one.
|
||||||
this.messages.forEach((message) => {
|
this.messages.forEach((message) => {
|
||||||
// If the message is unread, call this.messagesProvider.markMessageRead.
|
// If the message is unread, call this.messagesProvider.markMessageRead.
|
||||||
if (message.useridfrom != this.currentUserId && message.read == 0) {
|
if (message.useridfrom != this.currentUserId && (<AddonMessagesGetMessagesMessageFormatted> message).read == 0) {
|
||||||
promises.push(this.messagesProvider.markMessageRead(message.id).then(() => {
|
promises.push(this.messagesProvider.markMessageRead(message.id).then(() => {
|
||||||
readChanged = true;
|
readChanged = true;
|
||||||
message.read = 1;
|
(<AddonMessagesGetMessagesMessageFormatted> message).read = 1;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -703,7 +716,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
if (!message.pending && message.useridfrom != this.currentUserId) {
|
if (!message.pending && message.useridfrom != this.currentUserId) {
|
||||||
found++;
|
found++;
|
||||||
if (found == this.conversation.unreadcount) {
|
if (found == this.conversation.unreadcount) {
|
||||||
this.unreadMessageFrom = parseInt(message.id, 10);
|
this.unreadMessageFrom = Number(message.id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -713,13 +726,13 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
let previousMessageRead = false;
|
let previousMessageRead = false;
|
||||||
|
|
||||||
for (const x in this.messages) {
|
for (const x in this.messages) {
|
||||||
const message = this.messages[x];
|
const message = <AddonMessagesGetMessagesMessageFormatted> this.messages[x];
|
||||||
if (message.useridfrom != this.currentUserId) {
|
if (message.useridfrom != this.currentUserId) {
|
||||||
const unreadFrom = message.read == 0 && previousMessageRead;
|
const unreadFrom = message.read == 0 && previousMessageRead;
|
||||||
|
|
||||||
if (unreadFrom) {
|
if (unreadFrom) {
|
||||||
// Save where the label is placed.
|
// Save where the label is placed.
|
||||||
this.unreadMessageFrom = parseInt(message.id, 10);
|
this.unreadMessageFrom = Number(message.id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,8 +821,9 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
*
|
*
|
||||||
* @param message Message to be copied.
|
* @param message Message to be copied.
|
||||||
*/
|
*/
|
||||||
copyMessage(message: any): void {
|
copyMessage(message: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted): void {
|
||||||
const text = this.textUtils.decodeHTMLEntities(message.smallmessage || message.text || '');
|
const text = this.textUtils.decodeHTMLEntities(
|
||||||
|
(<AddonMessagesGetMessagesMessageFormatted> message).smallmessage || message.text || '');
|
||||||
this.utils.copyToClipboard(text);
|
this.utils.copyToClipboard(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -819,7 +833,9 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
* @param message Message object to delete.
|
* @param message Message object to delete.
|
||||||
* @param index Index where the message is to delete it from the view.
|
* @param index Index where the message is to delete it from the view.
|
||||||
*/
|
*/
|
||||||
deleteMessage(message: any, index: number): void {
|
deleteMessage(message: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted, index: number)
|
||||||
|
: void {
|
||||||
|
|
||||||
const canDeleteAll = this.conversation && this.conversation.candeletemessagesforallusers,
|
const canDeleteAll = this.conversation && this.conversation.candeletemessagesforallusers,
|
||||||
langKey = message.pending || canDeleteAll || this.isSelf ? 'core.areyousure' :
|
langKey = message.pending || canDeleteAll || this.isSelf ? 'core.areyousure' :
|
||||||
'addon.messages.deletemessageconfirmation',
|
'addon.messages.deletemessageconfirmation',
|
||||||
|
@ -860,7 +876,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
|
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
|
||||||
* @return Resolved when done.
|
* @return Resolved when done.
|
||||||
*/
|
*/
|
||||||
loadPrevious(infiniteComplete?: any): Promise<any> {
|
loadPrevious(infiniteComplete?: any): Promise<void> {
|
||||||
let infiniteHeight = this.infinite ? this.infinite.getHeight() : 0;
|
let infiniteHeight = this.infinite ? this.infinite.getHeight() : 0;
|
||||||
const scrollHeight = this.domUtils.getScrollHeight(this.content);
|
const scrollHeight = this.domUtils.getScrollHeight(this.content);
|
||||||
|
|
||||||
|
@ -962,7 +978,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
* @param text Message text.
|
* @param text Message text.
|
||||||
*/
|
*/
|
||||||
sendMessage(text: string): void {
|
sendMessage(text: string): void {
|
||||||
let message;
|
let message: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted;
|
||||||
|
|
||||||
this.hideUnreadLabel();
|
this.hideUnreadLabel();
|
||||||
|
|
||||||
|
@ -970,6 +986,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
this.scrollBottom = true;
|
this.scrollBottom = true;
|
||||||
|
|
||||||
message = {
|
message = {
|
||||||
|
id: null,
|
||||||
pending: true,
|
pending: true,
|
||||||
sending: true,
|
sending: true,
|
||||||
useridfrom: this.currentUserId,
|
useridfrom: this.currentUserId,
|
||||||
|
@ -985,7 +1002,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
// If there is an ongoing fetch, wait for it to finish.
|
// If there is an ongoing fetch, wait for it to finish.
|
||||||
// Otherwise, if a message is sent while fetching it could disappear until the next fetch.
|
// Otherwise, if a message is sent while fetching it could disappear until the next fetch.
|
||||||
this.waitForFetch().finally(() => {
|
this.waitForFetch().finally(() => {
|
||||||
let promise;
|
let promise: Promise<{sent: boolean, message: any}>;
|
||||||
|
|
||||||
if (this.conversationId) {
|
if (this.conversationId) {
|
||||||
promise = this.messagesProvider.sendMessageToConversation(this.conversation, text);
|
promise = this.messagesProvider.sendMessageToConversation(this.conversation, text);
|
||||||
|
@ -1050,7 +1067,9 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
* @param prevMessage Previous message where to compare the date with.
|
* @param prevMessage Previous message where to compare the date with.
|
||||||
* @return If date has changed and should be shown.
|
* @return If date has changed and should be shown.
|
||||||
*/
|
*/
|
||||||
showDate(message: any, prevMessage?: any): boolean {
|
showDate(message: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted,
|
||||||
|
prevMessage?: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted): boolean {
|
||||||
|
|
||||||
if (!prevMessage) {
|
if (!prevMessage) {
|
||||||
// First message, show it.
|
// First message, show it.
|
||||||
return true;
|
return true;
|
||||||
|
@ -1068,7 +1087,9 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
* @param prevMessage Previous message.
|
* @param prevMessage Previous message.
|
||||||
* @return Whether user data should be shown.
|
* @return Whether user data should be shown.
|
||||||
*/
|
*/
|
||||||
showUserData(message: any, prevMessage?: any): boolean {
|
showUserData(message: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted,
|
||||||
|
prevMessage?: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted): boolean {
|
||||||
|
|
||||||
return this.isGroup && message.useridfrom != this.currentUserId && this.members[message.useridfrom] &&
|
return this.isGroup && message.useridfrom != this.currentUserId && this.members[message.useridfrom] &&
|
||||||
(!prevMessage || prevMessage.useridfrom != message.useridfrom || message.showDate);
|
(!prevMessage || prevMessage.useridfrom != message.useridfrom || message.showDate);
|
||||||
}
|
}
|
||||||
|
@ -1080,7 +1101,8 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
* @param nextMessage Next message.
|
* @param nextMessage Next message.
|
||||||
* @return Whether user data should be shown.
|
* @return Whether user data should be shown.
|
||||||
*/
|
*/
|
||||||
showTail(message: any, nextMessage?: any): boolean {
|
showTail(message: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted,
|
||||||
|
nextMessage?: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted): boolean {
|
||||||
return !nextMessage || nextMessage.useridfrom != message.useridfrom || nextMessage.showDate;
|
return !nextMessage || nextMessage.useridfrom != message.useridfrom || nextMessage.showDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1422,3 +1444,26 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
||||||
this.viewDestroyed = true;
|
this.viewDestroyed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversation message with some calculated data.
|
||||||
|
*/
|
||||||
|
type AddonMessagesConversationMessageFormatted = AddonMessagesConversationMessage & {
|
||||||
|
pending?: boolean; // Calculated in the app. Whether the message is pending to be sent.
|
||||||
|
sending?: boolean; // Calculated in the app. Whether the message is being sent right now.
|
||||||
|
hash?: string; // Calculated in the app. A hash to identify the message.
|
||||||
|
showDate?: boolean; // Calculated in the app. Whether to show the date before the message.
|
||||||
|
showUserData?: boolean; // Calculated in the app. Whether to show the user data in the message.
|
||||||
|
showTail?: boolean; // Calculated in the app. Whether to show a "tail" in the message.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message with some calculated data.
|
||||||
|
*/
|
||||||
|
type AddonMessagesGetMessagesMessageFormatted = AddonMessagesGetMessagesMessage & {
|
||||||
|
sending?: boolean; // Calculated in the app. Whether the message is being sent right now.
|
||||||
|
hash?: string; // Calculated in the app. A hash to identify the message.
|
||||||
|
showDate?: boolean; // Calculated in the app. Whether to show the date before the message.
|
||||||
|
showUserData?: boolean; // Calculated in the app. Whether to show the user data in the message.
|
||||||
|
showTail?: boolean; // Calculated in the app. Whether to show a "tail" in the message.
|
||||||
|
};
|
||||||
|
|
|
@ -17,7 +17,9 @@ import { IonicPage, Platform, NavController, NavParams, Content } from 'ionic-an
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { AddonMessagesProvider } from '../../providers/messages';
|
import {
|
||||||
|
AddonMessagesProvider, AddonMessagesConversationFormatted, AddonMessagesConversationMessage
|
||||||
|
} from '../../providers/messages';
|
||||||
import { AddonMessagesOfflineProvider } from '../../providers/messages-offline';
|
import { AddonMessagesOfflineProvider } from '../../providers/messages-offline';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
|
@ -45,19 +47,19 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
selectedConversationId: number;
|
selectedConversationId: number;
|
||||||
selectedUserId: number;
|
selectedUserId: number;
|
||||||
contactRequestsCount = 0;
|
contactRequestsCount = 0;
|
||||||
favourites: any = {
|
favourites: AddonMessagesGroupConversationOption = {
|
||||||
type: null,
|
type: null,
|
||||||
favourites: true,
|
favourites: true,
|
||||||
count: 0,
|
count: 0,
|
||||||
unread: 0
|
unread: 0,
|
||||||
};
|
};
|
||||||
group: any = {
|
group: AddonMessagesGroupConversationOption = {
|
||||||
type: AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_GROUP,
|
type: AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_GROUP,
|
||||||
favourites: false,
|
favourites: false,
|
||||||
count: 0,
|
count: 0,
|
||||||
unread: 0
|
unread: 0
|
||||||
};
|
};
|
||||||
individual: any = {
|
individual: AddonMessagesGroupConversationOption = {
|
||||||
type: AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
|
type: AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
|
||||||
favourites: false,
|
favourites: false,
|
||||||
count: 0,
|
count: 0,
|
||||||
|
@ -331,7 +333,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
*
|
*
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected fetchDataForExpandedOption(): Promise<any> {
|
protected fetchDataForExpandedOption(): Promise<void> {
|
||||||
const expandedOption = this.getExpandedOption();
|
const expandedOption = this.getExpandedOption();
|
||||||
|
|
||||||
if (expandedOption) {
|
if (expandedOption) {
|
||||||
|
@ -349,12 +351,12 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
* @param getCounts Whether to get counts data.
|
* @param getCounts Whether to get counts data.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
fetchDataForOption(option: any, loadingMore?: boolean, getCounts?: boolean): Promise<void> {
|
fetchDataForOption(option: AddonMessagesGroupConversationOption, loadingMore?: boolean, getCounts?: boolean): Promise<void> {
|
||||||
option.loadMoreError = false;
|
option.loadMoreError = false;
|
||||||
|
|
||||||
const limitFrom = loadingMore ? option.conversations.length : 0,
|
const limitFrom = loadingMore ? option.conversations.length : 0,
|
||||||
promises = [];
|
promises = [];
|
||||||
let data,
|
let data: {conversations: AddonMessagesConversationForList[], canLoadMore: boolean},
|
||||||
offlineMessages;
|
offlineMessages;
|
||||||
|
|
||||||
// Get the conversations and, if needed, the offline messages. Always try to get the latest data.
|
// Get the conversations and, if needed, the offline messages. Always try to get the latest data.
|
||||||
|
@ -422,7 +424,9 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
* @param option The option to search in. If not defined, search in all options.
|
* @param option The option to search in. If not defined, search in all options.
|
||||||
* @return Conversation.
|
* @return Conversation.
|
||||||
*/
|
*/
|
||||||
protected findConversation(conversationId: number, userId?: number, option?: any): any {
|
protected findConversation(conversationId: number, userId?: number, option?: AddonMessagesGroupConversationOption)
|
||||||
|
: AddonMessagesConversationForList {
|
||||||
|
|
||||||
if (conversationId) {
|
if (conversationId) {
|
||||||
const conversations = option ? (option.conversations || []) : ((this.favourites.conversations || [])
|
const conversations = option ? (option.conversations || []) : ((this.favourites.conversations || [])
|
||||||
.concat(this.group.conversations || []).concat(this.individual.conversations || []));
|
.concat(this.group.conversations || []).concat(this.individual.conversations || []));
|
||||||
|
@ -445,7 +449,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
*
|
*
|
||||||
* @return Option currently expanded.
|
* @return Option currently expanded.
|
||||||
*/
|
*/
|
||||||
protected getExpandedOption(): any {
|
protected getExpandedOption(): AddonMessagesGroupConversationOption {
|
||||||
if (this.favourites.expanded) {
|
if (this.favourites.expanded) {
|
||||||
return this.favourites;
|
return this.favourites;
|
||||||
} else if (this.group.expanded) {
|
} else if (this.group.expanded) {
|
||||||
|
@ -495,9 +499,9 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
*
|
*
|
||||||
* @param option The option to fetch data for.
|
* @param option The option to fetch data for.
|
||||||
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
|
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
|
||||||
* @return Resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
loadMoreConversations(option: any, infiniteComplete?: any): Promise<any> {
|
loadMoreConversations(option: AddonMessagesGroupConversationOption, infiniteComplete?: any): Promise<void> {
|
||||||
return this.fetchDataForOption(option, true).catch((error) => {
|
return this.fetchDataForOption(option, true).catch((error) => {
|
||||||
this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingdiscussions', true);
|
this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingdiscussions', true);
|
||||||
option.loadMoreError = true;
|
option.loadMoreError = true;
|
||||||
|
@ -513,7 +517,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
* @param messages Offline messages.
|
* @param messages Offline messages.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected loadOfflineMessages(option: any, messages: any[]): Promise<any> {
|
protected loadOfflineMessages(option: AddonMessagesGroupConversationOption, messages: any[]): Promise<any> {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
messages.forEach((message) => {
|
messages.forEach((message) => {
|
||||||
|
@ -588,7 +592,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
* @param conversation Conversation where to put the last message.
|
* @param conversation Conversation where to put the last message.
|
||||||
* @param message Offline message to add.
|
* @param message Offline message to add.
|
||||||
*/
|
*/
|
||||||
protected addLastOfflineMessage(conversation: any, message: any): void {
|
protected addLastOfflineMessage(conversation: any, message: AddonMessagesConversationMessage): void {
|
||||||
conversation.lastmessage = message.text;
|
conversation.lastmessage = message.text;
|
||||||
conversation.lastmessagedate = message.timecreated / 1000;
|
conversation.lastmessagedate = message.timecreated / 1000;
|
||||||
conversation.lastmessagepending = true;
|
conversation.lastmessagepending = true;
|
||||||
|
@ -601,7 +605,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
* @param conversation Conversation to check.
|
* @param conversation Conversation to check.
|
||||||
* @return Option object.
|
* @return Option object.
|
||||||
*/
|
*/
|
||||||
protected getConversationOption(conversation: any): any {
|
protected getConversationOption(conversation: AddonMessagesConversationForList): AddonMessagesGroupConversationOption {
|
||||||
if (conversation.isfavourite) {
|
if (conversation.isfavourite) {
|
||||||
return this.favourites;
|
return this.favourites;
|
||||||
} else if (conversation.type == AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_GROUP) {
|
} else if (conversation.type == AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_GROUP) {
|
||||||
|
@ -618,7 +622,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
* @param refreshUnreadCounts Whether to refresh unread counts.
|
* @param refreshUnreadCounts Whether to refresh unread counts.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
refreshData(refresher?: any, refreshUnreadCounts: boolean = true): Promise<any> {
|
refreshData(refresher?: any, refreshUnreadCounts: boolean = true): Promise<void> {
|
||||||
// Don't invalidate conversations and so, they always try to get latest data.
|
// Don't invalidate conversations and so, they always try to get latest data.
|
||||||
const promises = [
|
const promises = [
|
||||||
this.messagesProvider.invalidateContactRequestsCountCache(this.siteId)
|
this.messagesProvider.invalidateContactRequestsCountCache(this.siteId)
|
||||||
|
@ -638,7 +642,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
*
|
*
|
||||||
* @param option The option to expand/collapse.
|
* @param option The option to expand/collapse.
|
||||||
*/
|
*/
|
||||||
toggle(option: any): void {
|
toggle(option: AddonMessagesGroupConversationOption): void {
|
||||||
if (option.expanded) {
|
if (option.expanded) {
|
||||||
// Already expanded, close it.
|
// Already expanded, close it.
|
||||||
option.expanded = false;
|
option.expanded = false;
|
||||||
|
@ -658,7 +662,7 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
* @param getCounts Whether to get counts data.
|
* @param getCounts Whether to get counts data.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected expandOption(option: any, getCounts?: boolean): Promise<any> {
|
protected expandOption(option: AddonMessagesGroupConversationOption, getCounts?: boolean): Promise<void> {
|
||||||
// Collapse all and expand the right one.
|
// Collapse all and expand the right one.
|
||||||
this.favourites.expanded = false;
|
this.favourites.expanded = false;
|
||||||
this.group.expanded = false;
|
this.group.expanded = false;
|
||||||
|
@ -715,3 +719,25 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
|
||||||
this.memberInfoObserver && this.memberInfoObserver.off();
|
this.memberInfoObserver && this.memberInfoObserver.off();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversation options.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGroupConversationOption = {
|
||||||
|
type: number; // Option type.
|
||||||
|
favourites: boolean; // Whether it contains favourites conversations.
|
||||||
|
count: number; // Number of conversations.
|
||||||
|
unread?: number; // Number of unread conversations.
|
||||||
|
expanded?: boolean; // Whether the option is currently expanded.
|
||||||
|
loading?: boolean; // Whether the option is being loaded.
|
||||||
|
canLoadMore?: boolean; // Whether it can load more data.
|
||||||
|
loadMoreError?: boolean; // Whether there was an error loading more conversations.
|
||||||
|
conversations?: AddonMessagesConversationForList[]; // List of conversations.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formatted conversation with some calculated data for the list.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesConversationForList = AddonMessagesConversationFormatted & {
|
||||||
|
lastmessagepending?: boolean; // Calculated in the app. Whether last message is pending to be sent.
|
||||||
|
};
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { Component, OnDestroy, ViewChild } from '@angular/core';
|
||||||
import { IonicPage } from 'ionic-angular';
|
import { IonicPage } from 'ionic-angular';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { AddonMessagesProvider } from '../../providers/messages';
|
import { AddonMessagesProvider, AddonMessagesConversationMember, AddonMessagesMessageAreaContact } from '../../providers/messages';
|
||||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
|
@ -38,21 +38,21 @@ export class AddonMessagesSearchPage implements OnDestroy {
|
||||||
contacts = {
|
contacts = {
|
||||||
type: 'contacts',
|
type: 'contacts',
|
||||||
titleString: 'addon.messages.contacts',
|
titleString: 'addon.messages.contacts',
|
||||||
results: [],
|
results: <AddonMessagesConversationMember[]> [],
|
||||||
canLoadMore: false,
|
canLoadMore: false,
|
||||||
loadingMore: false
|
loadingMore: false
|
||||||
};
|
};
|
||||||
nonContacts = {
|
nonContacts = {
|
||||||
type: 'noncontacts',
|
type: 'noncontacts',
|
||||||
titleString: 'addon.messages.noncontacts',
|
titleString: 'addon.messages.noncontacts',
|
||||||
results: [],
|
results: <AddonMessagesConversationMember[]> [],
|
||||||
canLoadMore: false,
|
canLoadMore: false,
|
||||||
loadingMore: false
|
loadingMore: false
|
||||||
};
|
};
|
||||||
messages = {
|
messages = {
|
||||||
type: 'messages',
|
type: 'messages',
|
||||||
titleString: 'addon.messages.messages',
|
titleString: 'addon.messages.messages',
|
||||||
results: [],
|
results: <AddonMessagesMessageAreaContact[]> [],
|
||||||
canLoadMore: false,
|
canLoadMore: false,
|
||||||
loadingMore: false,
|
loadingMore: false,
|
||||||
loadMoreError: false
|
loadMoreError: false
|
||||||
|
@ -116,9 +116,9 @@ export class AddonMessagesSearchPage implements OnDestroy {
|
||||||
this.displaySearching = !loadMore;
|
this.displaySearching = !loadMore;
|
||||||
|
|
||||||
const promises = [];
|
const promises = [];
|
||||||
let newContacts = [];
|
let newContacts: AddonMessagesConversationMember[] = [];
|
||||||
let newNonContacts = [];
|
let newNonContacts: AddonMessagesConversationMember[] = [];
|
||||||
let newMessages = [];
|
let newMessages: AddonMessagesMessageAreaContact[] = [];
|
||||||
let canLoadMoreContacts = false;
|
let canLoadMoreContacts = false;
|
||||||
let canLoadMoreNonContacts = false;
|
let canLoadMoreNonContacts = false;
|
||||||
let canLoadMoreMessages = false;
|
let canLoadMoreMessages = false;
|
||||||
|
|
|
@ -14,7 +14,10 @@
|
||||||
|
|
||||||
import { Component, OnDestroy } from '@angular/core';
|
import { Component, OnDestroy } from '@angular/core';
|
||||||
import { IonicPage } from 'ionic-angular';
|
import { IonicPage } from 'ionic-angular';
|
||||||
import { AddonMessagesProvider } from '../../providers/messages';
|
import {
|
||||||
|
AddonMessagesProvider, AddonMessagesMessagePreferences, AddonMessagesMessagePreferencesNotification,
|
||||||
|
AddonMessagesMessagePreferencesNotificationProcessor
|
||||||
|
} from '../../providers/messages';
|
||||||
import { CoreUserProvider } from '@core/user/providers/user';
|
import { CoreUserProvider } from '@core/user/providers/user';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreConfigProvider } from '@providers/config';
|
import { CoreConfigProvider } from '@providers/config';
|
||||||
|
@ -34,7 +37,7 @@ import { CoreConstants } from '@core/constants';
|
||||||
export class AddonMessagesSettingsPage implements OnDestroy {
|
export class AddonMessagesSettingsPage implements OnDestroy {
|
||||||
protected updateTimeout: any;
|
protected updateTimeout: any;
|
||||||
|
|
||||||
preferences: any;
|
preferences: AddonMessagesMessagePreferences;
|
||||||
preferencesLoaded: boolean;
|
preferencesLoaded: boolean;
|
||||||
contactablePrivacy: number | boolean;
|
contactablePrivacy: number | boolean;
|
||||||
advancedContactable = false; // Whether the site supports "advanced" contactable privacy.
|
advancedContactable = false; // Whether the site supports "advanced" contactable privacy.
|
||||||
|
@ -78,9 +81,9 @@ export class AddonMessagesSettingsPage implements OnDestroy {
|
||||||
/**
|
/**
|
||||||
* Fetches preference data.
|
* Fetches preference data.
|
||||||
*
|
*
|
||||||
* @return Resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected fetchPreferences(): Promise<any> {
|
protected fetchPreferences(): Promise<void> {
|
||||||
return this.messagesProvider.getMessagePreferences().then((preferences) => {
|
return this.messagesProvider.getMessagePreferences().then((preferences) => {
|
||||||
if (this.groupMessagingEnabled) {
|
if (this.groupMessagingEnabled) {
|
||||||
// Simplify the preferences.
|
// Simplify the preferences.
|
||||||
|
@ -90,11 +93,12 @@ export class AddonMessagesSettingsPage implements OnDestroy {
|
||||||
return notification.preferencekey == AddonMessagesProvider.NOTIFICATION_PREFERENCES_KEY;
|
return notification.preferencekey == AddonMessagesProvider.NOTIFICATION_PREFERENCES_KEY;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const notification of component.notifications) {
|
component.notifications.forEach((notification) => {
|
||||||
for (const processor of notification.processors) {
|
notification.processors.forEach(
|
||||||
|
(processor: AddonMessagesMessagePreferencesNotificationProcessorFormatted) => {
|
||||||
processor.checked = processor.loggedin.checked || processor.loggedoff.checked;
|
processor.checked = processor.loggedin.checked || processor.loggedoff.checked;
|
||||||
}
|
});
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,14 +172,16 @@ export class AddonMessagesSettingsPage implements OnDestroy {
|
||||||
* @param state State name, ['loggedin', 'loggedoff'].
|
* @param state State name, ['loggedin', 'loggedoff'].
|
||||||
* @param processor Notification processor.
|
* @param processor Notification processor.
|
||||||
*/
|
*/
|
||||||
changePreference(notification: any, state: string, processor: any): void {
|
changePreference(notification: AddonMessagesMessagePreferencesNotificationFormatted, state: string,
|
||||||
|
processor: AddonMessagesMessagePreferencesNotificationProcessorFormatted): void {
|
||||||
|
|
||||||
if (this.groupMessagingEnabled) {
|
if (this.groupMessagingEnabled) {
|
||||||
// Update both states at the same time.
|
// Update both states at the same time.
|
||||||
const valueArray = [],
|
const valueArray = [],
|
||||||
promises = [];
|
promises = [];
|
||||||
let value = 'none';
|
let value = 'none';
|
||||||
|
|
||||||
notification.processors.forEach((processor) => {
|
notification.processors.forEach((processor: AddonMessagesMessagePreferencesNotificationProcessorFormatted) => {
|
||||||
if (processor.checked) {
|
if (processor.checked) {
|
||||||
valueArray.push(processor.name);
|
valueArray.push(processor.name);
|
||||||
}
|
}
|
||||||
|
@ -268,3 +274,17 @@ export class AddonMessagesSettingsPage implements OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message preferences notification with some caclulated data.
|
||||||
|
*/
|
||||||
|
type AddonMessagesMessagePreferencesNotificationFormatted = AddonMessagesMessagePreferencesNotification & {
|
||||||
|
updating?: boolean | {[state: string]: boolean}; // Calculated in the app. Whether the notification is being updated.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message preferences notification processor with some caclulated data.
|
||||||
|
*/
|
||||||
|
type AddonMessagesMessagePreferencesNotificationProcessorFormatted = AddonMessagesMessagePreferencesNotificationProcessor & {
|
||||||
|
checked?: boolean; // Calculated in the app. Whether the processor is checked either for loggedin or loggedoff.
|
||||||
|
};
|
||||||
|
|
|
@ -248,7 +248,7 @@ export class AddonMessagesMainMenuHandler implements CoreMainMenuHandler, CoreCr
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentUserId = site.getUserId(),
|
const currentUserId = site.getUserId(),
|
||||||
message = conv.messages[0]; // Treat only the last message, is the one we're interested.
|
message: any = conv.messages[0]; // Treat only the last message, is the one we're interested.
|
||||||
|
|
||||||
if (!message || message.useridfrom == currentUserId) {
|
if (!message || message.useridfrom == currentUserId) {
|
||||||
// No last message or not from current user. Return empty list.
|
// No last message or not from current user. Return empty list.
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
import { CoreEmulatorHelperProvider } from '@core/emulator/providers/helper';
|
import { CoreEmulatorHelperProvider } from '@core/emulator/providers/helper';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
|
import { CoreWSExternalWarning } from '@providers/ws';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle messages.
|
* Service to handle messages.
|
||||||
|
@ -89,9 +90,9 @@ export class AddonMessagesProvider {
|
||||||
*
|
*
|
||||||
* @param userId User ID of the person to block.
|
* @param userId User ID of the person to block.
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
blockContact(userId: number, siteId?: string): Promise<any> {
|
blockContact(userId: number, siteId?: string): Promise<void> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
let promise;
|
let promise;
|
||||||
if (site.wsAvailable('core_message_block_user')) {
|
if (site.wsAvailable('core_message_block_user')) {
|
||||||
|
@ -313,7 +314,9 @@ export class AddonMessagesProvider {
|
||||||
* @param userId User ID viewing the conversation.
|
* @param userId User ID viewing the conversation.
|
||||||
* @return Formatted conversation.
|
* @return Formatted conversation.
|
||||||
*/
|
*/
|
||||||
protected formatConversation(conversation: any, userId: number): any {
|
protected formatConversation(conversation: AddonMessagesConversationFormatted, userId: number)
|
||||||
|
: AddonMessagesConversationFormatted {
|
||||||
|
|
||||||
const numMessages = conversation.messages.length,
|
const numMessages = conversation.messages.length,
|
||||||
lastMessage = numMessages ? conversation.messages[numMessages - 1] : null;
|
lastMessage = numMessages ? conversation.messages[numMessages - 1] : null;
|
||||||
|
|
||||||
|
@ -536,10 +539,10 @@ export class AddonMessagesProvider {
|
||||||
* Get all the contacts of the current user.
|
* Get all the contacts of the current user.
|
||||||
*
|
*
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Resolved with the WS data.
|
* @return Promise resolved with the WS data.
|
||||||
* @deprecated since Moodle 3.6
|
* @deprecated since Moodle 3.6
|
||||||
*/
|
*/
|
||||||
getAllContacts(siteId?: string): Promise<any> {
|
getAllContacts(siteId?: string): Promise<AddonMessagesGetContactsResult> {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
return this.getContacts(siteId).then((contacts) => {
|
return this.getContacts(siteId).then((contacts) => {
|
||||||
|
@ -562,9 +565,9 @@ export class AddonMessagesProvider {
|
||||||
* Get all the users blocked by the current user.
|
* Get all the users blocked by the current user.
|
||||||
*
|
*
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Resolved with the WS data.
|
* @return Promise resolved with the WS data.
|
||||||
*/
|
*/
|
||||||
getBlockedContacts(siteId?: string): Promise<any> {
|
getBlockedContacts(siteId?: string): Promise<AddonMessagesGetBlockedUsersResult> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const userId = site.getUserId(),
|
const userId = site.getUserId(),
|
||||||
params = {
|
params = {
|
||||||
|
@ -585,19 +588,24 @@ export class AddonMessagesProvider {
|
||||||
* This excludes the blocked users.
|
* This excludes the blocked users.
|
||||||
*
|
*
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Resolved with the WS data.
|
* @return Promise resolved with the WS data.
|
||||||
* @deprecated since Moodle 3.6
|
* @deprecated since Moodle 3.6
|
||||||
*/
|
*/
|
||||||
getContacts(siteId?: string): Promise<any> {
|
getContacts(siteId?: string): Promise<AddonMessagesGetContactsResult> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const preSets = {
|
const preSets = {
|
||||||
cacheKey: this.getCacheKeyForContacts(),
|
cacheKey: this.getCacheKeyForContacts(),
|
||||||
updateFrequency: CoreSite.FREQUENCY_OFTEN
|
updateFrequency: CoreSite.FREQUENCY_OFTEN
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_contacts', undefined, preSets).then((contacts) => {
|
return site.read('core_message_get_contacts', undefined, preSets).then((contacts: AddonMessagesGetContactsResult) => {
|
||||||
// Filter contacts with negative ID, they are notifications.
|
// Filter contacts with negative ID, they are notifications.
|
||||||
const validContacts = {};
|
const validContacts: AddonMessagesGetContactsResult = {
|
||||||
|
online: [],
|
||||||
|
offline: [],
|
||||||
|
strangers: []
|
||||||
|
};
|
||||||
|
|
||||||
for (const typeName in contacts) {
|
for (const typeName in contacts) {
|
||||||
if (!validContacts[typeName]) {
|
if (!validContacts[typeName]) {
|
||||||
validContacts[typeName] = [];
|
validContacts[typeName] = [];
|
||||||
|
@ -621,11 +629,11 @@ export class AddonMessagesProvider {
|
||||||
* @param limitFrom Position of the first contact to fetch.
|
* @param limitFrom Position of the first contact to fetch.
|
||||||
* @param limitNum Number of contacts to fetch. Default is AddonMessagesProvider.LIMIT_CONTACTS.
|
* @param limitNum Number of contacts to fetch. Default is AddonMessagesProvider.LIMIT_CONTACTS.
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Resolved with the list of user contacts.
|
* @return Promise resolved with the list of user contacts.
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
getUserContacts(limitFrom: number = 0, limitNum: number = AddonMessagesProvider.LIMIT_CONTACTS , siteId?: string):
|
getUserContacts(limitFrom: number = 0, limitNum: number = AddonMessagesProvider.LIMIT_CONTACTS , siteId?: string):
|
||||||
Promise<{contacts: any[], canLoadMore: boolean}> {
|
Promise<{contacts: AddonMessagesConversationMember[], canLoadMore: boolean}> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
|
@ -638,7 +646,9 @@ export class AddonMessagesProvider {
|
||||||
updateFrequency: CoreSite.FREQUENCY_OFTEN
|
updateFrequency: CoreSite.FREQUENCY_OFTEN
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_user_contacts', params, preSets).then((contacts) => {
|
return site.read('core_message_get_user_contacts', params, preSets)
|
||||||
|
.then((contacts: AddonMessagesConversationMember[]) => {
|
||||||
|
|
||||||
if (!contacts || !contacts.length) {
|
if (!contacts || !contacts.length) {
|
||||||
return { contacts: [], canLoadMore: false };
|
return { contacts: [], canLoadMore: false };
|
||||||
}
|
}
|
||||||
|
@ -663,11 +673,11 @@ export class AddonMessagesProvider {
|
||||||
* @param limitFrom Position of the first contact request to fetch.
|
* @param limitFrom Position of the first contact request to fetch.
|
||||||
* @param limitNum Number of contact requests to fetch. Default is AddonMessagesProvider.LIMIT_CONTACTS.
|
* @param limitNum Number of contact requests to fetch. Default is AddonMessagesProvider.LIMIT_CONTACTS.
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Resolved with the list of contact requests.
|
* @return Promise resolved with the list of contact requests.
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
getContactRequests(limitFrom: number = 0, limitNum: number = AddonMessagesProvider.LIMIT_CONTACTS, siteId?: string):
|
getContactRequests(limitFrom: number = 0, limitNum: number = AddonMessagesProvider.LIMIT_CONTACTS, siteId?: string):
|
||||||
Promise<{requests: any[], canLoadMore: boolean}> {
|
Promise<{requests: AddonMessagesConversationMember[], canLoadMore: boolean}> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const data = {
|
const data = {
|
||||||
|
@ -680,7 +690,9 @@ export class AddonMessagesProvider {
|
||||||
updateFrequency: CoreSite.FREQUENCY_OFTEN
|
updateFrequency: CoreSite.FREQUENCY_OFTEN
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_contact_requests', data, preSets).then((requests) => {
|
return site.read('core_message_get_contact_requests', data, preSets)
|
||||||
|
.then((requests: AddonMessagesConversationMember[]) => {
|
||||||
|
|
||||||
if (!requests || !requests.length) {
|
if (!requests || !requests.length) {
|
||||||
return { requests: [], canLoadMore: false };
|
return { requests: [], canLoadMore: false };
|
||||||
}
|
}
|
||||||
|
@ -716,7 +728,7 @@ export class AddonMessagesProvider {
|
||||||
typeExpected: 'number'
|
typeExpected: 'number'
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_received_contact_requests_count', data, preSets).then((count) => {
|
return site.read('core_message_get_received_contact_requests_count', data, preSets).then((count: number) => {
|
||||||
// Notify the new count so all badges are updated.
|
// Notify the new count so all badges are updated.
|
||||||
this.eventsProvider.trigger(AddonMessagesProvider.CONTACT_REQUESTS_COUNT_EVENT, { count }, site.id);
|
this.eventsProvider.trigger(AddonMessagesProvider.CONTACT_REQUESTS_COUNT_EVENT, { count }, site.id);
|
||||||
|
|
||||||
|
@ -745,7 +757,7 @@ export class AddonMessagesProvider {
|
||||||
*/
|
*/
|
||||||
getConversation(conversationId: number, includeContactRequests?: boolean, includePrivacyInfo?: boolean,
|
getConversation(conversationId: number, includeContactRequests?: boolean, includePrivacyInfo?: boolean,
|
||||||
messageOffset: number = 0, messageLimit: number = 1, memberOffset: number = 0, memberLimit: number = 2,
|
messageOffset: number = 0, messageLimit: number = 1, memberOffset: number = 0, memberLimit: number = 2,
|
||||||
newestFirst: boolean = true, siteId?: string, userId?: number): Promise<any> {
|
newestFirst: boolean = true, siteId?: string, userId?: number): Promise<AddonMessagesConversationFormatted> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
@ -765,7 +777,7 @@ export class AddonMessagesProvider {
|
||||||
newestmessagesfirst: newestFirst ? 1 : 0
|
newestmessagesfirst: newestFirst ? 1 : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_conversation', params, preSets).then((conversation) => {
|
return site.read('core_message_get_conversation', params, preSets).then((conversation: AddonMessagesConversation) => {
|
||||||
return this.formatConversation(conversation, userId);
|
return this.formatConversation(conversation, userId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -792,7 +804,8 @@ export class AddonMessagesProvider {
|
||||||
*/
|
*/
|
||||||
getConversationBetweenUsers(otherUserId: number, includeContactRequests?: boolean, includePrivacyInfo?: boolean,
|
getConversationBetweenUsers(otherUserId: number, includeContactRequests?: boolean, includePrivacyInfo?: boolean,
|
||||||
messageOffset: number = 0, messageLimit: number = 1, memberOffset: number = 0, memberLimit: number = 2,
|
messageOffset: number = 0, messageLimit: number = 1, memberOffset: number = 0, memberLimit: number = 2,
|
||||||
newestFirst: boolean = true, siteId?: string, userId?: number, preferCache?: boolean): Promise<any> {
|
newestFirst: boolean = true, siteId?: string, userId?: number, preferCache?: boolean)
|
||||||
|
: Promise<AddonMessagesConversationFormatted> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
@ -813,7 +826,8 @@ export class AddonMessagesProvider {
|
||||||
newestmessagesfirst: newestFirst ? 1 : 0
|
newestmessagesfirst: newestFirst ? 1 : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_conversation_between_users', params, preSets).then((conversation) => {
|
return site.read('core_message_get_conversation_between_users', params, preSets)
|
||||||
|
.then((conversation: AddonMessagesConversation) => {
|
||||||
return this.formatConversation(conversation, userId);
|
return this.formatConversation(conversation, userId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -826,12 +840,11 @@ export class AddonMessagesProvider {
|
||||||
* @param limitFrom Offset for members list.
|
* @param limitFrom Offset for members list.
|
||||||
* @param limitTo Limit of members.
|
* @param limitTo Limit of members.
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @param userId User ID. If not defined, current user in the site.
|
* @param userId User ID. If not defined, current user in
|
||||||
* @return Promise resolved with the response.
|
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
getConversationMembers(conversationId: number, limitFrom: number = 0, limitTo?: number, includeContactRequests?: boolean,
|
getConversationMembers(conversationId: number, limitFrom: number = 0, limitTo?: number, includeContactRequests?: boolean,
|
||||||
siteId?: string, userId?: number): Promise<any> {
|
siteId?: string, userId?: number): Promise<{members: AddonMessagesConversationMember[], canLoadMore: boolean}> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
@ -853,18 +866,21 @@ export class AddonMessagesProvider {
|
||||||
includeprivacyinfo: 1,
|
includeprivacyinfo: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_conversation_members', params, preSets).then((members) => {
|
return site.read('core_message_get_conversation_members', params, preSets)
|
||||||
const result: any = {};
|
.then((members: AddonMessagesConversationMember[]) => {
|
||||||
|
|
||||||
if (limitTo < 1) {
|
if (limitTo < 1) {
|
||||||
result.canLoadMore = false;
|
return {
|
||||||
result.members = members;
|
canLoadMore: false,
|
||||||
|
members: members
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
result.canLoadMore = members.length > limitTo;
|
return {
|
||||||
result.members = members.slice(0, limitTo);
|
canLoadMore: members.length > limitTo,
|
||||||
|
members: members.slice(0, limitTo)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -884,7 +900,8 @@ export class AddonMessagesProvider {
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
getConversationMessages(conversationId: number, excludePending: boolean, limitFrom: number = 0, limitTo?: number,
|
getConversationMessages(conversationId: number, excludePending: boolean, limitFrom: number = 0, limitTo?: number,
|
||||||
newestFirst: boolean = true, timeFrom: number = 0, siteId?: string, userId?: number): Promise<any> {
|
newestFirst: boolean = true, timeFrom: number = 0, siteId?: string, userId?: number)
|
||||||
|
: Promise<AddonMessagesGetConversationMessagesResult> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
@ -913,7 +930,9 @@ export class AddonMessagesProvider {
|
||||||
preSets['emergencyCache'] = false;
|
preSets['emergencyCache'] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('core_message_get_conversation_messages', params, preSets).then((result) => {
|
return site.read('core_message_get_conversation_messages', params, preSets)
|
||||||
|
.then((result: AddonMessagesGetConversationMessagesResult) => {
|
||||||
|
|
||||||
if (limitTo < 1) {
|
if (limitTo < 1) {
|
||||||
result.canLoadMore = false;
|
result.canLoadMore = false;
|
||||||
result.messages = result.messages;
|
result.messages = result.messages;
|
||||||
|
@ -975,7 +994,8 @@ export class AddonMessagesProvider {
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
getConversations(type?: number, favourites?: boolean, limitFrom: number = 0, siteId?: string, userId?: number,
|
getConversations(type?: number, favourites?: boolean, limitFrom: number = 0, siteId?: string, userId?: number,
|
||||||
forceCache?: boolean, ignoreCache?: boolean): Promise<{conversations: any[], canLoadMore: boolean}> {
|
forceCache?: boolean, ignoreCache?: boolean)
|
||||||
|
: Promise<{conversations: AddonMessagesConversationFormatted[], canLoadMore: boolean}> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
@ -1017,7 +1037,7 @@ export class AddonMessagesProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}).then((response) => {
|
}).then((response: AddonMessagesGetConversationsResult) => {
|
||||||
// Format the conversations, adding some calculated fields.
|
// Format the conversations, adding some calculated fields.
|
||||||
const conversations = response.conversations.slice(0, this.LIMIT_MESSAGES).map((conversation) => {
|
const conversations = response.conversations.slice(0, this.LIMIT_MESSAGES).map((conversation) => {
|
||||||
return this.formatConversation(conversation, userId);
|
return this.formatConversation(conversation, userId);
|
||||||
|
@ -1053,7 +1073,9 @@ export class AddonMessagesProvider {
|
||||||
cacheKey: this.getCacheKeyForConversationCounts()
|
cacheKey: this.getCacheKeyForConversationCounts()
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_conversation_counts', {}, preSets).then((result) => {
|
return site.read('core_message_get_conversation_counts', {}, preSets)
|
||||||
|
.then((result: AddonMessagesGetConversationCountsResult) => {
|
||||||
|
|
||||||
const counts = {
|
const counts = {
|
||||||
favourites: result.favourites,
|
favourites: result.favourites,
|
||||||
individual: result.types[AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL],
|
individual: result.types[AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL],
|
||||||
|
@ -1080,10 +1102,14 @@ export class AddonMessagesProvider {
|
||||||
* @return Promise resolved with messages and a boolean telling if can load more messages.
|
* @return Promise resolved with messages and a boolean telling if can load more messages.
|
||||||
*/
|
*/
|
||||||
getDiscussion(userId: number, excludePending: boolean, lfReceivedUnread: number = 0, lfReceivedRead: number = 0,
|
getDiscussion(userId: number, excludePending: boolean, lfReceivedUnread: number = 0, lfReceivedRead: number = 0,
|
||||||
lfSentUnread: number = 0, lfSentRead: number = 0, toDisplay: boolean = true, siteId?: string): Promise<any> {
|
lfSentUnread: number = 0, lfSentRead: number = 0, toDisplay: boolean = true, siteId?: string)
|
||||||
|
: Promise<{messages: AddonMessagesGetMessagesMessage[], canLoadMore: boolean}> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const result = {},
|
const result = {
|
||||||
|
messages: <AddonMessagesGetMessagesMessage[]> [],
|
||||||
|
canLoadMore: false
|
||||||
|
},
|
||||||
preSets = {
|
preSets = {
|
||||||
cacheKey: this.getCacheKeyForDiscussion(userId)
|
cacheKey: this.getCacheKeyForDiscussion(userId)
|
||||||
},
|
},
|
||||||
|
@ -1107,7 +1133,7 @@ export class AddonMessagesProvider {
|
||||||
// Get message received by current user.
|
// Get message received by current user.
|
||||||
return this.getRecentMessages(params, preSets, lfReceivedUnread, lfReceivedRead, toDisplay, site.getId())
|
return this.getRecentMessages(params, preSets, lfReceivedUnread, lfReceivedRead, toDisplay, site.getId())
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
result['messages'] = response;
|
result.messages = response;
|
||||||
params.useridto = userId;
|
params.useridto = userId;
|
||||||
params.useridfrom = site.getUserId();
|
params.useridfrom = site.getUserId();
|
||||||
hasReceived = response.length > 0;
|
hasReceived = response.length > 0;
|
||||||
|
@ -1115,16 +1141,16 @@ export class AddonMessagesProvider {
|
||||||
// Get message sent by current user.
|
// Get message sent by current user.
|
||||||
return this.getRecentMessages(params, preSets, lfSentUnread, lfSentRead, toDisplay, siteId);
|
return this.getRecentMessages(params, preSets, lfSentUnread, lfSentRead, toDisplay, siteId);
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
result['messages'] = result['messages'].concat(response);
|
result.messages = result.messages.concat(response);
|
||||||
hasSent = response.length > 0;
|
hasSent = response.length > 0;
|
||||||
|
|
||||||
if (result['messages'].length > this.LIMIT_MESSAGES) {
|
if (result.messages.length > this.LIMIT_MESSAGES) {
|
||||||
// Sort messages and get the more recent ones.
|
// Sort messages and get the more recent ones.
|
||||||
result['canLoadMore'] = true;
|
result.canLoadMore = true;
|
||||||
result['messages'] = this.sortMessages(result['messages']);
|
result.messages = this.sortMessages(result['messages']);
|
||||||
result['messages'] = result['messages'].slice(-this.LIMIT_MESSAGES);
|
result.messages = result.messages.slice(-this.LIMIT_MESSAGES);
|
||||||
} else {
|
} else {
|
||||||
result['canLoadMore'] = result['messages'].length == this.LIMIT_MESSAGES && (!hasReceived || !hasSent);
|
result.canLoadMore = result.messages.length == this.LIMIT_MESSAGES && (!hasReceived || !hasSent);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (excludePending) {
|
if (excludePending) {
|
||||||
|
@ -1140,7 +1166,7 @@ export class AddonMessagesProvider {
|
||||||
message.text = message.smallmessage;
|
message.text = message.smallmessage;
|
||||||
});
|
});
|
||||||
|
|
||||||
result['messages'] = result['messages'].concat(offlineMessages);
|
result.messages = result.messages.concat(offlineMessages);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
@ -1153,11 +1179,11 @@ export class AddonMessagesProvider {
|
||||||
* If the site is 3.6 or higher, please use getConversations.
|
* If the site is 3.6 or higher, please use getConversations.
|
||||||
*
|
*
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Resolved with an object where the keys are the user ID of the other user.
|
* @return Promise resolved with an object where the keys are the user ID of the other user.
|
||||||
*/
|
*/
|
||||||
getDiscussions(siteId?: string): Promise<any> {
|
getDiscussions(siteId?: string): Promise<{[userId: number]: AddonMessagesDiscussion}> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const discussions = {},
|
const discussions: {[userId: number]: AddonMessagesDiscussion} = {},
|
||||||
currentUserId = site.getUserId(),
|
currentUserId = site.getUserId(),
|
||||||
params = {
|
params = {
|
||||||
useridto: currentUserId,
|
useridto: currentUserId,
|
||||||
|
@ -1171,7 +1197,7 @@ export class AddonMessagesProvider {
|
||||||
/**
|
/**
|
||||||
* Convenience function to treat a recent message, adding it to discussions list if needed.
|
* Convenience function to treat a recent message, adding it to discussions list if needed.
|
||||||
*/
|
*/
|
||||||
const treatRecentMessage = (message: any, userId: number, userFullname: string): void => {
|
const treatRecentMessage = (message: AddonMessagesGetMessagesMessage, userId: number, userFullname: string): void => {
|
||||||
if (typeof discussions[userId] === 'undefined') {
|
if (typeof discussions[userId] === 'undefined') {
|
||||||
discussions[userId] = {
|
discussions[userId] = {
|
||||||
fullname: userFullname,
|
fullname: userFullname,
|
||||||
|
@ -1272,7 +1298,7 @@ export class AddonMessagesProvider {
|
||||||
* @return Promise resolved with the member info.
|
* @return Promise resolved with the member info.
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
getMemberInfo(otherUserId: number, siteId?: string, userId?: number): Promise<any> {
|
getMemberInfo(otherUserId: number, siteId?: string, userId?: number): Promise<AddonMessagesConversationMember> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
|
||||||
|
@ -1287,7 +1313,9 @@ export class AddonMessagesProvider {
|
||||||
includeprivacyinfo: 1,
|
includeprivacyinfo: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_member_info', params, preSets).then((members) => {
|
return site.read('core_message_get_member_info', params, preSets)
|
||||||
|
.then((members: AddonMessagesConversationMember[]): any => {
|
||||||
|
|
||||||
if (!members || members.length < 1) {
|
if (!members || members.length < 1) {
|
||||||
// Should never happen.
|
// Should never happen.
|
||||||
return Promise.reject(null);
|
return Promise.reject(null);
|
||||||
|
@ -1313,7 +1341,7 @@ export class AddonMessagesProvider {
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Promise resolved with the message preferences.
|
* @return Promise resolved with the message preferences.
|
||||||
*/
|
*/
|
||||||
getMessagePreferences(siteId?: string): Promise<any> {
|
getMessagePreferences(siteId?: string): Promise<AddonMessagesMessagePreferences> {
|
||||||
this.logger.debug('Get message preferences');
|
this.logger.debug('Get message preferences');
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
@ -1322,7 +1350,9 @@ export class AddonMessagesProvider {
|
||||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_user_message_preferences', {}, preSets).then((data) => {
|
return site.read('core_message_get_user_message_preferences', {}, preSets)
|
||||||
|
.then((data: AddonMessagesGetUserMessagePreferencesResult): any => {
|
||||||
|
|
||||||
if (data.preferences) {
|
if (data.preferences) {
|
||||||
data.preferences.blocknoncontacts = data.blocknoncontacts;
|
data.preferences.blocknoncontacts = data.blocknoncontacts;
|
||||||
|
|
||||||
|
@ -1341,15 +1371,18 @@ export class AddonMessagesProvider {
|
||||||
* @param preSets Set of presets for the WS.
|
* @param preSets Set of presets for the WS.
|
||||||
* @param toDisplay True if messages will be displayed to the user, either in view or in a notification.
|
* @param toDisplay True if messages will be displayed to the user, either in view or in a notification.
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
|
* @return Promise resolved with the data.
|
||||||
*/
|
*/
|
||||||
protected getMessages(params: any, preSets: any, toDisplay: boolean = true, siteId?: string): Promise<any> {
|
protected getMessages(params: any, preSets: any, toDisplay: boolean = true, siteId?: string)
|
||||||
|
: Promise<AddonMessagesGetMessagesResult> {
|
||||||
|
|
||||||
params['type'] = 'conversations';
|
params['type'] = 'conversations';
|
||||||
params['newestfirst'] = 1;
|
params['newestfirst'] = 1;
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const userId = site.getUserId();
|
const userId = site.getUserId();
|
||||||
|
|
||||||
return site.read('core_message_get_messages', params, preSets).then((response) => {
|
return site.read('core_message_get_messages', params, preSets).then((response: AddonMessagesGetMessagesResult) => {
|
||||||
response.messages.forEach((message) => {
|
response.messages.forEach((message) => {
|
||||||
message.read = params.read == 0 ? 0 : 1;
|
message.read = params.read == 0 ? 0 : 1;
|
||||||
// Convert times to milliseconds.
|
// Convert times to milliseconds.
|
||||||
|
@ -1377,9 +1410,10 @@ export class AddonMessagesProvider {
|
||||||
* @param limitFromRead Number of unread messages already fetched, so fetch will be done from this number.
|
* @param limitFromRead Number of unread messages already fetched, so fetch will be done from this number.
|
||||||
* @param toDisplay True if messages will be displayed to the user, either in view or in a notification.
|
* @param toDisplay True if messages will be displayed to the user, either in view or in a notification.
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
|
* @return Promise resolved with the data.
|
||||||
*/
|
*/
|
||||||
protected getRecentMessages(params: any, preSets: any, limitFromUnread: number = 0, limitFromRead: number = 0,
|
protected getRecentMessages(params: any, preSets: any, limitFromUnread: number = 0, limitFromRead: number = 0,
|
||||||
toDisplay: boolean = true, siteId?: string): Promise<any> {
|
toDisplay: boolean = true, siteId?: string): Promise<AddonMessagesGetMessagesMessage[]> {
|
||||||
limitFromUnread = limitFromUnread || 0;
|
limitFromUnread = limitFromUnread || 0;
|
||||||
limitFromRead = limitFromRead || 0;
|
limitFromRead = limitFromRead || 0;
|
||||||
|
|
||||||
|
@ -1427,7 +1461,7 @@ export class AddonMessagesProvider {
|
||||||
* @since 3.7
|
* @since 3.7
|
||||||
*/
|
*/
|
||||||
getSelfConversation(messageOffset: number = 0, messageLimit: number = 1, newestFirst: boolean = true, siteId?: string,
|
getSelfConversation(messageOffset: number = 0, messageLimit: number = 1, newestFirst: boolean = true, siteId?: string,
|
||||||
userId?: number): Promise<any> {
|
userId?: number): Promise<AddonMessagesConversationFormatted> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
userId = userId || site.getUserId();
|
userId = userId || site.getUserId();
|
||||||
|
@ -1442,7 +1476,8 @@ export class AddonMessagesProvider {
|
||||||
newestmessagesfirst: newestFirst ? 1 : 0
|
newestmessagesfirst: newestFirst ? 1 : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_self_conversation', params, preSets).then((conversation) => {
|
return site.read('core_message_get_self_conversation', params, preSets)
|
||||||
|
.then((conversation: AddonMessagesConversation) => {
|
||||||
return this.formatConversation(conversation, userId);
|
return this.formatConversation(conversation, userId);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1466,7 +1501,8 @@ export class AddonMessagesProvider {
|
||||||
cacheKey: this.getCacheKeyForUnreadConversationCounts()
|
cacheKey: this.getCacheKeyForUnreadConversationCounts()
|
||||||
};
|
};
|
||||||
|
|
||||||
promise = site.read('core_message_get_unread_conversation_counts', {}, preSets).then((result) => {
|
promise = site.read('core_message_get_unread_conversation_counts', {}, preSets)
|
||||||
|
.then((result: AddonMessagesGetUnreadConversationCountsResult) => {
|
||||||
return {
|
return {
|
||||||
favourites: result.favourites,
|
favourites: result.favourites,
|
||||||
individual: result.types[AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL],
|
individual: result.types[AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_INDIVIDUAL],
|
||||||
|
@ -1485,7 +1521,7 @@ export class AddonMessagesProvider {
|
||||||
typeExpected: 'number'
|
typeExpected: 'number'
|
||||||
};
|
};
|
||||||
|
|
||||||
promise = site.read('core_message_get_unread_conversations_count', params, preSets).then((count) => {
|
promise = site.read('core_message_get_unread_conversations_count', params, preSets).then((count: number) => {
|
||||||
return { favourites: 0, individual: count, group: 0, self: 0 };
|
return { favourites: 0, individual: count, group: 0, self: 0 };
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -1536,7 +1572,7 @@ export class AddonMessagesProvider {
|
||||||
* @return Promise resolved with the message unread count.
|
* @return Promise resolved with the message unread count.
|
||||||
*/
|
*/
|
||||||
getUnreadReceivedMessages(toDisplay: boolean = true, forceCache: boolean = false, ignoreCache: boolean = false,
|
getUnreadReceivedMessages(toDisplay: boolean = true, forceCache: boolean = false, ignoreCache: boolean = false,
|
||||||
siteId?: string): Promise<any> {
|
siteId?: string): Promise<AddonMessagesGetMessagesResult> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
read: 0,
|
read: 0,
|
||||||
|
@ -2049,7 +2085,7 @@ export class AddonMessagesProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved with boolean marking success or not.
|
* @return Promise resolved with boolean marking success or not.
|
||||||
*/
|
*/
|
||||||
markMessageRead(messageId: number, siteId?: string): Promise<any> {
|
markMessageRead(messageId: number, siteId?: string): Promise<AddonMessagesMarkMessageReadResult> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
messageid: messageId,
|
messageid: messageId,
|
||||||
|
@ -2067,7 +2103,7 @@ export class AddonMessagesProvider {
|
||||||
* @return Promise resolved if success.
|
* @return Promise resolved if success.
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
markAllConversationMessagesRead(conversationId?: number): Promise<any> {
|
markAllConversationMessagesRead(conversationId?: number): Promise<null> {
|
||||||
const params = {
|
const params = {
|
||||||
userid: this.sitesProvider.getCurrentSiteUserId(),
|
userid: this.sitesProvider.getCurrentSiteUserId(),
|
||||||
conversationid: conversationId
|
conversationid: conversationId
|
||||||
|
@ -2085,7 +2121,7 @@ export class AddonMessagesProvider {
|
||||||
* @param userIdFrom User Id for the sender.
|
* @param userIdFrom User Id for the sender.
|
||||||
* @return Promise resolved with boolean marking success or not.
|
* @return Promise resolved with boolean marking success or not.
|
||||||
*/
|
*/
|
||||||
markAllMessagesRead(userIdFrom?: number): Promise<any> {
|
markAllMessagesRead(userIdFrom?: number): Promise<boolean> {
|
||||||
const params = {
|
const params = {
|
||||||
useridto: this.sitesProvider.getCurrentSiteUserId(),
|
useridto: this.sitesProvider.getCurrentSiteUserId(),
|
||||||
useridfrom: userIdFrom
|
useridfrom: userIdFrom
|
||||||
|
@ -2217,8 +2253,9 @@ export class AddonMessagesProvider {
|
||||||
* @param query The query string.
|
* @param query The query string.
|
||||||
* @param limit The number of results to return, 0 for none.
|
* @param limit The number of results to return, 0 for none.
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
|
* @return Promise resolved with the contacts.
|
||||||
*/
|
*/
|
||||||
searchContacts(query: string, limit: number = 100, siteId?: string): Promise<any> {
|
searchContacts(query: string, limit: number = 100, siteId?: string): Promise<AddonMessagesSearchContactsContact[]> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const data = {
|
const data = {
|
||||||
searchtext: query,
|
searchtext: query,
|
||||||
|
@ -2228,7 +2265,9 @@ export class AddonMessagesProvider {
|
||||||
getFromCache: false // Always try to get updated data. If it fails, it will get it from cache.
|
getFromCache: false // Always try to get updated data. If it fails, it will get it from cache.
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_search_contacts', data, preSets).then((contacts) => {
|
return site.read('core_message_search_contacts', data, preSets)
|
||||||
|
.then((contacts: AddonMessagesSearchContactsContact[]) => {
|
||||||
|
|
||||||
if (limit && contacts.length > limit) {
|
if (limit && contacts.length > limit) {
|
||||||
contacts = contacts.splice(0, limit);
|
contacts = contacts.splice(0, limit);
|
||||||
}
|
}
|
||||||
|
@ -2250,7 +2289,7 @@ export class AddonMessagesProvider {
|
||||||
* @return Promise resolved with the results.
|
* @return Promise resolved with the results.
|
||||||
*/
|
*/
|
||||||
searchMessages(query: string, userId?: number, limitFrom: number = 0, limitNum: number = AddonMessagesProvider.LIMIT_SEARCH,
|
searchMessages(query: string, userId?: number, limitFrom: number = 0, limitNum: number = AddonMessagesProvider.LIMIT_SEARCH,
|
||||||
siteId?: string): Promise<{messages: any[], canLoadMore: boolean}> {
|
siteId?: string): Promise<{messages: AddonMessagesMessageAreaContact[], canLoadMore: boolean}> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
|
@ -2263,13 +2302,15 @@ export class AddonMessagesProvider {
|
||||||
getFromCache: false // Always try to get updated data. If it fails, it will get it from cache.
|
getFromCache: false // Always try to get updated data. If it fails, it will get it from cache.
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_data_for_messagearea_search_messages', params, preSets).then((result) => {
|
return site.read('core_message_data_for_messagearea_search_messages', params, preSets)
|
||||||
|
.then((result: AddonMessagesDataForMessageAreaSearchMessagesResult) => {
|
||||||
|
|
||||||
if (!result.contacts || !result.contacts.length) {
|
if (!result.contacts || !result.contacts.length) {
|
||||||
return { messages: [], canLoadMore: false };
|
return { messages: [], canLoadMore: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
result.contacts.forEach((result) => {
|
result.contacts.forEach((contact) => {
|
||||||
result.id = result.userid;
|
contact.id = contact.userid;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.userProvider.storeUsers(result.contacts, site.id);
|
this.userProvider.storeUsers(result.contacts, site.id);
|
||||||
|
@ -2297,7 +2338,8 @@ export class AddonMessagesProvider {
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
searchUsers(query: string, limitFrom: number = 0, limitNum: number = AddonMessagesProvider.LIMIT_SEARCH, siteId?: string):
|
searchUsers(query: string, limitFrom: number = 0, limitNum: number = AddonMessagesProvider.LIMIT_SEARCH, siteId?: string):
|
||||||
Promise<{contacts: any[], nonContacts: any[], canLoadMoreContacts: boolean, canLoadMoreNonContacts: boolean}> {
|
Promise<{contacts: AddonMessagesConversationMember[], nonContacts: AddonMessagesConversationMember[],
|
||||||
|
canLoadMoreContacts: boolean, canLoadMoreNonContacts: boolean}> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const data = {
|
const data = {
|
||||||
|
@ -2310,7 +2352,7 @@ export class AddonMessagesProvider {
|
||||||
getFromCache: false // Always try to get updated data. If it fails, it will get it from cache.
|
getFromCache: false // Always try to get updated data. If it fails, it will get it from cache.
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_message_search_users', data, preSets).then((result) => {
|
return site.read('core_message_message_search_users', data, preSets).then((result: AddonMessagesSearchUsersResult) => {
|
||||||
const contacts = result.contacts || [];
|
const contacts = result.contacts || [];
|
||||||
const nonContacts = result.noncontacts || [];
|
const nonContacts = result.noncontacts || [];
|
||||||
|
|
||||||
|
@ -2341,7 +2383,9 @@ export class AddonMessagesProvider {
|
||||||
* - sent (Boolean) True if message was sent to server, false if stored in device.
|
* - sent (Boolean) True if message was sent to server, false if stored in device.
|
||||||
* - message (Object) If sent=false, contains the stored message.
|
* - message (Object) If sent=false, contains the stored message.
|
||||||
*/
|
*/
|
||||||
sendMessage(toUserId: number, message: string, siteId?: string): Promise<any> {
|
sendMessage(toUserId: number, message: string, siteId?: string)
|
||||||
|
: Promise<{sent: boolean, message: AddonMessagesSendInstantMessagesMessage}> {
|
||||||
|
|
||||||
// Convenience function to store a message to be synchronized later.
|
// Convenience function to store a message to be synchronized later.
|
||||||
const storeOffline = (): Promise<any> => {
|
const storeOffline = (): Promise<any> => {
|
||||||
return this.messagesOffline.saveMessage(toUserId, message, siteId).then((entry) => {
|
return this.messagesOffline.saveMessage(toUserId, message, siteId).then((entry) => {
|
||||||
|
@ -2395,7 +2439,7 @@ export class AddonMessagesProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved if success, rejected if failure.
|
* @return Promise resolved if success, rejected if failure.
|
||||||
*/
|
*/
|
||||||
sendMessageOnline(toUserId: number, message: string, siteId?: string): Promise<any> {
|
sendMessageOnline(toUserId: number, message: string, siteId?: string): Promise<AddonMessagesSendInstantMessagesMessage> {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
const messages = [
|
const messages = [
|
||||||
|
@ -2430,7 +2474,7 @@ export class AddonMessagesProvider {
|
||||||
* @return Promise resolved if success, rejected if failure. Promise resolved doesn't mean that messages
|
* @return Promise resolved if success, rejected if failure. Promise resolved doesn't mean that messages
|
||||||
* have been sent, the resolve param can contain errors for messages not sent.
|
* have been sent, the resolve param can contain errors for messages not sent.
|
||||||
*/
|
*/
|
||||||
sendMessagesOnline(messages: any, siteId?: string): Promise<any> {
|
sendMessagesOnline(messages: any[], siteId?: string): Promise<AddonMessagesSendInstantMessagesMessage[]> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const data = {
|
const data = {
|
||||||
messages: messages
|
messages: messages
|
||||||
|
@ -2451,7 +2495,9 @@ export class AddonMessagesProvider {
|
||||||
* - message (any) If sent=false, contains the stored message.
|
* - message (any) If sent=false, contains the stored message.
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
sendMessageToConversation(conversation: any, message: string, siteId?: string): Promise<any> {
|
sendMessageToConversation(conversation: any, message: string, siteId?: string)
|
||||||
|
: Promise<{sent: boolean, message: AddonMessagesSendMessagesToConversationMessage}> {
|
||||||
|
|
||||||
// Convenience function to store a message to be synchronized later.
|
// Convenience function to store a message to be synchronized later.
|
||||||
const storeOffline = (): Promise<any> => {
|
const storeOffline = (): Promise<any> => {
|
||||||
return this.messagesOffline.saveConversationMessage(conversation, message, siteId).then((entry) => {
|
return this.messagesOffline.saveConversationMessage(conversation, message, siteId).then((entry) => {
|
||||||
|
@ -2506,7 +2552,8 @@ export class AddonMessagesProvider {
|
||||||
* @return Promise resolved if success, rejected if failure.
|
* @return Promise resolved if success, rejected if failure.
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
sendMessageToConversationOnline(conversationId: number, message: string, siteId?: string): Promise<any> {
|
sendMessageToConversationOnline(conversationId: number, message: string, siteId?: string)
|
||||||
|
: Promise<AddonMessagesSendMessagesToConversationMessage> {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
const messages = [
|
const messages = [
|
||||||
|
@ -2534,7 +2581,9 @@ export class AddonMessagesProvider {
|
||||||
* @return Promise resolved if success, rejected if failure.
|
* @return Promise resolved if success, rejected if failure.
|
||||||
* @since 3.6
|
* @since 3.6
|
||||||
*/
|
*/
|
||||||
sendMessagesToConversationOnline(conversationId: number, messages: any, siteId?: string): Promise<any> {
|
sendMessagesToConversationOnline(conversationId: number, messages: any[], siteId?: string)
|
||||||
|
: Promise<AddonMessagesSendMessagesToConversationMessage[]> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
conversationid: conversationId,
|
conversationid: conversationId,
|
||||||
|
@ -2603,10 +2652,10 @@ export class AddonMessagesProvider {
|
||||||
* @param conversations Array of conversations.
|
* @param conversations Array of conversations.
|
||||||
* @return Conversations sorted with most recent last.
|
* @return Conversations sorted with most recent last.
|
||||||
*/
|
*/
|
||||||
sortConversations(conversations: any[]): any[] {
|
sortConversations(conversations: AddonMessagesConversationFormatted[]): AddonMessagesConversationFormatted[] {
|
||||||
return conversations.sort((a, b) => {
|
return conversations.sort((a, b) => {
|
||||||
const timeA = parseInt(a.lastmessagedate, 10),
|
const timeA = Number(a.lastmessagedate),
|
||||||
timeB = parseInt(b.lastmessagedate, 10);
|
timeB = Number(b.lastmessagedate);
|
||||||
|
|
||||||
if (timeA == timeB && a.id) {
|
if (timeA == timeB && a.id) {
|
||||||
// Same time, sort by ID.
|
// Same time, sort by ID.
|
||||||
|
@ -2651,7 +2700,9 @@ export class AddonMessagesProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected storeLastReceivedMessageIfNeeded(convIdOrUserIdFrom: number, message: any, siteId?: string): Promise<any> {
|
protected storeLastReceivedMessageIfNeeded(convIdOrUserIdFrom: number,
|
||||||
|
message: AddonMessagesGetMessagesMessage | AddonMessagesConversationMessage, siteId?: string): Promise<any> {
|
||||||
|
|
||||||
const component = AddonMessagesProvider.PUSH_SIMULATION_COMPONENT;
|
const component = AddonMessagesProvider.PUSH_SIMULATION_COMPONENT;
|
||||||
|
|
||||||
// Get the last received message.
|
// Get the last received message.
|
||||||
|
@ -2675,7 +2726,7 @@ export class AddonMessagesProvider {
|
||||||
*
|
*
|
||||||
* @param contactTypes List of contacts grouped in types.
|
* @param contactTypes List of contacts grouped in types.
|
||||||
*/
|
*/
|
||||||
protected storeUsersFromAllContacts(contactTypes: any): void {
|
protected storeUsersFromAllContacts(contactTypes: AddonMessagesGetContactsResult): void {
|
||||||
for (const x in contactTypes) {
|
for (const x in contactTypes) {
|
||||||
this.userProvider.storeUsers(contactTypes[x]);
|
this.userProvider.storeUsers(contactTypes[x]);
|
||||||
}
|
}
|
||||||
|
@ -2735,3 +2786,377 @@ export class AddonMessagesProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversation.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesConversation = {
|
||||||
|
id: number; // The conversation id.
|
||||||
|
name: string; // The conversation name, if set.
|
||||||
|
subname: string; // A subtitle for the conversation name, if set.
|
||||||
|
imageurl: string; // A link to the conversation picture, if set.
|
||||||
|
type: number; // The type of the conversation (1=individual,2=group,3=self).
|
||||||
|
membercount: number; // Total number of conversation members.
|
||||||
|
ismuted: boolean; // If the user muted this conversation.
|
||||||
|
isfavourite: boolean; // If the user marked this conversation as a favourite.
|
||||||
|
isread: boolean; // If the user has read all messages in the conversation.
|
||||||
|
unreadcount: number; // The number of unread messages in this conversation.
|
||||||
|
members: AddonMessagesConversationMember[];
|
||||||
|
messages: AddonMessagesConversationMessage[];
|
||||||
|
candeletemessagesforallusers: boolean; // @since 3.7. If the user can delete messages in the conversation for all users.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversation with some calculated data.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesConversationFormatted = AddonMessagesConversation & {
|
||||||
|
lastmessage?: string; // Calculated in the app. Last message.
|
||||||
|
lastmessagedate?: number; // Calculated in the app. Date the last message was sent.
|
||||||
|
sentfromcurrentuser?: boolean; // Calculated in the app. Whether last message was sent by the current user.
|
||||||
|
name?: string; // Calculated in the app. If private conversation, name of the other user.
|
||||||
|
userid?: number; // Calculated in the app. URL. If private conversation, ID of the other user.
|
||||||
|
showonlinestatus?: boolean; // Calculated in the app. If private conversation, whether to show online status of the other user.
|
||||||
|
isonline?: boolean; // Calculated in the app. If private conversation, whether the other user is online.
|
||||||
|
isblocked?: boolean; // Calculated in the app. If private conversation, whether the other user is blocked.
|
||||||
|
otherUser?: AddonMessagesConversationMember; // Calculated in the app. Other user in the conversation.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversation member.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesConversationMember = {
|
||||||
|
id: number; // The user id.
|
||||||
|
fullname: string; // The user's name.
|
||||||
|
profileurl: string; // The link to the user's profile page.
|
||||||
|
profileimageurl: string; // User picture URL.
|
||||||
|
profileimageurlsmall: string; // Small user picture URL.
|
||||||
|
isonline: boolean; // The user's online status.
|
||||||
|
showonlinestatus: boolean; // Show the user's online status?.
|
||||||
|
isblocked: boolean; // If the user has been blocked.
|
||||||
|
iscontact: boolean; // Is the user a contact?.
|
||||||
|
isdeleted: boolean; // Is the user deleted?.
|
||||||
|
canmessageevenifblocked: boolean; // If the user can still message even if they get blocked.
|
||||||
|
canmessage: boolean; // If the user can be messaged.
|
||||||
|
requirescontact: boolean; // If the user requires to be contacts.
|
||||||
|
contactrequests?: { // The contact requests.
|
||||||
|
id: number; // The id of the contact request.
|
||||||
|
userid: number; // The id of the user who created the contact request.
|
||||||
|
requesteduserid: number; // The id of the user confirming the request.
|
||||||
|
timecreated: number; // The timecreated timestamp for the contact request.
|
||||||
|
}[];
|
||||||
|
conversations?: { // Conversations between users.
|
||||||
|
id: number; // Conversations id.
|
||||||
|
type: number; // Conversation type: private or public.
|
||||||
|
name: string; // Multilang compatible conversation name2.
|
||||||
|
timecreated: number; // The timecreated timestamp for the conversation.
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conversation message.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesConversationMessage = {
|
||||||
|
id: number; // The id of the message.
|
||||||
|
useridfrom: number; // The id of the user who sent the message.
|
||||||
|
text: string; // The text of the message.
|
||||||
|
timecreated: number; // The timecreated timestamp for the message.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message preferences.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesMessagePreferences = {
|
||||||
|
userid: number; // User id.
|
||||||
|
disableall: number; // Whether all the preferences are disabled.
|
||||||
|
processors: { // Config form values.
|
||||||
|
displayname: string; // Display name.
|
||||||
|
name: string; // Processor name.
|
||||||
|
hassettings: boolean; // Whether has settings.
|
||||||
|
contextid: number; // Context id.
|
||||||
|
userconfigured: number; // Whether is configured by the user.
|
||||||
|
}[];
|
||||||
|
components: { // Available components.
|
||||||
|
displayname: string; // Display name.
|
||||||
|
notifications: AddonMessagesMessagePreferencesNotification[]; // List of notificaitons for the component.
|
||||||
|
}[];
|
||||||
|
} & AddonMessagesMessagePreferencesCalculatedData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification processor in message preferences.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesMessagePreferencesNotification = {
|
||||||
|
displayname: string; // Display name.
|
||||||
|
preferencekey: string; // Preference key.
|
||||||
|
processors: AddonMessagesMessagePreferencesNotificationProcessor[]; // Processors values for this notification.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification processor in message preferences.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesMessagePreferencesNotificationProcessor = {
|
||||||
|
displayname: string; // Display name.
|
||||||
|
name: string; // Processor name.
|
||||||
|
locked: boolean; // Is locked by admin?.
|
||||||
|
lockedmessage?: string; // Text to display if locked.
|
||||||
|
userconfigured: number; // Is configured?.
|
||||||
|
loggedin: {
|
||||||
|
name: string; // Name.
|
||||||
|
displayname: string; // Display name.
|
||||||
|
checked: boolean; // Is checked?.
|
||||||
|
};
|
||||||
|
loggedoff: {
|
||||||
|
name: string; // Name.
|
||||||
|
displayname: string; // Display name.
|
||||||
|
checked: boolean; // Is checked?.
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message discussion (before 3.6).
|
||||||
|
*/
|
||||||
|
export type AddonMessagesDiscussion = {
|
||||||
|
fullname: string; // Full name of the other user in the discussion.
|
||||||
|
profileimageurl: string; // Profile image of the other user in the discussion.
|
||||||
|
message?: { // Last message.
|
||||||
|
id: number; // Message ID.
|
||||||
|
user: number; // User ID that sent the message.
|
||||||
|
message: string; // Text of the message.
|
||||||
|
timecreated: number; // Time the message was sent.
|
||||||
|
pending?: boolean; // Whether the message is pending to be sent.
|
||||||
|
};
|
||||||
|
unread?: boolean; // Whether the discussion has unread messages.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contact for message area.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesMessageAreaContact = {
|
||||||
|
userid: number; // The user's id.
|
||||||
|
fullname: string; // The user's name.
|
||||||
|
profileimageurl: string; // User picture URL.
|
||||||
|
profileimageurlsmall: string; // Small user picture URL.
|
||||||
|
ismessaging: boolean; // If we are messaging the user.
|
||||||
|
sentfromcurrentuser: boolean; // Was the last message sent from the current user?.
|
||||||
|
lastmessage: string; // The user's last message.
|
||||||
|
lastmessagedate: number; // Timestamp for last message.
|
||||||
|
messageid: number; // The unique search message id.
|
||||||
|
showonlinestatus: boolean; // Show the user's online status?.
|
||||||
|
isonline: boolean; // The user's online status.
|
||||||
|
isread: boolean; // If the user has read the message.
|
||||||
|
isblocked: boolean; // If the user has been blocked.
|
||||||
|
unreadcount: number; // The number of unread messages in this conversation.
|
||||||
|
conversationid: number; // The id of the conversation.
|
||||||
|
} & AddonMessagesMessageAreaContactCalculatedData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_blocked_users.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetBlockedUsersResult = {
|
||||||
|
users: AddonMessagesBlockedUser[]; // List of blocked users.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User data returned by core_message_get_blocked_users.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesBlockedUser = {
|
||||||
|
id: number; // User ID.
|
||||||
|
fullname: string; // User full name.
|
||||||
|
profileimageurl?: string; // User picture URL.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_contacts.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetContactsResult = {
|
||||||
|
online: AddonMessagesGetContactsContact[]; // List of online contacts.
|
||||||
|
offline: AddonMessagesGetContactsContact[]; // List of offline contacts.
|
||||||
|
strangers: AddonMessagesGetContactsContact[]; // List of users that are not in the user's contact list but have sent a message.
|
||||||
|
} & AddonMessagesGetContactsCalculatedData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User data returned by core_message_get_contacts.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetContactsContact = {
|
||||||
|
id: number; // User ID.
|
||||||
|
fullname: string; // User full name.
|
||||||
|
profileimageurl?: string; // User picture URL.
|
||||||
|
profileimageurlsmall?: string; // Small user picture URL.
|
||||||
|
unread: number; // Unread message count.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User data returned by core_message_search_contacts.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesSearchContactsContact = {
|
||||||
|
id: number; // User ID.
|
||||||
|
fullname: string; // User full name.
|
||||||
|
profileimageurl?: string; // User picture URL.
|
||||||
|
profileimageurlsmall?: string; // Small user picture URL.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_conversation_messages.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetConversationMessagesResult = {
|
||||||
|
id: number; // The conversation id.
|
||||||
|
members: AddonMessagesConversationMember[];
|
||||||
|
messages: AddonMessagesConversationMessage[];
|
||||||
|
} & AddonMessagesGetConversationMessagesCalculatedData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_conversations.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetConversationsResult = {
|
||||||
|
conversations: AddonMessagesConversation[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_conversation_counts.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetConversationCountsResult = {
|
||||||
|
favourites: number; // Total number of favourite conversations.
|
||||||
|
types: {
|
||||||
|
1: number; // Total number of individual conversations.
|
||||||
|
2: number; // Total number of group conversations.
|
||||||
|
3: number; // Total number of self conversations.
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_unread_conversation_counts.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetUnreadConversationCountsResult = {
|
||||||
|
favourites: number; // Total number of unread favourite conversations.
|
||||||
|
types: {
|
||||||
|
1: number; // Total number of unread individual conversations.
|
||||||
|
2: number; // Total number of unread group conversations.
|
||||||
|
3: number; // Total number of unread self conversations.
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_user_message_preferences.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetUserMessagePreferencesResult = {
|
||||||
|
preferences: AddonMessagesMessagePreferences;
|
||||||
|
blocknoncontacts: number; // Privacy messaging setting to define who can message you.
|
||||||
|
entertosend: boolean; // User preference for using enter to send messages.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_messages.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetMessagesResult = {
|
||||||
|
messages: AddonMessagesGetMessagesMessage[];
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message data returned by core_message_get_messages.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetMessagesMessage = {
|
||||||
|
id: number; // Message id.
|
||||||
|
useridfrom: number; // User from id.
|
||||||
|
useridto: number; // User to id.
|
||||||
|
subject: string; // The message subject.
|
||||||
|
text: string; // The message text formated.
|
||||||
|
fullmessage: string; // The message.
|
||||||
|
fullmessageformat: number; // Fullmessage format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
fullmessagehtml: string; // The message in html.
|
||||||
|
smallmessage: string; // The shorten message.
|
||||||
|
notification: number; // Is a notification?.
|
||||||
|
contexturl: string; // Context URL.
|
||||||
|
contexturlname: string; // Context URL link name.
|
||||||
|
timecreated: number; // Time created.
|
||||||
|
timeread: number; // Time read.
|
||||||
|
usertofullname: string; // User to full name.
|
||||||
|
userfromfullname: string; // User from full name.
|
||||||
|
component?: string; // The component that generated the notification.
|
||||||
|
eventtype?: string; // The type of notification.
|
||||||
|
customdata?: string; // Custom data to be passed to the message processor.
|
||||||
|
} & AddonMessagesGetMessagesMessageCalculatedData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_data_for_messagearea_search_messages.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesDataForMessageAreaSearchMessagesResult = {
|
||||||
|
contacts: AddonMessagesMessageAreaContact[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_message_search_users.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesSearchUsersResult = {
|
||||||
|
contacts: AddonMessagesConversationMember[];
|
||||||
|
noncontacts: AddonMessagesConversationMember[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_mark_message_read.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesMarkMessageReadResult = {
|
||||||
|
messageid: number; // The id of the message in the messages table.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_send_instant_messages.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesSendInstantMessagesMessage = {
|
||||||
|
msgid: number; // Test this to know if it succeeds: id of the created message if it succeeded, -1 when failed.
|
||||||
|
clientmsgid?: string; // Your own id for the message.
|
||||||
|
errormessage?: string; // Error message - if it failed.
|
||||||
|
text?: string; // The text of the message.
|
||||||
|
timecreated?: number; // The timecreated timestamp for the message.
|
||||||
|
conversationid?: number; // The conversation id for this message.
|
||||||
|
useridfrom?: number; // The user id who sent the message.
|
||||||
|
candeletemessagesforallusers: boolean; // If the user can delete messages in the conversation for all users.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_send_messages_to_conversation.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesSendMessagesToConversationMessage = {
|
||||||
|
id: number; // The id of the message.
|
||||||
|
useridfrom: number; // The id of the user who sent the message.
|
||||||
|
text: string; // The text of the message.
|
||||||
|
timecreated: number; // The timecreated timestamp for the message.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated data for core_message_get_contacts.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetContactsCalculatedData = {
|
||||||
|
blocked?: AddonMessagesBlockedUser[]; // Calculated in the app. List of blocked users.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated data for core_message_get_conversation_messages.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetConversationMessagesCalculatedData = {
|
||||||
|
canLoadMore?: boolean; // Calculated in the app. Whether more messages can be loaded.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated data for message preferences.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesMessagePreferencesCalculatedData = {
|
||||||
|
blocknoncontacts?: number; // Calculated in the app. Based on the result of core_message_get_user_message_preferences.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated data for messages returned by core_message_get_messages.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesGetMessagesMessageCalculatedData = {
|
||||||
|
pending?: boolean; // Calculated in the app. Whether the message is pending to be sent.
|
||||||
|
read?: number; // Calculated in the app. Whether the message has been read.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated data for contact for message area.
|
||||||
|
*/
|
||||||
|
export type AddonMessagesMessageAreaContactCalculatedData = {
|
||||||
|
id?: number; // Calculated in the app. User ID.
|
||||||
|
};
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { AddonMessagesOfflineProvider } from './messages-offline';
|
import { AddonMessagesOfflineProvider } from './messages-offline';
|
||||||
import { AddonMessagesProvider } from './messages';
|
import { AddonMessagesProvider, AddonMessagesConversationFormatted } from './messages';
|
||||||
import { CoreUserProvider } from '@core/user/providers/user';
|
import { CoreUserProvider } from '@core/user/providers/user';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
|
@ -258,7 +258,7 @@ export class AddonMessagesSyncProvider extends CoreSyncBaseProvider {
|
||||||
// Get conversation name and add errors to warnings array.
|
// Get conversation name and add errors to warnings array.
|
||||||
return this.messagesProvider.getConversation(conversationId, false, false).catch(() => {
|
return this.messagesProvider.getConversation(conversationId, false, false).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
return {};
|
return <AddonMessagesConversationFormatted> {};
|
||||||
}).then((conversation) => {
|
}).then((conversation) => {
|
||||||
errors.forEach((error) => {
|
errors.forEach((error) => {
|
||||||
warnings.push(this.translate.instant('addon.messages.warningconversationmessagenotsent', {
|
warnings.push(this.translate.instant('addon.messages.warningconversationmessagenotsent', {
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
import { CoreUserProvider } from '@core/user/providers/user';
|
import { CoreUserProvider } from '@core/user/providers/user';
|
||||||
import { coreSlideInOut } from '@classes/animations';
|
import { coreSlideInOut } from '@classes/animations';
|
||||||
import { AddonNotesProvider } from '../../providers/notes';
|
import { AddonNotesProvider, AddonNotesNoteFormatted } from '../../providers/notes';
|
||||||
import { AddonNotesOfflineProvider } from '../../providers/notes-offline';
|
import { AddonNotesOfflineProvider } from '../../providers/notes-offline';
|
||||||
import { AddonNotesSyncProvider } from '../../providers/notes-sync';
|
import { AddonNotesSyncProvider } from '../../providers/notes-sync';
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ export class AddonNotesListComponent implements OnInit, OnDestroy {
|
||||||
type = 'course';
|
type = 'course';
|
||||||
refreshIcon = 'spinner';
|
refreshIcon = 'spinner';
|
||||||
syncIcon = 'spinner';
|
syncIcon = 'spinner';
|
||||||
notes: any[];
|
notes: AddonNotesNoteFormatted[];
|
||||||
hasOffline = false;
|
hasOffline = false;
|
||||||
notesLoaded = false;
|
notesLoaded = false;
|
||||||
user: any;
|
user: any;
|
||||||
|
@ -101,21 +101,21 @@ export class AddonNotesListComponent implements OnInit, OnDestroy {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
return this.notesProvider.getNotes(this.courseId, this.userId).then((notes) => {
|
return this.notesProvider.getNotes(this.courseId, this.userId).then((notes) => {
|
||||||
notes = notes[this.type + 'notes'] || [];
|
const notesList: AddonNotesNoteFormatted[] = notes[this.type + 'notes'] || [];
|
||||||
|
|
||||||
return this.notesProvider.setOfflineDeletedNotes(notes, this.courseId).then((notes) => {
|
return this.notesProvider.setOfflineDeletedNotes(notesList, this.courseId).then((notesList) => {
|
||||||
|
|
||||||
this.hasOffline = notes.some((note) => note.offline || note.deleted);
|
this.hasOffline = notesList.some((note) => note.offline || note.deleted);
|
||||||
|
|
||||||
if (this.userId) {
|
if (this.userId) {
|
||||||
this.notes = notes;
|
this.notes = notesList;
|
||||||
|
|
||||||
// Get the user profile to retrieve the user image.
|
// Get the user profile to retrieve the user image.
|
||||||
return this.userProvider.getProfile(this.userId, this.courseId, true).then((user) => {
|
return this.userProvider.getProfile(this.userId, this.courseId, true).then((user) => {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return this.notesProvider.getNotesUserData(notes, this.courseId).then((notes) => {
|
return this.notesProvider.getNotesUserData(notesList, this.courseId).then((notes) => {
|
||||||
this.notes = notes;
|
this.notes = notes;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ export class AddonNotesListComponent implements OnInit, OnDestroy {
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
let canDelete = this.notes && this.notes.length > 0;
|
let canDelete = this.notes && this.notes.length > 0;
|
||||||
if (canDelete && this.type == 'personal') {
|
if (canDelete && this.type == 'personal') {
|
||||||
canDelete = this.notes.find((note) => {
|
canDelete = !!this.notes.find((note) => {
|
||||||
return note.usermodified == this.currentUserId;
|
return note.usermodified == this.currentUserId;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,7 @@ export class AddonNotesListComponent implements OnInit, OnDestroy {
|
||||||
addNote(e: Event): void {
|
addNote(e: Event): void {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
const modal = this.modalCtrl.create('AddonNotesAddPage', { userId: this.userId, courseId: this.courseId, type: this.type });
|
const modal = this.modalCtrl.create('AddonNotesAddPage', { userId: this.userId, courseId: this.courseId, type: this.type });
|
||||||
modal.onDidDismiss((data) => {
|
modal.onDidDismiss((data) => {
|
||||||
if (data && data.sent && data.type) {
|
if (data && data.sent && data.type) {
|
||||||
|
@ -192,6 +193,7 @@ export class AddonNotesListComponent implements OnInit, OnDestroy {
|
||||||
this.typeChanged();
|
this.typeChanged();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
modal.present();
|
modal.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +203,7 @@ export class AddonNotesListComponent implements OnInit, OnDestroy {
|
||||||
* @param e Click event.
|
* @param e Click event.
|
||||||
* @param note Note to delete.
|
* @param note Note to delete.
|
||||||
*/
|
*/
|
||||||
deleteNote(e: Event, note: any): void {
|
deleteNote(e: Event, note: AddonNotesNoteFormatted): void {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
|
@ -226,7 +228,7 @@ export class AddonNotesListComponent implements OnInit, OnDestroy {
|
||||||
* @param e Click event.
|
* @param e Click event.
|
||||||
* @param note Note to delete.
|
* @param note Note to delete.
|
||||||
*/
|
*/
|
||||||
undoDeleteNote(e: Event, note: any): void {
|
undoDeleteNote(e: Event, note: AddonNotesNoteFormatted): void {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreUserProvider } from '@core/user/providers/user';
|
import { CoreUserProvider } from '@core/user/providers/user';
|
||||||
import { AddonNotesOfflineProvider } from './notes-offline';
|
import { AddonNotesOfflineProvider } from './notes-offline';
|
||||||
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
||||||
|
import { CoreWSExternalWarning } from '@providers/ws';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle notes.
|
* Service to handle notes.
|
||||||
|
@ -119,9 +120,9 @@ export class AddonNotesProvider {
|
||||||
* @return Promise resolved when added, rejected otherwise. Promise resolved doesn't mean that notes
|
* @return Promise resolved when added, rejected otherwise. Promise resolved doesn't mean that notes
|
||||||
* have been added, the resolve param can contain errors for notes not sent.
|
* have been added, the resolve param can contain errors for notes not sent.
|
||||||
*/
|
*/
|
||||||
addNotesOnline(notes: any[], siteId?: string): Promise<any> {
|
addNotesOnline(notes: any[], siteId?: string): Promise<AddonNotesCreateNotesNote[]> {
|
||||||
if (!notes || !notes.length) {
|
if (!notes || !notes.length) {
|
||||||
return Promise.resolve();
|
return Promise.resolve([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
@ -142,7 +143,7 @@ export class AddonNotesProvider {
|
||||||
* @return Promise resolved when deleted, rejected otherwise. Promise resolved doesn't mean that notes
|
* @return Promise resolved when deleted, rejected otherwise. Promise resolved doesn't mean that notes
|
||||||
* have been deleted, the resolve param can contain errors for notes not deleted.
|
* have been deleted, the resolve param can contain errors for notes not deleted.
|
||||||
*/
|
*/
|
||||||
deleteNote(note: any, courseId: number, siteId?: string): Promise<void> {
|
deleteNote(note: AddonNotesNoteFormatted, courseId: number, siteId?: string): Promise<void> {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
if (note.offline) {
|
if (note.offline) {
|
||||||
|
@ -190,7 +191,7 @@ export class AddonNotesProvider {
|
||||||
notes: noteIds
|
notes: noteIds
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.write('core_notes_delete_notes', data).then((response) => {
|
return site.write('core_notes_delete_notes', data).then((response: CoreWSExternalWarning[]) => {
|
||||||
// A note was deleted, invalidate the course notes.
|
// A note was deleted, invalidate the course notes.
|
||||||
return this.invalidateNotes(courseId, undefined, siteId).catch(() => {
|
return this.invalidateNotes(courseId, undefined, siteId).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
|
@ -288,7 +289,9 @@ export class AddonNotesProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise to be resolved when the notes are retrieved.
|
* @return Promise to be resolved when the notes are retrieved.
|
||||||
*/
|
*/
|
||||||
getNotes(courseId: number, userId?: number, ignoreCache?: boolean, onlyOnline?: boolean, siteId?: string): Promise<any> {
|
getNotes(courseId: number, userId?: number, ignoreCache?: boolean, onlyOnline?: boolean, siteId?: string)
|
||||||
|
: Promise<AddonNotesGetCourseNotesResult> {
|
||||||
|
|
||||||
this.logger.debug('Get notes for course ' + courseId);
|
this.logger.debug('Get notes for course ' + courseId);
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
@ -310,7 +313,7 @@ export class AddonNotesProvider {
|
||||||
preSets.emergencyCache = false;
|
preSets.emergencyCache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('core_notes_get_course_notes', data, preSets).then((notes) => {
|
return site.read('core_notes_get_course_notes', data, preSets).then((notes: AddonNotesGetCourseNotesResult) => {
|
||||||
if (onlyOnline) {
|
if (onlyOnline) {
|
||||||
return notes;
|
return notes;
|
||||||
}
|
}
|
||||||
|
@ -339,9 +342,11 @@ export class AddonNotesProvider {
|
||||||
* @param notes Array of notes.
|
* @param notes Array of notes.
|
||||||
* @param courseId ID of the course the notes belong to.
|
* @param courseId ID of the course the notes belong to.
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return [description]
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
setOfflineDeletedNotes(notes: any[], courseId: number, siteId?: string): Promise<any> {
|
setOfflineDeletedNotes(notes: AddonNotesNoteFormatted[], courseId: number, siteId?: string)
|
||||||
|
: Promise<AddonNotesNoteFormatted[]> {
|
||||||
|
|
||||||
return this.notesOffline.getCourseDeletedNotes(courseId, siteId).then((deletedNotes) => {
|
return this.notesOffline.getCourseDeletedNotes(courseId, siteId).then((deletedNotes) => {
|
||||||
notes.forEach((note) => {
|
notes.forEach((note) => {
|
||||||
note.deleted = deletedNotes.some((n) => n.noteid == note.id);
|
note.deleted = deletedNotes.some((n) => n.noteid == note.id);
|
||||||
|
@ -358,7 +363,7 @@ export class AddonNotesProvider {
|
||||||
* @param courseId ID of the course the notes belong to.
|
* @param courseId ID of the course the notes belong to.
|
||||||
* @return Promise always resolved. Resolve param is the formatted notes.
|
* @return Promise always resolved. Resolve param is the formatted notes.
|
||||||
*/
|
*/
|
||||||
getNotesUserData(notes: any[], courseId: number): Promise<any> {
|
getNotesUserData(notes: AddonNotesNoteFormatted[], courseId: number): Promise<AddonNotesNoteFormatted[]> {
|
||||||
const promises = notes.map((note) => {
|
const promises = notes.map((note) => {
|
||||||
// Get the user profile to retrieve the user image.
|
// Get the user profile to retrieve the user image.
|
||||||
return this.userProvider.getProfile(note.userid, note.courseid, true).then((user) => {
|
return this.userProvider.getProfile(note.userid, note.courseid, true).then((user) => {
|
||||||
|
@ -400,7 +405,7 @@ export class AddonNotesProvider {
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved when the WS call is successful.
|
* @return Promise resolved when the WS call is successful.
|
||||||
*/
|
*/
|
||||||
logView(courseId: number, userId?: number, siteId?: string): Promise<any> {
|
logView(courseId: number, userId?: number, siteId?: string): Promise<AddonNotesViewNotesResult> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
courseid: courseId,
|
courseid: courseId,
|
||||||
|
@ -413,3 +418,57 @@ export class AddonNotesProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note data returned by core_notes_get_course_notes.
|
||||||
|
*/
|
||||||
|
export type AddonNotesNote = {
|
||||||
|
id: number; // Id of this note.
|
||||||
|
courseid: number; // Id of the course.
|
||||||
|
userid: number; // User id.
|
||||||
|
content: string; // The content text formated.
|
||||||
|
format: number; // Content format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
created: number; // Time created (timestamp).
|
||||||
|
lastmodified: number; // Time of last modification (timestamp).
|
||||||
|
usermodified: number; // User id of the creator of this note.
|
||||||
|
publishstate: string; // State of the note (i.e. draft, public, site).
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_notes_get_course_notes.
|
||||||
|
*/
|
||||||
|
export type AddonNotesGetCourseNotesResult = {
|
||||||
|
sitenotes?: AddonNotesNote[]; // Site notes.
|
||||||
|
coursenotes?: AddonNotesNote[]; // Couse notes.
|
||||||
|
personalnotes?: AddonNotesNote[]; // Personal notes.
|
||||||
|
canmanagesystemnotes?: boolean; // Whether the user can manage notes at system level.
|
||||||
|
canmanagecoursenotes?: boolean; // Whether the user can manage notes at the given course.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note returned by WS core_notes_create_notes.
|
||||||
|
*/
|
||||||
|
export type AddonNotesCreateNotesNote = {
|
||||||
|
clientnoteid?: string; // Your own id for the note.
|
||||||
|
noteid: number; // ID of the created note when successful, -1 when failed.
|
||||||
|
errormessage?: string; // Error message - if failed.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_notes_view_notes.
|
||||||
|
*/
|
||||||
|
export type AddonNotesViewNotesResult = {
|
||||||
|
status: boolean; // Status: true if success.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notes with some calculated data.
|
||||||
|
*/
|
||||||
|
export type AddonNotesNoteFormatted = AddonNotesNote & {
|
||||||
|
offline?: boolean; // Calculated in the app. Whether it's an offline note.
|
||||||
|
deleted?: boolean; // Calculated in the app. Whether the note was deleted in offline.
|
||||||
|
userfullname?: string; // Calculated in the app. Full name of the user the note refers to.
|
||||||
|
userprofileimageurl?: string; // Calculated in the app. Avatar url of the user the note refers to.
|
||||||
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
import { CoreEventsProvider, CoreEventObserver } from '@providers/events';
|
import { CoreEventsProvider, CoreEventObserver } from '@providers/events';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { AddonNotificationsProvider } from '../../providers/notifications';
|
import { AddonNotificationsProvider, AddonNotificationsAnyNotification } from '../../providers/notifications';
|
||||||
import { AddonNotificationsHelperProvider } from '../../providers/helper';
|
import { AddonNotificationsHelperProvider } from '../../providers/helper';
|
||||||
import { CorePushNotificationsDelegate } from '@core/pushnotifications/providers/delegate';
|
import { CorePushNotificationsDelegate } from '@core/pushnotifications/providers/delegate';
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ import { CorePushNotificationsDelegate } from '@core/pushnotifications/providers
|
||||||
})
|
})
|
||||||
export class AddonNotificationsListPage {
|
export class AddonNotificationsListPage {
|
||||||
|
|
||||||
notifications = [];
|
notifications: AddonNotificationsAnyNotification[] = [];
|
||||||
notificationsLoaded = false;
|
notificationsLoaded = false;
|
||||||
canLoadMore = false;
|
canLoadMore = false;
|
||||||
loadMoreError = false;
|
loadMoreError = false;
|
||||||
|
@ -130,11 +130,12 @@ export class AddonNotificationsListPage {
|
||||||
*
|
*
|
||||||
* @param notifications Array of notification objects.
|
* @param notifications Array of notification objects.
|
||||||
*/
|
*/
|
||||||
protected markNotificationsAsRead(notifications: any[]): void {
|
protected markNotificationsAsRead(notifications: AddonNotificationsAnyNotification[]): void {
|
||||||
|
|
||||||
let promise;
|
let promise;
|
||||||
|
|
||||||
if (notifications.length > 0) {
|
if (notifications.length > 0) {
|
||||||
const promises = notifications.map((notification) => {
|
const promises: Promise<any>[] = notifications.map((notification) => {
|
||||||
if (notification.read) {
|
if (notification.read) {
|
||||||
// Already read, don't mark it.
|
// Already read, don't mark it.
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
@ -202,7 +203,7 @@ export class AddonNotificationsListPage {
|
||||||
*
|
*
|
||||||
* @param notification The notification object.
|
* @param notification The notification object.
|
||||||
*/
|
*/
|
||||||
protected formatText(notification: any): void {
|
protected formatText(notification: AddonNotificationsAnyNotification): void {
|
||||||
const text = notification.mobiletext.replace(/-{4,}/ig, '');
|
const text = notification.mobiletext.replace(/-{4,}/ig, '');
|
||||||
notification.mobiletext = this.textUtils.replaceNewLines(text, '<br>');
|
notification.mobiletext = this.textUtils.replaceNewLines(text, '<br>');
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,11 @@
|
||||||
|
|
||||||
import { Component, OnDestroy, Optional } from '@angular/core';
|
import { Component, OnDestroy, Optional } from '@angular/core';
|
||||||
import { IonicPage, NavController } from 'ionic-angular';
|
import { IonicPage, NavController } from 'ionic-angular';
|
||||||
import { AddonNotificationsProvider } from '../../providers/notifications';
|
import {
|
||||||
|
AddonNotificationsProvider, AddonNotificationsNotificationPreferences, AddonNotificationsNotificationPreferencesProcessor,
|
||||||
|
AddonNotificationsNotificationPreferencesComponent, AddonNotificationsNotificationPreferencesNotification,
|
||||||
|
AddonNotificationsNotificationPreferencesNotificationProcessorState
|
||||||
|
} from '../../providers/notifications';
|
||||||
import { CoreUserProvider } from '@core/user/providers/user';
|
import { CoreUserProvider } from '@core/user/providers/user';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreSettingsHelper } from '@core/settings/providers/helper';
|
import { CoreSettingsHelper } from '@core/settings/providers/helper';
|
||||||
|
@ -38,10 +42,10 @@ import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||||
export class AddonNotificationsSettingsPage implements OnDestroy {
|
export class AddonNotificationsSettingsPage implements OnDestroy {
|
||||||
protected updateTimeout: any;
|
protected updateTimeout: any;
|
||||||
|
|
||||||
components: any[];
|
components: AddonNotificationsNotificationPreferencesComponent[];
|
||||||
preferences: any;
|
preferences: AddonNotificationsNotificationPreferences;
|
||||||
preferencesLoaded: boolean;
|
preferencesLoaded: boolean;
|
||||||
currentProcessor: any;
|
currentProcessor: AddonNotificationsNotificationPreferencesProcessorFormatted;
|
||||||
notifPrefsEnabled: boolean;
|
notifPrefsEnabled: boolean;
|
||||||
canChangeSound: boolean;
|
canChangeSound: boolean;
|
||||||
notificationSound: boolean;
|
notificationSound: boolean;
|
||||||
|
@ -99,7 +103,7 @@ export class AddonNotificationsSettingsPage implements OnDestroy {
|
||||||
// Get display data of message output handlers (thery are displayed in the context menu),
|
// Get display data of message output handlers (thery are displayed in the context menu),
|
||||||
this.processorHandlers = [];
|
this.processorHandlers = [];
|
||||||
if (preferences.processors) {
|
if (preferences.processors) {
|
||||||
preferences.processors.forEach((processor) => {
|
preferences.processors.forEach((processor: AddonNotificationsNotificationPreferencesProcessorFormatted) => {
|
||||||
processor.supported = this.messageOutputDelegate.hasHandler(processor.name, true);
|
processor.supported = this.messageOutputDelegate.hasHandler(processor.name, true);
|
||||||
if (processor.hassettings && processor.supported) {
|
if (processor.hassettings && processor.supported) {
|
||||||
this.processorHandlers.push(this.messageOutputDelegate.getDisplayData(processor));
|
this.processorHandlers.push(this.messageOutputDelegate.getDisplayData(processor));
|
||||||
|
@ -118,7 +122,7 @@ export class AddonNotificationsSettingsPage implements OnDestroy {
|
||||||
*
|
*
|
||||||
* @param processor Processor object.
|
* @param processor Processor object.
|
||||||
*/
|
*/
|
||||||
protected loadProcessor(processor: any): void {
|
protected loadProcessor(processor: AddonNotificationsNotificationPreferencesProcessorFormatted): void {
|
||||||
if (!processor) {
|
if (!processor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -191,8 +195,9 @@ export class AddonNotificationsSettingsPage implements OnDestroy {
|
||||||
* @param notification Notification object.
|
* @param notification Notification object.
|
||||||
* @param state State name, ['loggedin', 'loggedoff'].
|
* @param state State name, ['loggedin', 'loggedoff'].
|
||||||
*/
|
*/
|
||||||
changePreference(notification: any, state: string): void {
|
changePreference(notification: AddonNotificationsNotificationPreferencesNotificationFormatted, state: string): void {
|
||||||
const processorState = notification.currentProcessor[state];
|
const processorState: AddonNotificationsNotificationPreferencesNotificationProcessorStateFormatted =
|
||||||
|
notification.currentProcessor[state];
|
||||||
const preferenceName = notification.preferencekey + '_' + processorState.name;
|
const preferenceName = notification.preferencekey + '_' + processorState.name;
|
||||||
let value;
|
let value;
|
||||||
|
|
||||||
|
@ -211,6 +216,7 @@ export class AddonNotificationsSettingsPage implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
processorState.updating = true;
|
processorState.updating = true;
|
||||||
|
|
||||||
this.userProvider.updateUserPreference(preferenceName, value).then(() => {
|
this.userProvider.updateUserPreference(preferenceName, value).then(() => {
|
||||||
// Update the preferences since they were modified.
|
// Update the preferences since they were modified.
|
||||||
this.updatePreferencesAfterDelay();
|
this.updatePreferencesAfterDelay();
|
||||||
|
@ -264,3 +270,25 @@ export class AddonNotificationsSettingsPage implements OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification preferences notification with some calculated data.
|
||||||
|
*/
|
||||||
|
type AddonNotificationsNotificationPreferencesNotificationFormatted = AddonNotificationsNotificationPreferencesNotification & {
|
||||||
|
currentProcessor?: AddonNotificationsNotificationPreferencesProcessorFormatted; // Calculated in the app. Current processor.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification preferences processor with some calculated data.
|
||||||
|
*/
|
||||||
|
type AddonNotificationsNotificationPreferencesProcessorFormatted = AddonNotificationsNotificationPreferencesProcessor & {
|
||||||
|
supported?: boolean; // Calculated in the app. Whether the processor is supported in the app.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State in notification processor in notification preferences component with some calculated data.
|
||||||
|
*/
|
||||||
|
type AddonNotificationsNotificationPreferencesNotificationProcessorStateFormatted =
|
||||||
|
AddonNotificationsNotificationPreferencesNotificationProcessorState & {
|
||||||
|
updating?: boolean; // Calculated in the app. Whether the state is being updated.
|
||||||
|
};
|
||||||
|
|
|
@ -14,7 +14,9 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { AddonNotificationsProvider } from './notifications';
|
import {
|
||||||
|
AddonNotificationsProvider, AddonNotificationsAnyNotification, AddonNotificationsGetMessagesMessage
|
||||||
|
} from './notifications';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service that provides some helper functions for notifications.
|
* Service that provides some helper functions for notifications.
|
||||||
|
@ -37,7 +39,7 @@ export class AddonNotificationsHelperProvider {
|
||||||
* @return Promise resolved with notifications and if can load more.
|
* @return Promise resolved with notifications and if can load more.
|
||||||
*/
|
*/
|
||||||
getNotifications(notifications: any[], limit?: number, toDisplay: boolean = true, forceCache?: boolean, ignoreCache?: boolean,
|
getNotifications(notifications: any[], limit?: number, toDisplay: boolean = true, forceCache?: boolean, ignoreCache?: boolean,
|
||||||
siteId?: string): Promise<{notifications: any[], canLoadMore: boolean}> {
|
siteId?: string): Promise<{notifications: AddonNotificationsAnyNotification[], canLoadMore: boolean}> {
|
||||||
|
|
||||||
notifications = notifications || [];
|
notifications = notifications || [];
|
||||||
limit = limit || AddonNotificationsProvider.LIST_LIMIT;
|
limit = limit || AddonNotificationsProvider.LIST_LIMIT;
|
||||||
|
@ -80,7 +82,7 @@ export class AddonNotificationsHelperProvider {
|
||||||
promise = Promise.resolve(unread);
|
promise = Promise.resolve(unread);
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise.then((notifications) => {
|
return promise.then((notifications: AddonNotificationsGetMessagesMessage[]) => {
|
||||||
return {
|
return {
|
||||||
notifications: notifications,
|
notifications: notifications,
|
||||||
canLoadMore: notifications.length >= limit
|
canLoadMore: notifications.length >= limit
|
||||||
|
|
|
@ -20,8 +20,9 @@ import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
import { CoreUserProvider } from '@core/user/providers/user';
|
import { CoreUserProvider } from '@core/user/providers/user';
|
||||||
import { CoreEmulatorHelperProvider } from '@core/emulator/providers/helper';
|
import { CoreEmulatorHelperProvider } from '@core/emulator/providers/helper';
|
||||||
import { AddonMessagesProvider } from '@addon/messages/providers/messages';
|
import { AddonMessagesProvider, AddonMessagesMarkMessageReadResult } from '@addon/messages/providers/messages';
|
||||||
import { CoreSite } from '@classes/site';
|
import { CoreSite } from '@classes/site';
|
||||||
|
import { CoreWSExternalWarning } from '@providers/ws';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle notifications.
|
* Service to handle notifications.
|
||||||
|
@ -51,14 +52,13 @@ export class AddonNotificationsProvider {
|
||||||
* @param read Whether the notifications are read or unread.
|
* @param read Whether the notifications are read or unread.
|
||||||
* @return Promise resolved with notifications.
|
* @return Promise resolved with notifications.
|
||||||
*/
|
*/
|
||||||
protected formatNotificationsData(notifications: any[], read?: boolean): Promise<any> {
|
protected formatNotificationsData(notifications: AddonNotificationsAnyNotification[], read?: boolean): Promise<any> {
|
||||||
|
|
||||||
const promises = notifications.map((notification) => {
|
const promises = notifications.map((notification) => {
|
||||||
|
|
||||||
// Set message to show.
|
// Set message to show.
|
||||||
if (notification.component && notification.component == 'mod_forum') {
|
if (notification.component && notification.component == 'mod_forum') {
|
||||||
notification.mobiletext = notification.smallmessage;
|
notification.mobiletext = notification.smallmessage;
|
||||||
} else if (notification.component && notification.component == 'moodle' && notification.name == 'insights') {
|
|
||||||
notification.mobiletext = notification.fullmessagehtml;
|
|
||||||
} else {
|
} else {
|
||||||
notification.mobiletext = notification.fullmessage;
|
notification.mobiletext = notification.fullmessage;
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ export class AddonNotificationsProvider {
|
||||||
* @param siteId Site ID. If not defined, use current site.
|
* @param siteId Site ID. If not defined, use current site.
|
||||||
* @return Promise resolved with the notification preferences.
|
* @return Promise resolved with the notification preferences.
|
||||||
*/
|
*/
|
||||||
getNotificationPreferences(siteId?: string): Promise<any> {
|
getNotificationPreferences(siteId?: string): Promise<AddonNotificationsNotificationPreferences> {
|
||||||
this.logger.debug('Get notification preferences');
|
this.logger.debug('Get notification preferences');
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
@ -126,7 +126,9 @@ export class AddonNotificationsProvider {
|
||||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||||
};
|
};
|
||||||
|
|
||||||
return site.read('core_message_get_user_notification_preferences', {}, preSets).then((data) => {
|
return site.read('core_message_get_user_notification_preferences', {}, preSets)
|
||||||
|
.then((data: AddonNotificationsGetUserNotificationPreferencesResult) => {
|
||||||
|
|
||||||
return data.preferences;
|
return data.preferences;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -154,7 +156,7 @@ export class AddonNotificationsProvider {
|
||||||
* @return Promise resolved with notifications.
|
* @return Promise resolved with notifications.
|
||||||
*/
|
*/
|
||||||
getNotifications(read: boolean, limitFrom: number, limitNumber: number = 0, toDisplay: boolean = true,
|
getNotifications(read: boolean, limitFrom: number, limitNumber: number = 0, toDisplay: boolean = true,
|
||||||
forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<any[]> {
|
forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<AddonNotificationsGetMessagesMessage[]> {
|
||||||
limitNumber = limitNumber || AddonNotificationsProvider.LIST_LIMIT;
|
limitNumber = limitNumber || AddonNotificationsProvider.LIST_LIMIT;
|
||||||
this.logger.debug('Get ' + (read ? 'read' : 'unread') + ' notifications from ' + limitFrom + '. Limit: ' + limitNumber);
|
this.logger.debug('Get ' + (read ? 'read' : 'unread') + ' notifications from ' + limitFrom + '. Limit: ' + limitNumber);
|
||||||
|
|
||||||
|
@ -176,7 +178,7 @@ export class AddonNotificationsProvider {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get unread notifications.
|
// Get unread notifications.
|
||||||
return site.read('core_message_get_messages', data, preSets).then((response) => {
|
return site.read('core_message_get_messages', data, preSets).then((response: AddonNotificationsGetMessagesResult) => {
|
||||||
if (response.messages) {
|
if (response.messages) {
|
||||||
const notifications = response.messages;
|
const notifications = response.messages;
|
||||||
|
|
||||||
|
@ -209,7 +211,7 @@ export class AddonNotificationsProvider {
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
getPopupNotifications(offset: number, limit?: number, toDisplay: boolean = true, forceCache?: boolean, ignoreCache?: boolean,
|
getPopupNotifications(offset: number, limit?: number, toDisplay: boolean = true, forceCache?: boolean, ignoreCache?: boolean,
|
||||||
siteId?: string): Promise<{notifications: any[], canLoadMore: boolean}> {
|
siteId?: string): Promise<{notifications: AddonNotificationsPopupNotificationFormatted[], canLoadMore: boolean}> {
|
||||||
|
|
||||||
limit = limit || AddonNotificationsProvider.LIST_LIMIT;
|
limit = limit || AddonNotificationsProvider.LIST_LIMIT;
|
||||||
|
|
||||||
|
@ -230,17 +232,17 @@ export class AddonNotificationsProvider {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get notifications.
|
// Get notifications.
|
||||||
return site.read('message_popup_get_popup_notifications', data, preSets).then((response) => {
|
return site.read('message_popup_get_popup_notifications', data, preSets)
|
||||||
|
.then((response: AddonNotificationsGetPopupNotificationsResult) => {
|
||||||
|
|
||||||
if (response.notifications) {
|
if (response.notifications) {
|
||||||
const result: any = {
|
const result = {
|
||||||
canLoadMore: response.notifications.length > limit
|
canLoadMore: response.notifications.length > limit,
|
||||||
},
|
notifications: response.notifications.slice(0, limit)
|
||||||
notifications = response.notifications.slice(0, limit);
|
};
|
||||||
|
|
||||||
result.notifications = notifications;
|
return this.formatNotificationsData(result.notifications).then(() => {
|
||||||
|
const first = result.notifications[0];
|
||||||
return this.formatNotificationsData(notifications).then(() => {
|
|
||||||
const first = notifications[0];
|
|
||||||
|
|
||||||
if (this.appProvider.isDesktop() && toDisplay && offset === 0 && first && !first.read) {
|
if (this.appProvider.isDesktop() && toDisplay && offset === 0 && first && !first.read) {
|
||||||
// Store the last received notification. Don't block the user for this.
|
// Store the last received notification. Don't block the user for this.
|
||||||
|
@ -269,7 +271,7 @@ export class AddonNotificationsProvider {
|
||||||
* @return Promise resolved with notifications.
|
* @return Promise resolved with notifications.
|
||||||
*/
|
*/
|
||||||
getReadNotifications(limitFrom: number, limitNumber: number, toDisplay: boolean = true,
|
getReadNotifications(limitFrom: number, limitNumber: number, toDisplay: boolean = true,
|
||||||
forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<any[]> {
|
forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<AddonNotificationsGetMessagesMessage[]> {
|
||||||
return this.getNotifications(true, limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId);
|
return this.getNotifications(true, limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +287,7 @@ export class AddonNotificationsProvider {
|
||||||
* @return Promise resolved with notifications.
|
* @return Promise resolved with notifications.
|
||||||
*/
|
*/
|
||||||
getUnreadNotifications(limitFrom: number, limitNumber: number, toDisplay: boolean = true,
|
getUnreadNotifications(limitFrom: number, limitNumber: number, toDisplay: boolean = true,
|
||||||
forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<any[]> {
|
forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<AddonNotificationsGetMessagesMessage[]> {
|
||||||
return this.getNotifications(false, limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId);
|
return this.getNotifications(false, limitFrom, limitNumber, toDisplay, forceCache, ignoreCache, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +351,7 @@ export class AddonNotificationsProvider {
|
||||||
* @return Resolved when done.
|
* @return Resolved when done.
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
markAllNotificationsAsRead(): Promise<any> {
|
markAllNotificationsAsRead(): Promise<boolean> {
|
||||||
const params = {
|
const params = {
|
||||||
useridto: this.sitesProvider.getCurrentSiteUserId()
|
useridto: this.sitesProvider.getCurrentSiteUserId()
|
||||||
};
|
};
|
||||||
|
@ -362,10 +364,12 @@ export class AddonNotificationsProvider {
|
||||||
*
|
*
|
||||||
* @param notificationId ID of notification to mark as read
|
* @param notificationId ID of notification to mark as read
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Resolved when done.
|
* @return Promise resolved when done.
|
||||||
* @since 3.5
|
* @since 3.5
|
||||||
*/
|
*/
|
||||||
markNotificationRead(notificationId: number, siteId?: string): Promise<any> {
|
markNotificationRead(notificationId: number, siteId?: string)
|
||||||
|
: Promise<AddonNotificationsMarkNotificationReadResult | AddonMessagesMarkMessageReadResult> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
|
||||||
if (site.wsAvailable('core_message_mark_notification_read')) {
|
if (site.wsAvailable('core_message_mark_notification_read')) {
|
||||||
|
@ -436,3 +440,179 @@ export class AddonNotificationsProvider {
|
||||||
return this.sitesProvider.wsAvailableInCurrentSite('core_message_get_user_notification_preferences');
|
return this.sitesProvider.wsAvailableInCurrentSite('core_message_get_user_notification_preferences');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preferences returned by core_message_get_user_notification_preferences.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsNotificationPreferences = {
|
||||||
|
userid: number; // User id.
|
||||||
|
disableall: number | boolean; // Whether all the preferences are disabled.
|
||||||
|
processors: AddonNotificationsNotificationPreferencesProcessor[]; // Config form values.
|
||||||
|
components: AddonNotificationsNotificationPreferencesComponent[]; // Available components.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processor in notification preferences.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsNotificationPreferencesProcessor = {
|
||||||
|
displayname: string; // Display name.
|
||||||
|
name: string; // Processor name.
|
||||||
|
hassettings: boolean; // Whether has settings.
|
||||||
|
contextid: number; // Context id.
|
||||||
|
userconfigured: number; // Whether is configured by the user.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component in notification preferences.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsNotificationPreferencesComponent = {
|
||||||
|
displayname: string; // Display name.
|
||||||
|
notifications: AddonNotificationsNotificationPreferencesNotification[]; // List of notificaitons for the component.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification processor in notification preferences component.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsNotificationPreferencesNotification = {
|
||||||
|
displayname: string; // Display name.
|
||||||
|
preferencekey: string; // Preference key.
|
||||||
|
processors: AddonNotificationsNotificationPreferencesNotificationProcessor[]; // Processors values for this notification.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification processor in notification preferences component.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsNotificationPreferencesNotificationProcessor = {
|
||||||
|
displayname: string; // Display name.
|
||||||
|
name: string; // Processor name.
|
||||||
|
locked: boolean; // Is locked by admin?.
|
||||||
|
lockedmessage?: string; // Text to display if locked.
|
||||||
|
userconfigured: number; // Is configured?.
|
||||||
|
loggedin: AddonNotificationsNotificationPreferencesNotificationProcessorState;
|
||||||
|
loggedoff: AddonNotificationsNotificationPreferencesNotificationProcessorState;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State in notification processor in notification preferences component.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsNotificationPreferencesNotificationProcessorState = {
|
||||||
|
name: string; // Name.
|
||||||
|
displayname: string; // Display name.
|
||||||
|
checked: boolean; // Is checked?.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_messages.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsGetMessagesResult = {
|
||||||
|
messages: AddonNotificationsGetMessagesMessage[];
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message data returned by core_message_get_messages.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsGetMessagesMessage = {
|
||||||
|
id: number; // Message id.
|
||||||
|
useridfrom: number; // User from id.
|
||||||
|
useridto: number; // User to id.
|
||||||
|
subject: string; // The message subject.
|
||||||
|
text: string; // The message text formated.
|
||||||
|
fullmessage: string; // The message.
|
||||||
|
fullmessageformat: number; // Fullmessage format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
fullmessagehtml: string; // The message in html.
|
||||||
|
smallmessage: string; // The shorten message.
|
||||||
|
notification: number; // Is a notification?.
|
||||||
|
contexturl: string; // Context URL.
|
||||||
|
contexturlname: string; // Context URL link name.
|
||||||
|
timecreated: number; // Time created.
|
||||||
|
timeread: number; // Time read.
|
||||||
|
usertofullname: string; // User to full name.
|
||||||
|
userfromfullname: string; // User from full name.
|
||||||
|
component?: string; // @since 3.7. The component that generated the notification.
|
||||||
|
eventtype?: string; // @since 3.7. The type of notification.
|
||||||
|
customdata?: any; // @since 3.7. Custom data to be passed to the message processor.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message data returned by core_message_get_messages with some calculated data.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsGetMessagesMessageFormatted =
|
||||||
|
AddonNotificationsGetMessagesMessage & AddonNotificationsNotificationCalculatedData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS message_popup_get_popup_notifications.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsGetPopupNotificationsResult = {
|
||||||
|
notifications: AddonNotificationsPopupNotification[];
|
||||||
|
unreadcount: number; // The number of unread message for the given user.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification returned by message_popup_get_popup_notifications.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsPopupNotification = {
|
||||||
|
id: number; // Notification id (this is not guaranteed to be unique within this result set).
|
||||||
|
useridfrom: number; // User from id.
|
||||||
|
useridto: number; // User to id.
|
||||||
|
subject: string; // The notification subject.
|
||||||
|
shortenedsubject: string; // The notification subject shortened with ellipsis.
|
||||||
|
text: string; // The message text formated.
|
||||||
|
fullmessage: string; // The message.
|
||||||
|
fullmessageformat: number; // Fullmessage format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
fullmessagehtml: string; // The message in html.
|
||||||
|
smallmessage: string; // The shorten message.
|
||||||
|
contexturl: string; // Context URL.
|
||||||
|
contexturlname: string; // Context URL link name.
|
||||||
|
timecreated: number; // Time created.
|
||||||
|
timecreatedpretty: string; // Time created in a pretty format.
|
||||||
|
timeread: number; // Time read.
|
||||||
|
read: boolean; // Notification read status.
|
||||||
|
deleted: boolean; // Notification deletion status.
|
||||||
|
iconurl: string; // URL for notification icon.
|
||||||
|
component?: string; // The component that generated the notification.
|
||||||
|
eventtype?: string; // The type of notification.
|
||||||
|
customdata?: any; // @since 3.7. Custom data to be passed to the message processor.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification returned by message_popup_get_popup_notifications.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsPopupNotificationFormatted =
|
||||||
|
AddonNotificationsPopupNotification & AddonNotificationsNotificationCalculatedData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any kind of notification that can be retrieved.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsAnyNotification =
|
||||||
|
AddonNotificationsPopupNotificationFormatted | AddonNotificationsGetMessagesMessageFormatted;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_get_user_notification_preferences.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsGetUserNotificationPreferencesResult = {
|
||||||
|
preferences: AddonNotificationsNotificationPreferences;
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of WS core_message_mark_notification_read.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsMarkNotificationReadResult = {
|
||||||
|
notificationid: number; // Id of the notification.
|
||||||
|
warnings?: CoreWSExternalWarning[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculated data for messages returned by core_message_get_messages.
|
||||||
|
*/
|
||||||
|
export type AddonNotificationsNotificationCalculatedData = {
|
||||||
|
mobiletext?: string; // Calculated in the app. Text to display for the notification.
|
||||||
|
moodlecomponent?: string; // Calculated in the app. Moodle's component.
|
||||||
|
notif?: number; // Calculated in the app. Whether it's a notification.
|
||||||
|
notification?: number; // Calculated in the app in some cases. Whether it's a notification.
|
||||||
|
read?: boolean; // Calculated in the app. Whether the notifications is read.
|
||||||
|
courseid?: number; // Calculated in the app. Course the notification belongs to.
|
||||||
|
profileimageurlfrom?: string; // Calculated in the app. Avatar of user that sent the notification.
|
||||||
|
userfromfullname?: string; // Calculated in the app in some cases. User from full name.
|
||||||
|
};
|
||||||
|
|
|
@ -407,3 +407,27 @@ export class CoreCommentsProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by comment_area_exporter.
|
||||||
|
*/
|
||||||
|
export type CoreCommentsArea = {
|
||||||
|
component: string; // Component.
|
||||||
|
commentarea: string; // Commentarea.
|
||||||
|
itemid: number; // Itemid.
|
||||||
|
courseid: number; // Courseid.
|
||||||
|
contextid: number; // Contextid.
|
||||||
|
cid: string; // Cid.
|
||||||
|
autostart: boolean; // Autostart.
|
||||||
|
canpost: boolean; // Canpost.
|
||||||
|
canview: boolean; // Canview.
|
||||||
|
count: number; // Count.
|
||||||
|
collapsediconkey: string; // Collapsediconkey.
|
||||||
|
displaytotalcount: boolean; // Displaytotalcount.
|
||||||
|
displaycancel: boolean; // Displaycancel.
|
||||||
|
fullwidth: boolean; // Fullwidth.
|
||||||
|
linktext: string; // Linktext.
|
||||||
|
notoggle: boolean; // Notoggle.
|
||||||
|
template: string; // Template.
|
||||||
|
canpostorhascomments: boolean; // Canpostorhascomments.
|
||||||
|
};
|
||||||
|
|
|
@ -1135,3 +1135,38 @@ export class CoreCourseProvider {
|
||||||
}, siteId);
|
}, siteId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by course_summary_exporter.
|
||||||
|
*/
|
||||||
|
export type CoreCourseSummary = {
|
||||||
|
id: number; // Id.
|
||||||
|
fullname: string; // Fullname.
|
||||||
|
shortname: string; // Shortname.
|
||||||
|
idnumber: string; // Idnumber.
|
||||||
|
summary: string; // Summary.
|
||||||
|
summaryformat: number; // Summary format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
||||||
|
startdate: number; // Startdate.
|
||||||
|
enddate: number; // Enddate.
|
||||||
|
visible: boolean; // Visible.
|
||||||
|
fullnamedisplay: string; // Fullnamedisplay.
|
||||||
|
viewurl: string; // Viewurl.
|
||||||
|
courseimage: string; // Courseimage.
|
||||||
|
progress?: number; // Progress.
|
||||||
|
hasprogress: boolean; // Hasprogress.
|
||||||
|
isfavourite: boolean; // Isfavourite.
|
||||||
|
hidden: boolean; // Hidden.
|
||||||
|
timeaccess?: number; // Timeaccess.
|
||||||
|
showshortname: boolean; // Showshortname.
|
||||||
|
coursecategory: string; // Coursecategory.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by course_module_summary_exporter.
|
||||||
|
*/
|
||||||
|
export type CoreCourseModuleSummary = {
|
||||||
|
id: number; // Id.
|
||||||
|
name: string; // Name.
|
||||||
|
url?: string; // Url.
|
||||||
|
iconurl: string; // Iconurl.
|
||||||
|
};
|
||||||
|
|
|
@ -17,74 +17,6 @@ import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure of a tag cloud returned by WS.
|
|
||||||
*/
|
|
||||||
export interface CoreTagCloud {
|
|
||||||
tags: CoreTagCloudTag[];
|
|
||||||
tagscount: number;
|
|
||||||
totalcount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure of a tag cloud tag returned by WS.
|
|
||||||
*/
|
|
||||||
export interface CoreTagCloudTag {
|
|
||||||
name: string;
|
|
||||||
viewurl: string;
|
|
||||||
flag: boolean;
|
|
||||||
isstandard: boolean;
|
|
||||||
count: number;
|
|
||||||
size: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure of a tag collection returned by WS.
|
|
||||||
*/
|
|
||||||
export interface CoreTagCollection {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
isdefault: boolean;
|
|
||||||
component: string;
|
|
||||||
sortoder: number;
|
|
||||||
searchable: boolean;
|
|
||||||
customurl: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure of a tag index returned by WS.
|
|
||||||
*/
|
|
||||||
export interface CoreTagIndex {
|
|
||||||
tagid: number;
|
|
||||||
ta: number;
|
|
||||||
component: string;
|
|
||||||
itemtype: string;
|
|
||||||
nextpageurl: string;
|
|
||||||
prevpageurl: string;
|
|
||||||
exclusiveurl: string;
|
|
||||||
exclusivetext: string;
|
|
||||||
title: string;
|
|
||||||
content: string;
|
|
||||||
hascontent: number;
|
|
||||||
anchor: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure of a tag item returned by WS.
|
|
||||||
*/
|
|
||||||
export interface CoreTagItem {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
rawname: string;
|
|
||||||
isstandard: boolean;
|
|
||||||
tagcollid: number;
|
|
||||||
taginstanceid: number;
|
|
||||||
taginstancecontextid: number;
|
|
||||||
itemid: number;
|
|
||||||
ordering: number;
|
|
||||||
flag: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to handle tags.
|
* Service to handle tags.
|
||||||
*/
|
*/
|
||||||
|
@ -343,3 +275,71 @@ export class CoreTagProvider {
|
||||||
+ contextId + ':' + (recursive ? 1 : 0);
|
+ contextId + ':' + (recursive ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure of a tag cloud returned by WS.
|
||||||
|
*/
|
||||||
|
export type CoreTagCloud = {
|
||||||
|
tags: CoreTagCloudTag[];
|
||||||
|
tagscount: number;
|
||||||
|
totalcount: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure of a tag cloud tag returned by WS.
|
||||||
|
*/
|
||||||
|
export type CoreTagCloudTag = {
|
||||||
|
name: string;
|
||||||
|
viewurl: string;
|
||||||
|
flag: boolean;
|
||||||
|
isstandard: boolean;
|
||||||
|
count: number;
|
||||||
|
size: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure of a tag collection returned by WS.
|
||||||
|
*/
|
||||||
|
export type CoreTagCollection = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
isdefault: boolean;
|
||||||
|
component: string;
|
||||||
|
sortoder: number;
|
||||||
|
searchable: boolean;
|
||||||
|
customurl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure of a tag index returned by WS.
|
||||||
|
*/
|
||||||
|
export type CoreTagIndex = {
|
||||||
|
tagid: number;
|
||||||
|
ta: number;
|
||||||
|
component: string;
|
||||||
|
itemtype: string;
|
||||||
|
nextpageurl: string;
|
||||||
|
prevpageurl: string;
|
||||||
|
exclusiveurl: string;
|
||||||
|
exclusivetext: string;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
hascontent: number;
|
||||||
|
anchor: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure of a tag item returned by WS.
|
||||||
|
*/
|
||||||
|
export type CoreTagItem = {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
rawname: string;
|
||||||
|
isstandard: boolean;
|
||||||
|
tagcollid: number;
|
||||||
|
taginstanceid: number;
|
||||||
|
taginstancecontextid: number;
|
||||||
|
itemid: number;
|
||||||
|
ordering: number;
|
||||||
|
flag: number;
|
||||||
|
};
|
||||||
|
|
|
@ -634,3 +634,21 @@ export class CoreUserProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by user_summary_exporter.
|
||||||
|
*/
|
||||||
|
export type CoreUserSummary = {
|
||||||
|
id: number; // Id.
|
||||||
|
email: string; // Email.
|
||||||
|
idnumber: string; // Idnumber.
|
||||||
|
phone1: string; // Phone1.
|
||||||
|
phone2: string; // Phone2.
|
||||||
|
department: string; // Department.
|
||||||
|
institution: string; // Institution.
|
||||||
|
fullname: string; // Fullname.
|
||||||
|
identity: string; // Identity.
|
||||||
|
profileurl: string; // Profileurl.
|
||||||
|
profileimageurl: string; // Profileimageurl.
|
||||||
|
profileimageurlsmall: string; // Profileimageurlsmall.
|
||||||
|
};
|
||||||
|
|
|
@ -81,126 +81,6 @@ export interface CoreWSAjaxPreSets {
|
||||||
useGet?: boolean;
|
useGet?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Error returned by a WS call.
|
|
||||||
*/
|
|
||||||
export interface CoreWSError {
|
|
||||||
/**
|
|
||||||
* The error message.
|
|
||||||
*/
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the exception. Undefined for local errors (fake WS errors).
|
|
||||||
*/
|
|
||||||
exception?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The error code. Undefined for local errors (fake WS errors).
|
|
||||||
*/
|
|
||||||
errorcode?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File upload options.
|
|
||||||
*/
|
|
||||||
export interface CoreWSFileUploadOptions extends FileUploadOptions {
|
|
||||||
/**
|
|
||||||
* The file area where to put the file. By default, 'draft'.
|
|
||||||
*/
|
|
||||||
fileArea?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Item ID of the area where to put the file. By default, 0.
|
|
||||||
*/
|
|
||||||
itemId?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure of warnings returned by WS.
|
|
||||||
*/
|
|
||||||
export type CoreWSExternalWarning = {
|
|
||||||
/**
|
|
||||||
* Item.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
item?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Item id.
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
itemid?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The warning code can be used by the client app to implement specific behaviour.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
warningcode: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Untranslated english message to explain the warning.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
message: string;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Structure of files returned by WS.
|
|
||||||
*/
|
|
||||||
export type CoreWSExternalFile = {
|
|
||||||
/**
|
|
||||||
* File name.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
filename?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File path.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
filepath?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File size.
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
filesize?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Downloadable file url.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
fileurl?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Time modified.
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
timemodified?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File mime type.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
mimetype?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether is an external file.
|
|
||||||
* @type {number}
|
|
||||||
*/
|
|
||||||
isexternalfile?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The repository type for external files.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
repositorytype?: string;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This service allows performing WS calls and download/upload files.
|
* This service allows performing WS calls and download/upload files.
|
||||||
*/
|
*/
|
||||||
|
@ -948,3 +828,127 @@ export class CoreWSProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error returned by a WS call.
|
||||||
|
*/
|
||||||
|
export interface CoreWSError {
|
||||||
|
/**
|
||||||
|
* The error message.
|
||||||
|
*/
|
||||||
|
message: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the exception. Undefined for local errors (fake WS errors).
|
||||||
|
*/
|
||||||
|
exception?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The error code. Undefined for local errors (fake WS errors).
|
||||||
|
*/
|
||||||
|
errorcode?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File upload options.
|
||||||
|
*/
|
||||||
|
export interface CoreWSFileUploadOptions extends FileUploadOptions {
|
||||||
|
/**
|
||||||
|
* The file area where to put the file. By default, 'draft'.
|
||||||
|
*/
|
||||||
|
fileArea?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item ID of the area where to put the file. By default, 0.
|
||||||
|
*/
|
||||||
|
itemId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure of warnings returned by WS.
|
||||||
|
*/
|
||||||
|
export type CoreWSExternalWarning = {
|
||||||
|
/**
|
||||||
|
* Item.
|
||||||
|
*/
|
||||||
|
item?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item id.
|
||||||
|
*/
|
||||||
|
itemid?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The warning code can be used by the client app to implement specific behaviour.
|
||||||
|
*/
|
||||||
|
warningcode: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Untranslated english message to explain the warning.
|
||||||
|
*/
|
||||||
|
message: string;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure of files returned by WS.
|
||||||
|
*/
|
||||||
|
export type CoreWSExternalFile = {
|
||||||
|
/**
|
||||||
|
* File name.
|
||||||
|
*/
|
||||||
|
filename?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File path.
|
||||||
|
*/
|
||||||
|
filepath?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File size.
|
||||||
|
*/
|
||||||
|
filesize?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloadable file url.
|
||||||
|
*/
|
||||||
|
fileurl?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time modified.
|
||||||
|
*/
|
||||||
|
timemodified?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File mime type.
|
||||||
|
*/
|
||||||
|
mimetype?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether is an external file.
|
||||||
|
*/
|
||||||
|
isexternalfile?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The repository type for external files.
|
||||||
|
*/
|
||||||
|
repositorytype?: string;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data returned by date_exporter.
|
||||||
|
*/
|
||||||
|
export type CoreWSDate = {
|
||||||
|
seconds: number; // Seconds.
|
||||||
|
minutes: number; // Minutes.
|
||||||
|
hours: number; // Hours.
|
||||||
|
mday: number; // Mday.
|
||||||
|
wday: number; // Wday.
|
||||||
|
mon: number; // Mon.
|
||||||
|
year: number; // Year.
|
||||||
|
yday: number; // Yday.
|
||||||
|
weekday: string; // Weekday.
|
||||||
|
month: string; // Month.
|
||||||
|
timestamp: number; // Timestamp.
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue