commit
ac574a76f3
|
@ -346,6 +346,7 @@
|
|||
"addon.mod_book.errorchapter": "book",
|
||||
"addon.mod_book.modulenameplural": "book",
|
||||
"addon.mod_chat.beep": "chat",
|
||||
"addon.mod_chat.chatreport": "chat",
|
||||
"addon.mod_chat.currentusers": "chat",
|
||||
"addon.mod_chat.enterchat": "chat",
|
||||
"addon.mod_chat.entermessage": "chat",
|
||||
|
@ -357,12 +358,16 @@
|
|||
"addon.mod_chat.messagebeepsyou": "chat",
|
||||
"addon.mod_chat.messageenter": "chat",
|
||||
"addon.mod_chat.messageexit": "chat",
|
||||
"addon.mod_chat.messages": "chat",
|
||||
"addon.mod_chat.modulenameplural": "chat",
|
||||
"addon.mod_chat.mustbeonlinetosendmessages": "local_moodlemobileapp",
|
||||
"addon.mod_chat.nomessages": "chat",
|
||||
"addon.mod_chat.nosessionsfound": "local_moodlemobileapp",
|
||||
"addon.mod_chat.send": "chat",
|
||||
"addon.mod_chat.sessionstart": "chat",
|
||||
"addon.mod_chat.showincompletesessions": "local_moodlemobileapp",
|
||||
"addon.mod_chat.talk": "chat",
|
||||
"addon.mod_chat.viewreport": "chat",
|
||||
"addon.mod_choice.cannotsubmit": "choice",
|
||||
"addon.mod_choice.choiceoptions": "choice",
|
||||
"addon.mod_choice.errorgetchoice": "local_moodlemobileapp",
|
||||
|
@ -1295,6 +1300,7 @@
|
|||
"core.defaultvalue": "tool_usertours",
|
||||
"core.delete": "moodle",
|
||||
"core.deletedoffline": "local_moodlemobileapp",
|
||||
"core.deleteduser": "bulkusers",
|
||||
"core.deleting": "local_moodlemobileapp",
|
||||
"core.description": "moodle",
|
||||
"core.dfdaymonthyear": "local_moodlemobileapp",
|
||||
|
@ -1545,6 +1551,7 @@
|
|||
"core.noresults": "moodle",
|
||||
"core.notapplicable": "local_moodlemobileapp",
|
||||
"core.notice": "moodle",
|
||||
"core.notingroup": "moodle",
|
||||
"core.notsent": "local_moodlemobileapp",
|
||||
"core.now": "moodle",
|
||||
"core.numwords": "moodle",
|
||||
|
|
|
@ -15,11 +15,13 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
|
||||
import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
|
||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||
import { AddonModChatComponentsModule } from './components/components.module';
|
||||
import { AddonModChatProvider } from './providers/chat';
|
||||
import { AddonModChatLinkHandler } from './providers/link-handler';
|
||||
import { AddonModChatListLinkHandler } from './providers/list-link-handler';
|
||||
import { AddonModChatModuleHandler } from './providers/module-handler';
|
||||
import { AddonModChatPrefetchHandler } from './providers/prefetch-handler';
|
||||
|
||||
// List of providers (without handlers).
|
||||
export const ADDON_MOD_CHAT_PROVIDERS: any[] = [
|
||||
|
@ -37,15 +39,18 @@ export const ADDON_MOD_CHAT_PROVIDERS: any[] = [
|
|||
AddonModChatLinkHandler,
|
||||
AddonModChatListLinkHandler,
|
||||
AddonModChatModuleHandler,
|
||||
AddonModChatPrefetchHandler
|
||||
]
|
||||
})
|
||||
export class AddonModChatModule {
|
||||
constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModChatModuleHandler,
|
||||
contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModChatLinkHandler,
|
||||
prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModChatPrefetchHandler,
|
||||
listLinkHandler: AddonModChatListLinkHandler) {
|
||||
|
||||
moduleDelegate.registerHandler(moduleHandler);
|
||||
contentLinksDelegate.registerHandler(linkHandler);
|
||||
contentLinksDelegate.registerHandler(listLinkHandler);
|
||||
prefetchDelegate.registerHandler(prefetchHandler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch()" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
@ -17,7 +18,8 @@
|
|||
<ion-icon name="time"></ion-icon> {{ 'addon.mod_chat.sessionstart' | translate:{$a: chatInfo} }}
|
||||
</ion-card>
|
||||
|
||||
<div padding-horizontal>
|
||||
<div padding>
|
||||
<a ion-button block color="primary" (click)="enterChat()">{{ 'addon.mod_chat.enterchat' | translate }}</a>
|
||||
<a ion-button block color="light" margin-top *ngIf="sessionsAvailable" (click)="viewSessions()">{{ 'addon.mod_chat.viewreport' | translate }}</a>
|
||||
</div>
|
||||
</core-loading>
|
||||
|
|
|
@ -33,6 +33,7 @@ export class AddonModChatIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
chatInfo: any;
|
||||
|
||||
protected title: string;
|
||||
protected sessionsAvailable = false;
|
||||
|
||||
constructor(injector: Injector, private chatProvider: AddonModChatProvider, private timeUtils: CoreTimeUtilsProvider,
|
||||
protected navCtrl: NavController) {
|
||||
|
@ -83,6 +84,10 @@ export class AddonModChatIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
|
||||
// All data obtained, now fill the context menu.
|
||||
this.fillContextMenu(refresh);
|
||||
|
||||
return this.chatProvider.areSessionsAvailable().then((available) => {
|
||||
this.sessionsAvailable = available;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -93,4 +98,11 @@ export class AddonModChatIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
const title = this.chat.name || this.moduleName;
|
||||
this.navCtrl.push('AddonModChatChatPage', {chatId: this.chat.id, courseId: this.courseId, title: title });
|
||||
}
|
||||
|
||||
/**
|
||||
* View past sessions.
|
||||
*/
|
||||
viewSessions(): void {
|
||||
this.navCtrl.push('AddonModChatSessionsPage', {courseId: this.courseId, chatId: this.chat.id, cmId: this.module.id});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"beep": "Beep",
|
||||
"chatreport": "Chat sessions",
|
||||
"currentusers": "Current users",
|
||||
"enterchat": "Click here to enter the chat now",
|
||||
"entermessage": "Enter your message",
|
||||
|
@ -11,10 +12,14 @@
|
|||
"messagebeepsyou": "{{$a}} has just beeped you!",
|
||||
"messageenter": "{{$a}} has just entered this chat",
|
||||
"messageexit": "{{$a}} has left this chat",
|
||||
"messages": "Messages",
|
||||
"modulenameplural": "Chats",
|
||||
"mustbeonlinetosendmessages": "You must be online to send messages.",
|
||||
"nomessages": "No messages yet",
|
||||
"nosessionsfound": "No sessions found",
|
||||
"send": "Send",
|
||||
"sessionstart": "The next chat session will start on {{$a.date}}, ({{$a.fromnow}} from now)",
|
||||
"talk": "Talk"
|
||||
"showincompletesessions": "Show incomplete sessions",
|
||||
"talk": "Talk",
|
||||
"viewreport": "View past chat sessions"
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<ion-header>
|
||||
<ion-navbar core-back-button>
|
||||
<ion-title>{{ 'addon.mod_chat.messages' | translate }}</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="loaded" (ionRefresh)="refreshMessages($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="loaded">
|
||||
<div *ngFor="let message of messages; index as index; last as last">
|
||||
<div text-center *ngIf="showDate(messages[index], messages[index - 1])" class="addon-mod-chat-notice">
|
||||
<ion-badge text-wrap color="light">
|
||||
<span>{{ message.timestamp * 1000 | coreFormatDate:"strftimedayshort" }}</span>
|
||||
</ion-badge>
|
||||
</div>
|
||||
|
||||
<div text-center *ngIf="message.issystem && message.message == 'enter'" class="addon-mod-chat-notice">
|
||||
<ion-badge text-wrap color="light">
|
||||
<span>{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }}</span>
|
||||
</ion-badge>
|
||||
</div>
|
||||
|
||||
<div text-center *ngIf="message.issystem && message.message == 'exit'" class="addon-mod-chat-notice">
|
||||
<ion-badge text-wrap color="light">
|
||||
<span>{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }}</span>
|
||||
</ion-badge>
|
||||
</div>
|
||||
|
||||
<ion-item text-wrap *ngIf="!message.issystem && message.message.substr(0, 4) != 'beep'" class="addon-mod-chat-message">
|
||||
<ion-avatar core-user-avatar [user]="message" item-start></ion-avatar>
|
||||
<h2>
|
||||
<p float-end>{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}</p>
|
||||
<core-format-text [text]="message.userfullname"></core-format-text>
|
||||
</h2>
|
||||
<core-format-text [text]="message.message"></core-format-text>
|
||||
</ion-item>
|
||||
</div>
|
||||
</core-loading>
|
||||
</ion-content>
|
|
@ -0,0 +1,37 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { CorePipesModule } from '@pipes/pipes.module';
|
||||
import { AddonModChatComponentsModule } from '../../components/components.module';
|
||||
import { AddonModChatSessionMessagesPage } from './session-messages';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModChatSessionMessagesPage,
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CorePipesModule,
|
||||
AddonModChatComponentsModule,
|
||||
IonicPageModule.forChild(AddonModChatSessionMessagesPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class AddonModChatSessionMessagesPageModule {}
|
|
@ -0,0 +1,9 @@
|
|||
ion-app.app-root page-addon-mod-chat-session-messages {
|
||||
.addon-mod-chat-notice {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.addon-mod-chat-message {
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { IonicPage, NavParams } from 'ionic-angular';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { AddonModChatProvider } from '../../providers/chat';
|
||||
import * as moment from 'moment';
|
||||
|
||||
/**
|
||||
* Page that displays list of chat session messages.
|
||||
*/
|
||||
@IonicPage({ segment: 'addon-mod-chat-session-messages' })
|
||||
@Component({
|
||||
selector: 'page-addon-mod-chat-session-messages',
|
||||
templateUrl: 'session-messages.html',
|
||||
})
|
||||
export class AddonModChatSessionMessagesPage {
|
||||
|
||||
protected courseId: number;
|
||||
protected chatId: number;
|
||||
protected sessionStart: number;
|
||||
protected sessionEnd: number;
|
||||
protected groupId: number;
|
||||
protected loaded = false;
|
||||
protected messages = [];
|
||||
|
||||
constructor(navParams: NavParams, private domUtils: CoreDomUtilsProvider, private chatProvider: AddonModChatProvider) {
|
||||
this.courseId = navParams.get('courseId');
|
||||
this.chatId = navParams.get('chatId');
|
||||
this.groupId = navParams.get('groupId');
|
||||
this.sessionStart = navParams.get('sessionStart');
|
||||
this.sessionEnd = navParams.get('sessionEnd');
|
||||
|
||||
this.fetchMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch session messages.
|
||||
*
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected fetchMessages(): Promise<any> {
|
||||
return this.chatProvider.getSessionMessages(this.chatId, this.sessionStart, this.sessionEnd, this.groupId)
|
||||
.then((messages) => {
|
||||
return this.chatProvider.getMessagesUserData(messages, this.courseId).then((messages) => {
|
||||
this.messages = messages;
|
||||
});
|
||||
}).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'core.errorloadingcontent', true);
|
||||
}).finally(() => {
|
||||
this.loaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh session messages.
|
||||
*
|
||||
* @param {any} refresher Refresher.
|
||||
*/
|
||||
refreshMessages(refresher: any): void {
|
||||
this.chatProvider.invalidateSessionMessages(this.chatId, this.sessionStart, this.groupId).finally(() => {
|
||||
this.fetchMessages().finally(() => {
|
||||
refresher.complete();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the date should be displayed between messages (when the day changes at midnight for example).
|
||||
*
|
||||
* @param {any} message New message object.
|
||||
* @param {any} prevMessage Previous message object.
|
||||
* @return {boolean} True if messages are from diferent days, false othetwise.
|
||||
*/
|
||||
showDate(message: any, prevMessage: any): boolean {
|
||||
if (!prevMessage) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if day has changed.
|
||||
return !moment(message.timestamp * 1000).isSame(prevMessage.timestamp * 1000, 'day');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<ion-header>
|
||||
<ion-navbar core-back-button>
|
||||
<ion-title>{{ 'addon.mod_chat.chatreport' | translate }}</ion-title>
|
||||
</ion-navbar>
|
||||
</ion-header>
|
||||
<core-split-view>
|
||||
<ion-content>
|
||||
<ion-refresher [enabled]="loaded" (ionRefresh)="refreshSessions($event)">
|
||||
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
<core-loading [hideUntil]="loaded">
|
||||
<ion-item text-wrap *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)">
|
||||
<ion-label id="addon-chat-groupslabel" *ngIf="groupInfo.separateGroups">{{ 'core.groupsseparate' | translate }}</ion-label>
|
||||
<ion-label id="addon-chat-groupslabel" *ngIf="groupInfo.visibleGroups">{{ 'core.groupsvisible' | translate }}</ion-label>
|
||||
<ion-select [(ngModel)]="groupId" (ionChange)="fetchSessions(true)" aria-labelledby="addon-chat-groupslabel" interface="action-sheet">
|
||||
<ion-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">{{groupOpt.name}}</ion-option>
|
||||
</ion-select>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label id="addon-chat-showalllabel">{{ 'addon.mod_chat.showincompletesessions' | translate }}</ion-label>
|
||||
<ion-toggle [(ngModel)]="showAll" (ionChange)="fetchSessions(true)" aria-labelledby="addon-chat-showalllabel"></ion-toggle>
|
||||
</ion-item>
|
||||
<ion-card *ngFor="let session of sessions" (click)="openSession(session)"
|
||||
[class.addon-mod-chat-session-selected]="session.sessionstart == selectedSessionStart && groupId == selectedSessionGroupId"
|
||||
[class.addon-mod-chat-session-show-more]="session.sessionusers.length < session.allsessionusers.length">
|
||||
<ion-item text-wrap>
|
||||
<h2>{{ session.sessionstart * 1000 | coreFormatDate }}</h2>
|
||||
<p *ngIf="session.duration">{{ session.duration | coreDuration }}</p>
|
||||
</ion-item>
|
||||
<ion-card-content>
|
||||
<p *ngFor="let user of session.sessionusers">
|
||||
{{ user.userfullname }} <span *ngIf="user.messagecount">({{ user.messagecount }})</span>
|
||||
</p>
|
||||
</ion-card-content>
|
||||
<div *ngIf="session.sessionusers.length < session.allsessionusers.length">
|
||||
<button ion-button clear (click)="showMoreUsers(session, $event)">
|
||||
{{ 'core.showmore' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</ion-card>
|
||||
<core-empty-box *ngIf="sessions.length == 0" icon="chatbubbles" [message]="'addon.mod_chat.nosessionsfound' | translate">
|
||||
</core-empty-box>
|
||||
</core-loading>
|
||||
</ion-content>
|
||||
</core-split-view>
|
|
@ -0,0 +1,37 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicPageModule } from 'ionic-angular';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { CoreComponentsModule } from '@components/components.module';
|
||||
import { CoreDirectivesModule } from '@directives/directives.module';
|
||||
import { CorePipesModule } from '@pipes/pipes.module';
|
||||
import { AddonModChatComponentsModule } from '../../components/components.module';
|
||||
import { AddonModChatSessionsPage } from './sessions';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AddonModChatSessionsPage,
|
||||
],
|
||||
imports: [
|
||||
CoreComponentsModule,
|
||||
CoreDirectivesModule,
|
||||
CorePipesModule,
|
||||
AddonModChatComponentsModule,
|
||||
IonicPageModule.forChild(AddonModChatSessionsPage),
|
||||
TranslateModule.forChild()
|
||||
],
|
||||
})
|
||||
export class AddonModChatSessionsPageModule {}
|
|
@ -0,0 +1,8 @@
|
|||
ion-app.app-root page-addon-mod-chat-sessions {
|
||||
.addon-mod-chat-session-show-more .card-content{
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.addon-mod-chat-session-selected {
|
||||
border-top: 5px solid $core-splitview-selected;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, ViewChild } from '@angular/core';
|
||||
import { IonicPage, NavParams } from 'ionic-angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreSplitViewComponent } from '@components/split-view/split-view';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { AddonModChatProvider } from '../../providers/chat';
|
||||
|
||||
/**
|
||||
* Page that displays list of chat sessions.
|
||||
*/
|
||||
@IonicPage({ segment: 'addon-mod-chat-sessions' })
|
||||
@Component({
|
||||
selector: 'page-addon-mod-chat-sessions',
|
||||
templateUrl: 'sessions.html',
|
||||
})
|
||||
export class AddonModChatSessionsPage {
|
||||
|
||||
@ViewChild(CoreSplitViewComponent) splitviewCtrl: CoreSplitViewComponent;
|
||||
|
||||
protected courseId: number;
|
||||
protected cmId: number;
|
||||
protected chatId: number;
|
||||
protected loaded = false;
|
||||
protected showAll = false;
|
||||
protected groupId = 0;
|
||||
protected groupInfo: CoreGroupInfo;
|
||||
protected sessions = [];
|
||||
protected selectedSessionStart: number;
|
||||
protected selectedSessionGroupId: number;
|
||||
|
||||
constructor(navParams: NavParams, private chatProvider: AddonModChatProvider, private domUtils: CoreDomUtilsProvider,
|
||||
private userProvider: CoreUserProvider, private groupsProvider: CoreGroupsProvider,
|
||||
private translate: TranslateService, private utils: CoreUtilsProvider) {
|
||||
this.courseId = navParams.get('courseId');
|
||||
this.cmId = navParams.get('cmId');
|
||||
this.chatId = navParams.get('chatId');
|
||||
|
||||
this.fetchSessions().then(() => {
|
||||
if (this.splitviewCtrl.isOn() && this.sessions.length > 0) {
|
||||
this.openSession(this.sessions[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch chat sessions.
|
||||
*
|
||||
* @param {number} [showLoading] Display a loading modal.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
fetchSessions(showLoading?: boolean): Promise<any> {
|
||||
const modal = showLoading ? this.domUtils.showModalLoading() : null;
|
||||
|
||||
return this.groupsProvider.getActivityGroupInfo(this.cmId, false).then((groupInfo) => {
|
||||
this.groupInfo = groupInfo;
|
||||
|
||||
if (groupInfo.groups && groupInfo.groups.length > 0) {
|
||||
if (!groupInfo.groups.find((group) => group.id === this.groupId)) {
|
||||
this.groupId = groupInfo.groups[0].id;
|
||||
}
|
||||
} else {
|
||||
this.groupId = 0;
|
||||
}
|
||||
|
||||
return this.chatProvider.getSessions(this.chatId, this.groupId, this.showAll);
|
||||
}).then((sessions) => {
|
||||
// Fetch user profiles.
|
||||
const promises = [];
|
||||
|
||||
sessions.forEach((session) => {
|
||||
session.duration = session.sessionend - session.sessionstart;
|
||||
session.sessionusers.forEach((sessionUser) => {
|
||||
if (!sessionUser.userfullname) {
|
||||
// The WS does not return the user name, fetch user profile.
|
||||
promises.push(this.userProvider.getProfile(sessionUser.userid, this.courseId, true).then((user) => {
|
||||
sessionUser.userfullname = user.fullname;
|
||||
}).catch(() => {
|
||||
// Error getting profile, most probably the user is deleted.
|
||||
sessionUser.userfullname = this.translate.instant('core.deleteduser') + ' ' + sessionUser.userid;
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
// If session has more than 4 users we display a "Show more" link.
|
||||
session.allsessionusers = session.sessionusers;
|
||||
if (session.sessionusers.length > 4) {
|
||||
session.sessionusers = session.allsessionusers.slice(0, 3);
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
this.sessions = sessions;
|
||||
});
|
||||
}).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'core.errorloadingcontent', true);
|
||||
}).finally(() => {
|
||||
this.loaded = true;
|
||||
modal && modal.dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh chat sessions.
|
||||
*
|
||||
* @param {any} refresher Refresher.
|
||||
*/
|
||||
refreshSessions(refresher: any): void {
|
||||
const promises = [
|
||||
this.groupsProvider.invalidateActivityGroupInfo(this.cmId),
|
||||
this.chatProvider.invalidateSessions(this.chatId, this.groupId, this.showAll)
|
||||
];
|
||||
|
||||
this.utils.allPromises(promises).finally(() => {
|
||||
this.fetchSessions().finally(() => {
|
||||
refresher.complete();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a session.
|
||||
*
|
||||
* @param {any} session Chat session.
|
||||
*/
|
||||
openSession(session: any): void {
|
||||
this.selectedSessionStart = session.sessionstart;
|
||||
this.selectedSessionGroupId = this.groupId;
|
||||
const params = {
|
||||
courseId: this.courseId,
|
||||
chatId: this.chatId,
|
||||
groupId: this.groupId,
|
||||
sessionStart: session.sessionstart,
|
||||
sessionEnd: session.sessionend
|
||||
};
|
||||
this.splitviewCtrl.push('AddonModChatSessionMessagesPage', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show more session users.
|
||||
*
|
||||
* @param {any} session Chat session.
|
||||
* @param {Event} $event The event.
|
||||
*/
|
||||
showMoreUsers(session: any, $event: Event): void {
|
||||
session.sessionusers = session.allsessionusers;
|
||||
$event.stopPropagation();
|
||||
}
|
||||
}
|
|
@ -13,9 +13,12 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreSiteWSPreSets } from '@classes/site';
|
||||
|
||||
/**
|
||||
* Service that provides some features for chats.
|
||||
|
@ -25,34 +28,38 @@ export class AddonModChatProvider {
|
|||
static COMPONENT = 'mmaModChat';
|
||||
static POLL_INTERVAL = 4000;
|
||||
|
||||
protected ROOT_CACHE_KEY = 'AddonModChat:';
|
||||
|
||||
constructor(private sitesProvider: CoreSitesProvider, private userProvider: CoreUserProvider,
|
||||
private logHelper: CoreCourseLogHelperProvider) {}
|
||||
private logHelper: CoreCourseLogHelperProvider, protected utils: CoreUtilsProvider, private translate: TranslateService) {}
|
||||
|
||||
/**
|
||||
* Get a chat.
|
||||
*
|
||||
* @param {number} courseId Course ID.
|
||||
* @param {number} cmId Course module ID.
|
||||
* @param {boolean} [refresh=false] True when we should not get the value from the cache.
|
||||
* @param {number} courseId Course ID.
|
||||
* @param {number} cmId Course module ID.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any>} Promise resolved when the chat is retrieved.
|
||||
*/
|
||||
getChat(courseId: number, cmId: number, refresh: boolean = false): Promise<any> {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
};
|
||||
const preSets = {
|
||||
getFromCache: refresh ? false : undefined,
|
||||
};
|
||||
getChat(courseId: number, cmId: number, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getChatsCacheKey(courseId)
|
||||
};
|
||||
|
||||
return this.sitesProvider.getCurrentSite().read('mod_chat_get_chats_by_courses', params, preSets).then((response) => {
|
||||
if (response.chats) {
|
||||
const chat = response.chats.find((chat) => chat.coursemodule == cmId);
|
||||
if (chat) {
|
||||
return chat;
|
||||
return site.read('mod_chat_get_chats_by_courses', params, preSets).then((response) => {
|
||||
if (response.chats) {
|
||||
const chat = response.chats.find((chat) => chat.coursemodule == cmId);
|
||||
if (chat) {
|
||||
return chat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(null);
|
||||
return Promise.reject(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -146,8 +153,8 @@ export class AddonModChatProvider {
|
|||
message.userfullname = user.fullname;
|
||||
message.userprofileimageurl = user.profileimageurl;
|
||||
}).catch(() => {
|
||||
// Error getting profile. Set default data.
|
||||
message.userfullname = message.userid;
|
||||
// Error getting profile, most probably the user is deleted.
|
||||
message.userfullname = this.translate.instant('core.deleteduser') + ' ' + message.userid;
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -172,4 +179,210 @@ export class AddonModChatProvider {
|
|||
|
||||
return this.sitesProvider.getCurrentSite().read('mod_chat_get_chat_users', params, preSets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether WS for passed sessions are available.
|
||||
*
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<boolean>} Promise resolved with a boolean.
|
||||
*/
|
||||
areSessionsAvailable(siteId?: string): Promise<boolean> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return site.wsAvailable('mod_chat_get_sessions') && site.wsAvailable('mod_chat_get_session_messages');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get chat sessions.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @param {number} [groupId=0] Group ID, 0 means that the function will determine the user group.
|
||||
* @param {boolean} [showAll=false] Whether to include incomplete sessions or not.
|
||||
* @param {boolean} [ignoreCache=false] True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any[]>} Promise resolved with the list of sessions.
|
||||
* @since 3.5
|
||||
*/
|
||||
getSessions(chatId: number, groupId: number = 0, showAll: boolean = false, ignoreCache: boolean = false, siteId?: string):
|
||||
Promise<any[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const params = {
|
||||
chatid: chatId,
|
||||
groupid: groupId,
|
||||
showall: showAll ? 1 : 0
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getSessionsCacheKey(chatId, groupId, showAll),
|
||||
};
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
return site.read('mod_chat_get_sessions', params, preSets).then((response) => {
|
||||
if (!response || !response.sessions) {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
return response.sessions;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get chat session messages.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @param {number} sessionStart Session start time.
|
||||
* @param {number} sessionEnd Session end time.
|
||||
* @param {number} [groupId=0] Group ID, 0 means that the function will determine the user group.
|
||||
* @param {boolean} [ignoreCache=false] True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any[]>} Promise resolved with the list of messages.
|
||||
* @since 3.5
|
||||
*/
|
||||
getSessionMessages(chatId: number, sessionStart: number, sessionEnd: number, groupId: number = 0, ignoreCache: boolean = false,
|
||||
siteId?: string): Promise<any[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const params = {
|
||||
chatid: chatId,
|
||||
sessionstart: sessionStart,
|
||||
sessionend: sessionEnd,
|
||||
groupid: groupId
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getSessionMessagesCacheKey(chatId, sessionStart, groupId)
|
||||
};
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
return site.read('mod_chat_get_session_messages', params, preSets).then((response) => {
|
||||
if (!response || !response.messages) {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
return response.messages;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate chats.
|
||||
*
|
||||
* @param {number} courseId Course ID.
|
||||
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
||||
*/
|
||||
invalidateChats(courseId: number): Promise<any> {
|
||||
const site = this.sitesProvider.getCurrentSite();
|
||||
|
||||
return site.invalidateWsCacheForKey(this.getChatsCacheKey(courseId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate chat sessions.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @param {number} [groupId=0] Group ID, 0 means that the function will determine the user group.
|
||||
* @param {boolean} [showAll=false] Whether to include incomplete sessions or not.
|
||||
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
||||
*/
|
||||
invalidateSessions(chatId: number, groupId: number = 0, showAll: boolean = false): Promise<any> {
|
||||
const site = this.sitesProvider.getCurrentSite();
|
||||
|
||||
return site.invalidateWsCacheForKey(this.getSessionsCacheKey(chatId, groupId, showAll));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all chat sessions.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
||||
*/
|
||||
invalidateAllSessions(chatId: number): Promise<any> {
|
||||
const site = this.sitesProvider.getCurrentSite();
|
||||
|
||||
return site.invalidateWsCacheForKeyStartingWith(this.getSessionsCacheKeyPrefix(chatId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate chat session messages.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @param {number} sessionStart Session start time.
|
||||
* @param {number} [groupId=0] Group ID, 0 means that the function will determine the user group.
|
||||
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
||||
*/
|
||||
invalidateSessionMessages(chatId: number, sessionStart: number, groupId: number = 0): Promise<any> {
|
||||
const site = this.sitesProvider.getCurrentSite();
|
||||
|
||||
return site.invalidateWsCacheForKey(this.getSessionMessagesCacheKey(chatId, sessionStart, groupId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all chat session messages.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
||||
*/
|
||||
invalidateAllSessionMessages(chatId: number): Promise<any> {
|
||||
const site = this.sitesProvider.getCurrentSite();
|
||||
|
||||
return site.invalidateWsCacheForKeyStartingWith(this.getSessionMessagesCacheKeyPrefix(chatId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key for chats WS call.
|
||||
*
|
||||
* @param {number} courseId Course ID.
|
||||
* @return {string} Cache key.
|
||||
*/
|
||||
protected getChatsCacheKey(courseId: number): string {
|
||||
return this.ROOT_CACHE_KEY + 'chats:' + courseId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key for sessions WS call.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @param {number} groupId Goup ID, 0 means that the function will determine the user group.
|
||||
* @param {boolean} showAll Whether to include incomplete sessions or not.
|
||||
* @return {string} Cache key.
|
||||
*/
|
||||
protected getSessionsCacheKey(chatId: number, groupId: number, showAll: boolean): string {
|
||||
return this.getSessionsCacheKeyPrefix(chatId) + groupId + ':' + (showAll ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key prefix for sessions WS call.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @return {string} Cache key prefix.
|
||||
*/
|
||||
protected getSessionsCacheKeyPrefix(chatId: number): string {
|
||||
return this.ROOT_CACHE_KEY + 'sessions:' + chatId + ':';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key for session messages WS call.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @param {number} sessionStart Session start time.
|
||||
* @param {number} groupId Group ID, 0 means that the function will determine the user group.
|
||||
* @return {string} Cache key.
|
||||
*/
|
||||
protected getSessionMessagesCacheKey(chatId: number, sessionStart: number, groupId: number): string {
|
||||
return this.getSessionMessagesCacheKeyPrefix(chatId) + sessionStart + ':' + groupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key prefix for session messages WS call.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @return {string} Cache key prefix.
|
||||
*/
|
||||
protected getSessionMessagesCacheKeyPrefix(chatId: number): string {
|
||||
return this.ROOT_CACHE_KEY + 'sessionsMessages:' + chatId + ':';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import { AddonModChatIndexComponent } from '../components/index/index';
|
|||
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreConstants } from '@core/constants';
|
||||
import { AddonModChatProvider } from './chat';
|
||||
|
||||
/**
|
||||
* Handler to support chat modules.
|
||||
|
@ -38,7 +39,7 @@ export class AddonModChatModuleHandler implements CoreCourseModuleHandler {
|
|||
[CoreConstants.FEATURE_SHOW_DESCRIPTION]: true
|
||||
};
|
||||
|
||||
constructor(private courseProvider: CoreCourseProvider) { }
|
||||
constructor(private courseProvider: CoreCourseProvider, private chatProvider: AddonModChatProvider) { }
|
||||
|
||||
/**
|
||||
* Check if the handler is enabled on a site level.
|
||||
|
@ -58,7 +59,7 @@ export class AddonModChatModuleHandler implements CoreCourseModuleHandler {
|
|||
* @return {CoreCourseModuleHandlerData} Data to render the module.
|
||||
*/
|
||||
getData(module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData {
|
||||
return {
|
||||
const data: CoreCourseModuleHandlerData = {
|
||||
icon: this.courseProvider.getModuleIconSrc(this.modName, module.modicon),
|
||||
title: module.name,
|
||||
class: 'addon-mod_chat-handler',
|
||||
|
@ -70,6 +71,12 @@ export class AddonModChatModuleHandler implements CoreCourseModuleHandler {
|
|||
navCtrl.push('AddonModChatIndexPage', pageParams, options);
|
||||
}
|
||||
};
|
||||
|
||||
this.chatProvider.areSessionsAvailable().then((available) => {
|
||||
data.showDownloadButton = available;
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
// (C) Copyright 2015 Martin Dougiamas
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { AddonModChatProvider } from './chat';
|
||||
|
||||
/**
|
||||
* Handler to prefetch chats.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AddonModChatPrefetchHandler extends CoreCourseActivityPrefetchHandlerBase {
|
||||
name = 'AddonModChat';
|
||||
modName = 'chat';
|
||||
component = AddonModChatProvider.COMPONENT;
|
||||
|
||||
constructor(translate: TranslateService,
|
||||
appProvider: CoreAppProvider,
|
||||
utils: CoreUtilsProvider,
|
||||
courseProvider: CoreCourseProvider,
|
||||
filepoolProvider: CoreFilepoolProvider,
|
||||
sitesProvider: CoreSitesProvider,
|
||||
domUtils: CoreDomUtilsProvider,
|
||||
private groupsProvider: CoreGroupsProvider,
|
||||
private userProvider: CoreUserProvider,
|
||||
private chatProvider: AddonModChatProvider) {
|
||||
|
||||
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the handler is enabled on a site level.
|
||||
*
|
||||
* @return {boolean|Promise<boolean>} A boolean, or a promise resolved with a boolean, indicating if the handler is enabled.
|
||||
*/
|
||||
isEnabled(): boolean | Promise<boolean> {
|
||||
return this.chatProvider.areSessionsAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the prefetched content.
|
||||
*
|
||||
* @param {number} moduleId The module ID.
|
||||
* @param {number} courseId The course ID the module belongs to.
|
||||
* @return {Promise<any>} Promise resolved when the data is invalidated.
|
||||
*/
|
||||
invalidateContent(moduleId: number, courseId: number): Promise<any> {
|
||||
return this.chatProvider.getChat(courseId, moduleId).then((chat) => {
|
||||
const promises = [
|
||||
this.chatProvider.invalidateAllSessions(chat.id),
|
||||
this.chatProvider.invalidateAllSessionMessages(chat.id)
|
||||
];
|
||||
|
||||
return this.utils.allPromises(promises);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate WS calls needed to determine module status (usually, to check if module is downloadable).
|
||||
* It doesn't need to invalidate check updates. It should NOT invalidate files nor all the prefetched data.
|
||||
*
|
||||
* @param {any} module Module.
|
||||
* @param {number} courseId Course ID the module belongs to.
|
||||
* @return {Promise<any>} Promise resolved when invalidated.
|
||||
*/
|
||||
invalidateModule(module: any, courseId: number): Promise<any> {
|
||||
const promises = [
|
||||
this.chatProvider.invalidateChats(courseId),
|
||||
this.courseProvider.invalidateModule(module.id)
|
||||
];
|
||||
|
||||
return this.utils.allPromises(promises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch a module.
|
||||
*
|
||||
* @param {any} module Module.
|
||||
* @param {number} courseId Course ID the module belongs to.
|
||||
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
|
||||
* @param {string} [dirPath] Path of the directory where to store all the content files.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {
|
||||
return this.prefetchPackage(module, courseId, single, this.prefetchChat.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch a chat.
|
||||
*
|
||||
* @param {any} module The module object returned by WS.
|
||||
* @param {number} courseId Course ID the module belongs to.
|
||||
* @param {boolean} single True if we're downloading a single module, false if we're downloading a whole section.
|
||||
* @param {string} siteId Site ID.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected prefetchChat(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||
// Prefetch chat and group info.
|
||||
const promises = [
|
||||
this.chatProvider.getChat(courseId, module.id, siteId),
|
||||
this.groupsProvider.getActivityGroupInfo(module.id, false, undefined, siteId)
|
||||
];
|
||||
|
||||
return Promise.all(promises).then(([chat, groupInfo]: [any, CoreGroupInfo]) => {
|
||||
const promises = [];
|
||||
|
||||
let groupIds = [0];
|
||||
if (groupInfo.groups && groupInfo.groups.length > 0) {
|
||||
groupIds = groupInfo.groups.map((group) => group.id);
|
||||
}
|
||||
|
||||
groupIds.forEach((groupId) => {
|
||||
// Prefetch complete sessions.
|
||||
promises.push(this.chatProvider.getSessions(chat.id, groupId, false, true, siteId).catch((error) => {
|
||||
// Ignore group error.
|
||||
if (error.errorcode != 'notingroup') {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}));
|
||||
|
||||
// Prefetch all sessions.
|
||||
promises.push(this.chatProvider.getSessions(chat.id, groupId, true, true, siteId).then((sessions) => {
|
||||
const promises = sessions.map((session) => this.prefetchSession(chat.id, session, 0, courseId, siteId));
|
||||
|
||||
return Promise.all(promises);
|
||||
}).catch((error) => {
|
||||
// Ignore group error.
|
||||
if (error.errorcode != 'notingroup') {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch chat session messages and user profiles.
|
||||
*
|
||||
* @param {number} chatId Chat ID.
|
||||
* @param {any} session Session object.
|
||||
* @param {number} groupId Group ID.
|
||||
* @param {number} courseId Course ID the module belongs to.
|
||||
* @param {string} siteId Site ID.
|
||||
* @return {Promise<any>} Promise resolved when done.
|
||||
*/
|
||||
protected prefetchSession(chatId: number, session: any, groupId: number, courseId: number, siteId: string): Promise<any> {
|
||||
return this.chatProvider.getSessionMessages(chatId, session.sessionstart, session.sessionend, groupId, true, siteId)
|
||||
.then((messages) => {
|
||||
const users = {};
|
||||
session.sessionusers.forEach((user) => {
|
||||
users[user.userid] = true;
|
||||
});
|
||||
messages.forEach((message) => {
|
||||
users[message.userid] = true;
|
||||
});
|
||||
const userIds = Object.keys(users).map(Number);
|
||||
|
||||
return this.userProvider.prefetchProfiles(userIds, courseId, siteId).catch(() => {
|
||||
// Ignore errors, some users might not exist.
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -345,6 +345,7 @@
|
|||
"addon.mod_book.errorchapter": "Error reading chapter of book.",
|
||||
"addon.mod_book.modulenameplural": "Books",
|
||||
"addon.mod_chat.beep": "Beep",
|
||||
"addon.mod_chat.chatreport": "Chat sessions",
|
||||
"addon.mod_chat.currentusers": "Current users",
|
||||
"addon.mod_chat.enterchat": "Click here to enter the chat now",
|
||||
"addon.mod_chat.entermessage": "Enter your message",
|
||||
|
@ -356,12 +357,16 @@
|
|||
"addon.mod_chat.messagebeepsyou": "{{$a}} has just beeped you!",
|
||||
"addon.mod_chat.messageenter": "{{$a}} has just entered this chat",
|
||||
"addon.mod_chat.messageexit": "{{$a}} has left this chat",
|
||||
"addon.mod_chat.messages": "Messages",
|
||||
"addon.mod_chat.modulenameplural": "Chats",
|
||||
"addon.mod_chat.mustbeonlinetosendmessages": "You must be online to send messages.",
|
||||
"addon.mod_chat.nomessages": "No messages yet",
|
||||
"addon.mod_chat.nosessionsfound": "No sessions found",
|
||||
"addon.mod_chat.send": "Send",
|
||||
"addon.mod_chat.sessionstart": "The next chat session will start on {{$a.date}}, ({{$a.fromnow}} from now)",
|
||||
"addon.mod_chat.showincompletesessions": "Show incomplete sessions",
|
||||
"addon.mod_chat.talk": "Talk",
|
||||
"addon.mod_chat.viewreport": "View past chat sessions",
|
||||
"addon.mod_choice.cannotsubmit": "Sorry, there was a problem submitting your choice. Please try again.",
|
||||
"addon.mod_choice.choiceoptions": "Choice options",
|
||||
"addon.mod_choice.errorgetchoice": "Error getting choice data.",
|
||||
|
@ -1294,6 +1299,7 @@
|
|||
"core.defaultvalue": "Default ({{$a}})",
|
||||
"core.delete": "Delete",
|
||||
"core.deletedoffline": "Deleted offline",
|
||||
"core.deleteduser": "Deleted user",
|
||||
"core.deleting": "Deleting",
|
||||
"core.description": "Description",
|
||||
"core.dfdaymonthyear": "MM-DD-YYYY",
|
||||
|
@ -1544,6 +1550,7 @@
|
|||
"core.noresults": "No results",
|
||||
"core.notapplicable": "n/a",
|
||||
"core.notice": "Notice",
|
||||
"core.notingroup": "Sorry, but you need to be part of a group to see this page.",
|
||||
"core.notsent": "Not sent",
|
||||
"core.now": "now",
|
||||
"core.numwords": "{{$a}} words",
|
||||
|
|
|
@ -632,10 +632,13 @@ export class CoreSite {
|
|||
error.message = this.translate.instant('core.unicodenotsupported');
|
||||
|
||||
return Promise.reject(error);
|
||||
} else if (error.exception === 'required_capability_exception' || error.errorcode === 'nopermission') {
|
||||
} else if (error.exception === 'required_capability_exception' || error.errorcode === 'nopermission' ||
|
||||
error.errorcode === 'notingroup') {
|
||||
// Translate error messages with missing strings.
|
||||
if (error.message === 'error/nopermission') {
|
||||
// This error message is returned by some web services but the string does not exist.
|
||||
error.message = this.translate.instant('core.nopermissionerror');
|
||||
} else if (error.message === 'error/notingroup') {
|
||||
error.message = this.translate.instant('core.notingroup');
|
||||
}
|
||||
|
||||
// Save the error instead of deleting the cache entry so the same content is displayed in offline.
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
"defaultvalue": "Default ({{$a}})",
|
||||
"delete": "Delete",
|
||||
"deletedoffline": "Deleted offline",
|
||||
"deleteduser": "Deleted user",
|
||||
"deleting": "Deleting",
|
||||
"description": "Description",
|
||||
"dfdaymonthyear": "MM-DD-YYYY",
|
||||
|
@ -169,6 +170,7 @@
|
|||
"noresults": "No results",
|
||||
"notapplicable": "n/a",
|
||||
"notice": "Notice",
|
||||
"notingroup": "Sorry, but you need to be part of a group to see this page.",
|
||||
"notsent": "Not sent",
|
||||
"now": "now",
|
||||
"numwords": "{{$a}} words",
|
||||
|
|
Loading…
Reference in New Issue