MOBILE-3819 core: Remove code specific for Moodle 3.1-3.4

main
Dani Palou 2021-09-03 11:51:26 +02:00
parent d944cb1978
commit 68e57c0f17
147 changed files with 436 additions and 2398 deletions

View File

@ -39,7 +39,7 @@ export class AddonBadgesProvider {
async isPluginEnabled(siteId?: string): Promise<boolean> {
const site = await CoreSites.getSite(siteId);
return site.canUseAdvancedFeature('enablebadges') && site.wsAvailable('core_course_get_user_navigation_options');
return site.canUseAdvancedFeature('enablebadges');
}
/**
@ -194,7 +194,7 @@ export type AddonBadgesUserBadge = {
targetframework?: string; // Target framework.
targetcode?: string; // Target code.
}[];
competencies?: { // @deprecated from 3.7. @since 3.6. In 3.7 it was renamed to alignment.
competencies?: { // @deprecatedonmoodle from 3.7. @since 3.6. In 3.7 it was renamed to alignment.
id?: number; // Alignment id.
badgeid?: number; // Badge id.
targetname?: string; // Target name.

View File

@ -16,10 +16,10 @@ import { Injectable } from '@angular/core';
import { CoreBlockHandlerData } from '@features/block/services/block-delegate';
import { CoreBlockOnlyTitleComponent } from '@features/block/components/only-title-block/only-title-block';
import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler';
import { AddonCalendar } from '@/addons/calendar/services/calendar';
import { CoreCourseBlock } from '@features/course/services/course';
import { Params } from '@angular/router';
import { makeSingleton } from '@singletons';
import { AddonCalendarMainMenuHandlerService } from '@addons/calendar/services/handlers/mainmenu';
/**
* Block handler.
@ -45,7 +45,7 @@ export class AddonBlockCalendarMonthHandlerService extends CoreBlockBaseHandler
title: 'addon.block_calendarmonth.pluginname',
class: 'addon-block-calendar-month',
component: CoreBlockOnlyTitleComponent,
link: AddonCalendar.getMainCalendarPagePath(),
link: AddonCalendarMainMenuHandlerService.PAGE_NAME,
linkParams: linkParams,
navOptions: {
preferCurrentTab: false,

View File

@ -16,10 +16,10 @@ import { Injectable } from '@angular/core';
import { CoreBlockHandlerData } from '@features/block/services/block-delegate';
import { CoreBlockOnlyTitleComponent } from '@features/block/components/only-title-block/only-title-block';
import { CoreBlockBaseHandler } from '@features/block/classes/base-block-handler';
import { AddonCalendar } from '@/addons/calendar/services/calendar';
import { CoreCourseBlock } from '@features/course/services/course';
import { Params } from '@angular/router';
import { makeSingleton } from '@singletons';
import { AddonCalendarMainMenuHandlerService } from '@addons/calendar/services/handlers/mainmenu';
/**
* Block handler.
@ -46,7 +46,7 @@ export class AddonBlockCalendarUpcomingHandlerService extends CoreBlockBaseHandl
title: 'addon.block_calendarupcoming.pluginname',
class: 'addon-block-calendar-upcoming',
component: CoreBlockOnlyTitleComponent,
link: AddonCalendar.getMainCalendarPagePath(),
link: AddonCalendarMainMenuHandlerService.PAGE_NAME,
linkParams: linkParams,
navOptions: {
preferCurrentTab: false,

View File

@ -248,13 +248,8 @@ export class AddonBlockTimelineProvider {
async isAvailable(siteId?: string): Promise<boolean> {
const site = await CoreSites.getSite(siteId);
// First check if dashboard is disabled.
if (CoreCoursesDashboard.isDisabledInSite(site)) {
return false;
}
return site.wsAvailable('core_calendar_get_action_events_by_courses') &&
site.wsAvailable('core_calendar_get_action_events_by_timesort');
// Check if dashboard is disabled.
return !CoreCoursesDashboard.isDisabledInSite(site);
}
/**

View File

@ -40,11 +40,12 @@ export class AddonBlogProvider {
*
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with true if enabled, resolved with false or rejected otherwise.
* @since 3.6
*/
async isPluginEnabled(siteId?: string): Promise<boolean> {
const site = await CoreSites.getSite(siteId);
return site.wsAvailable('core_blog_get_entries') &&site.canUseAdvancedFeature('enableblogs');
return site.wsAvailable('core_blog_get_entries') && site.canUseAdvancedFeature('enableblogs');
}
/**

View File

@ -38,13 +38,6 @@ function buildRoutes(injector: Injector): Routes {
},
loadChildren: () => import('@/addons/calendar/pages/index/index.module').then(m => m.AddonCalendarIndexPageModule),
},
{
path: 'list',
data: {
mainMenuTabRoot: AddonCalendarMainMenuHandlerService.PAGE_NAME,
},
loadChildren: () => import('@/addons/calendar/pages/list/list.module').then(m => m.AddonCalendarListPageModule),
},
{
path: 'settings',
loadChildren: () =>

View File

@ -28,7 +28,7 @@
<core-context-menu-item [hidden]="!canEdit || !event || !event.canedit || event.deleted" [priority]="300"
[content]="'core.edit' | translate" (action)="openEdit()" iconAction="fas-edit">
</core-context-menu-item>
<core-context-menu-item [hidden]="!canDelete || !event || !event.candelete || event.deleted" [priority]="200"
<core-context-menu-item [hidden]="!event || !event.candelete || event.deleted" [priority]="200"
[content]="'core.delete' | translate" (action)="deleteEvent()"
iconAction="fas-trash"></core-context-menu-item>
<core-context-menu-item [hidden]="!event || !event.deleted" [priority]="200" [content]="'core.restore' | translate"

View File

@ -17,16 +17,12 @@ import { IonRefresher } from '@ionic/angular';
import { AlertOptions } from '@ionic/core';
import {
AddonCalendar,
AddonCalendarEvent,
AddonCalendarEventBase,
AddonCalendarEventToDisplay,
AddonCalendarGetEventsEvent,
AddonCalendarProvider,
} from '../../services/calendar';
import { AddonCalendarHelper } from '../../services/calendar-helper';
import { AddonCalendarOffline } from '../../services/calendar-offline';
import { AddonCalendarSync, AddonCalendarSyncEvents, AddonCalendarSyncProvider } from '../../services/calendar-sync';
import { CoreCourses } from '@features/courses/services/courses';
import { CoreApp } from '@services/app';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreDomUtils } from '@services/utils/dom';
@ -82,7 +78,6 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
defaultTime = 0;
reminders: AddonCalendarReminderDBRecord[] = [];
canEdit = false;
canDelete = false;
hasOffline = false;
isOnline = false;
syncIcon = CoreConstants.ICON_LOADING; // Sync icon.
@ -99,9 +94,8 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
this.currentSiteId = CoreSites.getCurrentSiteId();
this.isSplitViewOn = this.svComponent?.outletActivated;
// Check if site supports editing and deleting. No need to check allowed types, event.canedit already does it.
// Check if site supports editing. No need to check allowed types, event.canedit already does it.
this.canEdit = AddonCalendar.canEditEventsInSite();
this.canDelete = AddonCalendar.canDeleteEventsInSite();
// Listen for event edited. If current event is edited, reload the data.
this.editEventObserver = CoreEvents.on(AddonCalendarProvider.EDIT_EVENT_EVENT, (data) => {
@ -168,8 +162,6 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
* @return Promise resolved when done.
*/
async fetchEvent(sync = false, showErrors = false): Promise<void> {
const currentSite = CoreSites.getCurrentSite();
const canGetById = AddonCalendar.isGetEventByIdAvailableInSite();
let deleted = false;
this.isOnline = CoreApp.isOnline();
@ -209,13 +201,8 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
}
try {
let event: AddonCalendarEvent | AddonCalendarEventBase | AddonCalendarGetEventsEvent;
// Get the event data.
if (canGetById) {
event = await AddonCalendar.getEventById(this.eventId);
} else {
event = await AddonCalendar.getEvent(this.eventId);
}
const event = await AddonCalendar.getEventById(this.eventId);
this.event = AddonCalendarHelper.formatEventData(event);
try {
@ -254,9 +241,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
}
// Get the module URL.
if (canGetById) {
this.moduleUrl = this.event!.url || '';
}
this.moduleUrl = this.event!.url || '';
}
const promises: Promise<void>[] = [];
@ -264,24 +249,10 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
const courseId = this.event.courseid;
if (courseId != this.siteHomeId) {
// If the event belongs to a course, get the course name and the URL to view it.
if (canGetById && this.event.course) {
if (this.event.course) {
this.courseId = this.event.course.id;
this.courseName = this.event.course.fullname;
this.courseUrl = this.event.course.viewurl;
} else if (!canGetById && this.event.courseid ) {
// Retrieve the course.
promises.push(CoreCourses.getUserCourse(this.event.courseid, true).then((course) => {
this.courseId = course.id;
this.courseName = course.fullname;
this.courseUrl = currentSite ? CoreTextUtils.concatenatePaths(
currentSite.siteUrl,
'/course/view.php?id=' + this.courseId,
) : '';
return;
}).catch(() => {
// Error getting course, just don't show the course name.
}));
}
}
@ -299,7 +270,7 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy {
}));
}
if (canGetById && this.event.iscategoryevent && this.event.category) {
if (this.event.iscategoryevent && this.event.category) {
this.categoryPath = this.event.category.nestedname;
}

View File

@ -1,96 +0,0 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button [text]="'core.back' | translate"></ion-back-button>
</ion-buttons>
<h1>{{ 'addon.calendar.calendarevents' | translate }}</h1>
<ion-buttons slot="end">
<ion-button fill="clear" (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate">
<ion-icon slot="icon-only" name="fas-filter" aria-hidden="true"></ion-icon>
</ion-button>
<core-context-menu>
<core-context-menu-item [hidden]="!notificationsEnabled" [priority]="600"
[content]="'core.settings.settings' | translate" (action)="openSettings()" iconAction="fas-cogs">
</core-context-menu-item>
<core-context-menu-item [hidden]="!eventsLoaded || !hasOffline || !isOnline" [priority]="400"
[content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(undefined, $event, true)"
[iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
</core-context-menu>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-refresher slot="fixed" [disabled]="!eventsLoaded" (ionRefresh)="doRefresh($event.target)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-loading [hideUntil]="eventsLoaded">
<!-- There is data to be synchronized -->
<ion-card class="core-warning-card" *ngIf="hasOffline">
<ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}</ion-label>
</ion-item>
</ion-card>
<core-empty-box *ngIf="!filteredEvents || !filteredEvents.length" icon="fas-calendar"
[message]="'addon.calendar.noevents' | translate">
</core-empty-box>
<ion-list *ngIf="filteredEvents && filteredEvents.length" class="ion-no-margin">
<ng-container *ngFor="let event of filteredEvents">
<ion-item-divider *ngIf="event.showDate">
<ion-label><p class="item-heading">{{ event.timestart * 1000 | coreFormatDate: "strftimedayshort" }}</p></ion-label>
</ion-item-divider>
<ion-item class="addon-calendar-event ion-text-wrap" [attr.aria-label]="event.name" (click)="gotoEvent(event.id)"
[attr.aria-current]="event.id == eventId ? 'page' : 'false'"
[ngClass]="['addon-calendar-eventtype-'+event.eventtype]" button detail="true">
<img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon" alt=""
role="presentation">
<ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start"
aria-hidden="true">
</ion-icon>
<ion-label>
<p class="item-heading">
<!-- Add the icon title so accessibility tools read it. -->
<span class="sr-only">
{{ 'addon.calendar.type' + event.formattedType | translate }}
<span class="sr-only" *ngIf="event.moduleIcon && event.iconTitle">{{ event.iconTitle }}</span>
</span>
<core-format-text [text]="event.name" [contextLevel]="event.contextLevel"
[contextInstanceId]="event.contextInstanceId">
</core-format-text>
</p>
<p>
{{ event.timestart * 1000 | coreFormatDate: "strftimetime" }}
<span *ngIf="event.timeduration && event.endsSameDay">
- {{ (event.timestart + event.timeduration) * 1000 | coreFormatDate: "strftimetime" }}
</span>
<span *ngIf="event.timeduration && !event.endsSameDay">
- {{ (event.timestart + event.timeduration) * 1000 | coreFormatDate: "strftimedatetimeshort" }}
</span>
</p>
</ion-label>
<ion-note *ngIf="event.offline && !event.deleted" slot="end">
<ion-icon name="fas-clock" aria-hidden="true"></ion-icon>
<span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span>
</ion-note>
<ion-note *ngIf="event.deleted" slot="end">
<ion-icon name="fas-trash" aria-hidden="true"></ion-icon>
<span class="ion-text-wrap">{{ 'core.deletedoffline' | translate }}</span>
</ion-note>
</ion-item>
</ng-container>
</ion-list>
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreEvents($event)" [error]="loadMoreError">
</core-infinite-loading>
</core-loading>
<!-- Create a calendar event. -->
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canCreate">
<ion-fab-button (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate">
<ion-icon name="fas-plus" aria-hidden="true"></ion-icon>
<span class="sr-only">{{ 'addon.calendar.newevent' | translate }}</span>
</ion-fab-button>
</ion-fab>
</ion-content>

View File

@ -1,60 +0,0 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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 { RouterModule, Routes } from '@angular/router';
import { AddonCalendarEventRoute, AddonCalendarEditRoute } from '@addons/calendar/calendar-lazy.module';
import { conditionalRoutes } from '@/app/app-routing.module';
import { CoreScreen } from '@services/screen';
import { CoreSharedModule } from '@/core/shared.module';
import { AddonCalendarListPage } from './list.page';
const splitviewRoutes = [AddonCalendarEditRoute, AddonCalendarEventRoute];
const mobileRoutes: Routes = [
{
path: '',
component: AddonCalendarListPage,
},
...splitviewRoutes,
];
const tabletRoutes: Routes = [
{
path: '',
component: AddonCalendarListPage,
children: [
...splitviewRoutes,
],
},
];
const routes: Routes = [
...conditionalRoutes(mobileRoutes, () => CoreScreen.isMobile),
...conditionalRoutes(tabletRoutes, () => CoreScreen.isTablet),
];
@NgModule({
imports: [
RouterModule.forChild(routes),
CoreSharedModule,
],
declarations: [
AddonCalendarListPage,
],
exports: [RouterModule],
})
export class AddonCalendarListPageModule {}

View File

@ -1,643 +0,0 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// 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, OnDestroy, OnInit } from '@angular/core';
import { IonContent, IonRefresher } from '@ionic/angular';
import {
AddonCalendarProvider,
AddonCalendar,
AddonCalendarEventToDisplay,
} from '../../services/calendar';
import { AddonCalendarOffline } from '../../services/calendar-offline';
import { AddonCalendarFilter, AddonCalendarHelper } from '../../services/calendar-helper';
import { AddonCalendarSync, AddonCalendarSyncProvider } from '../../services/calendar-sync';
import { CoreCategoryData, CoreCourses, CoreEnrolledCourseData } from '@features/courses/services/courses';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreTimeUtils } from '@services/utils/time';
import { CoreSites } from '@services/sites';
import { CoreLocalNotifications } from '@services/local-notifications';
import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreApp } from '@services/app';
import moment from 'moment';
import { CoreConstants } from '@/core/constants';
import { AddonCalendarFilterPopoverComponent } from '../../components/filter/filter';
import { Params } from '@angular/router';
import { Subscription } from 'rxjs';
import { Network, NgZone } from '@singletons';
import { CoreCoursesHelper } from '@features/courses/services/courses-helper';
import { CoreUtils } from '@services/utils/utils';
import { CoreNavigator } from '@services/navigator';
/**
* Page that displays the list of calendar events.
*/
@Component({
selector: 'page-addon-calendar-list',
templateUrl: 'list.html',
styleUrls: ['../../calendar-common.scss', 'list.scss'],
})
export class AddonCalendarListPage implements OnInit, OnDestroy {
@ViewChild(IonContent) content?: IonContent;
protected initialTime = 0;
protected daysLoaded = 0;
protected emptyEventsTimes = 0; // Variable to identify consecutive calls returning 0 events.
protected categoriesRetrieved = false;
protected getCategories = false;
protected categories: { [id: number]: CoreCategoryData } = {};
protected siteHomeId: number;
protected currentSiteId: string;
protected onlineEvents: AddonCalendarEventToDisplay[] = [];
protected offlineEvents: AddonCalendarEventToDisplay[] = [];
protected deletedEvents: number [] = [];
// Observers.
protected obsDefaultTimeChange?: CoreEventObserver;
protected newEventObserver: CoreEventObserver;
protected discardedObserver: CoreEventObserver;
protected editEventObserver: CoreEventObserver;
protected deleteEventObserver: CoreEventObserver;
protected undeleteEventObserver: CoreEventObserver;
protected syncObserver: CoreEventObserver;
protected manualSyncObserver: CoreEventObserver;
protected filterChangedObserver: CoreEventObserver;
protected onlineObserver: Subscription;
eventId?: number; // Selected EventId on list
courses: Partial<CoreEnrolledCourseData>[] = [];
eventsLoaded = false;
events: AddonCalendarEventToDisplay[] = []; // Events (both online and offline).
notificationsEnabled = false;
filteredEvents: AddonCalendarEventToDisplay[] = [];
canLoadMore = false;
loadMoreError = false;
canCreate = false;
hasOffline = false;
isOnline = false;
syncIcon = CoreConstants.ICON_LOADING;
filter: AddonCalendarFilter = {
filtered: false,
courseId: undefined,
categoryId: undefined,
course: true,
group: true,
site: true,
user: true,
category: true,
};
constructor() {
this.siteHomeId = CoreSites.getCurrentSiteHomeId();
this.notificationsEnabled = CoreLocalNotifications.isAvailable();
this.currentSiteId = CoreSites.getCurrentSiteId();
if (this.notificationsEnabled) {
// Re-schedule events if default time changes.
this.obsDefaultTimeChange = CoreEvents.on(AddonCalendarProvider.DEFAULT_NOTIFICATION_TIME_CHANGED, () => {
AddonCalendar.scheduleEventsNotifications(this.onlineEvents);
}, this.currentSiteId);
}
// Listen for events added. When an event is added, reload the data.
this.newEventObserver = CoreEvents.on(AddonCalendarProvider.NEW_EVENT_EVENT, (data) => {
if (data && data.eventId) {
this.eventsLoaded = false;
this.refreshEvents(true, false);
}
}, this.currentSiteId);
// Listen for new event discarded event. When it does, reload the data.
this.discardedObserver = CoreEvents.on(AddonCalendarProvider.NEW_EVENT_DISCARDED_EVENT, () => {
this.eventsLoaded = false;
this.refreshEvents(true, false);
}, this.currentSiteId);
// Listen for events edited. When an event is edited, reload the data.
this.editEventObserver = CoreEvents.on(AddonCalendarProvider.EDIT_EVENT_EVENT, (data) => {
if (data && data.eventId) {
this.eventsLoaded = false;
this.refreshEvents(true, false);
}
}, this.currentSiteId);
// Refresh data if calendar events are synchronized automatically.
this.syncObserver = CoreEvents.on(AddonCalendarSyncProvider.AUTO_SYNCED, () => {
this.eventsLoaded = false;
this.refreshEvents();
}, this.currentSiteId);
// Refresh data if calendar events are synchronized manually but not by this page.
this.manualSyncObserver = CoreEvents.on(AddonCalendarSyncProvider.MANUAL_SYNCED, (data) => {
if (data && data.source != 'list') {
this.eventsLoaded = false;
this.refreshEvents();
}
}, this.currentSiteId);
// Update the list when an event is deleted.
this.deleteEventObserver = CoreEvents.on(
AddonCalendarProvider.DELETED_EVENT_EVENT,
(data) => {
if (data && !data.sent) {
// Event was deleted in offline. Just mark it as deleted, no need to refresh.
this.markAsDeleted(data.eventId, true);
this.deletedEvents.push(data.eventId);
this.hasOffline = true;
} else {
// Event deleted, refresh the view.
this.eventsLoaded = false;
this.refreshEvents();
}
},
this.currentSiteId,
);
// Listen for events "undeleted" (offline).
this.undeleteEventObserver = CoreEvents.on(
AddonCalendarProvider.UNDELETED_EVENT_EVENT,
(data) => {
if (!data || !data.eventId) {
return;
}
// Mark it as undeleted, no need to refresh.
this.markAsDeleted(data.eventId, false);
// Remove it from the list of deleted events if it's there.
const index = this.deletedEvents.indexOf(data.eventId);
if (index != -1) {
this.deletedEvents.splice(index, 1);
}
this.hasOffline = !!this.offlineEvents.length || !!this.deletedEvents.length;
},
this.currentSiteId,
);
this.filterChangedObserver =
CoreEvents.on(AddonCalendarProvider.FILTER_CHANGED_EVENT, async (data) => {
this.filter = data;
// Course viewed has changed, check if the user can create events for this course calendar.
this.canCreate = await AddonCalendarHelper.canEditEvents(this.filter.courseId);
this.filterEvents();
this.content?.scrollToTop();
});
// Refresh online status when changes.
this.onlineObserver = Network.onChange().subscribe(() => {
// Execute the callback in the Angular zone, so change detection doesn't stop working.
NgZone.run(() => {
this.isOnline = CoreApp.isOnline();
});
});
}
/**
* View loaded.
*/
async ngOnInit(): Promise<void> {
this.filter.courseId = CoreNavigator.getRouteNumberParam('courseId');
this.syncIcon = CoreConstants.ICON_LOADING;
await this.fetchData(false, true, false);
}
/**
* Fetch all the data required for the view.
*
* @param refresh Empty events array first.
* @param sync Whether it should try to synchronize offline events.
* @param showErrors Whether to show sync errors to the user.
* @return Promise resolved when done.
*/
async fetchData(refresh = false, sync = false, showErrors = false): Promise<void> {
this.initialTime = CoreTimeUtils.timestamp();
this.daysLoaded = 0;
this.emptyEventsTimes = 0;
this.isOnline = CoreApp.isOnline();
if (sync) {
// Try to synchronize offline events.
try {
const result = await AddonCalendarSync.syncEvents();
if (result.warnings && result.warnings.length) {
CoreDomUtils.showErrorModal(result.warnings[0]);
}
if (result.updated) {
// Trigger a manual sync event.
result.source = 'list';
CoreEvents.trigger(
AddonCalendarSyncProvider.MANUAL_SYNCED,
result,
this.currentSiteId,
);
}
} catch (error) {
if (showErrors) {
CoreDomUtils.showErrorModalDefault(error, 'core.errorsync', true);
}
}
}
try {
const promises: Promise<void>[] = [];
this.hasOffline = false;
promises.push(AddonCalendarHelper.canEditEvents(this.filter.courseId).then((canEdit) => {
this.canCreate = canEdit;
return;
}));
// Load courses for the popover.
promises.push(CoreCoursesHelper.getCoursesForPopover(this.filter.courseId).then((result) => {
this.courses = result.courses;
return this.fetchEvents(refresh);
}));
// Get offline events.
promises.push(AddonCalendarOffline.getAllEditedEvents().then((offlineEvents) => {
this.hasOffline = this.hasOffline || !!offlineEvents.length;
// Format data and sort by timestart.
const events: AddonCalendarEventToDisplay[] = offlineEvents.map((event) =>
AddonCalendarHelper.formatOfflineEventData(event));
this.offlineEvents = AddonCalendarHelper.sortEvents(events);
return;
}));
// Get events deleted in offline.
promises.push(AddonCalendarOffline.getAllDeletedEventsIds().then((ids) => {
this.hasOffline = this.hasOffline || !!ids.length;
this.deletedEvents = ids;
return;
}));
await Promise.all(promises);
} catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevents', true);
}
this.eventsLoaded = true;
this.syncIcon = CoreConstants.ICON_SYNC;
}
/**
* Fetches the events and updates the view.
*
* @param refresh Empty events array first.
* @return Promise resolved when done.
*/
async fetchEvents(refresh = false): Promise<void> {
this.loadMoreError = false;
try {
const onlineEventsTemp =
await AddonCalendar.getEventsList(this.initialTime, this.daysLoaded, AddonCalendarProvider.DAYS_INTERVAL);
if (onlineEventsTemp.length === 0) {
this.emptyEventsTimes++;
if (this.emptyEventsTimes > 5) { // Stop execution if we retrieve empty list 6 consecutive times.
this.canLoadMore = false;
if (refresh) {
this.onlineEvents = [];
this.filteredEvents = [];
this.events = this.offlineEvents;
}
} else {
// No events returned, load next events.
this.daysLoaded += AddonCalendarProvider.DAYS_INTERVAL;
return this.fetchEvents();
}
} else {
const onlineEvents = onlineEventsTemp.map((event) => AddonCalendarHelper.formatEventData(event));
// Get the merged events of this period.
const events = this.mergeEvents(onlineEvents);
this.getCategories = this.shouldLoadCategories(onlineEvents);
if (refresh) {
this.onlineEvents = onlineEvents;
this.events = events;
} else {
// Filter events with same ID. Repeated events are returned once per WS call, show them only once.
this.onlineEvents = CoreUtils.mergeArraysWithoutDuplicates(this.onlineEvents, onlineEvents, 'id');
this.events = CoreUtils.mergeArraysWithoutDuplicates(this.events, events, 'id');
}
this.filterEvents();
// Calculate which evemts need to display the date.
this.filteredEvents.forEach((event, index) => {
event.showDate = this.showDate(event, this.filteredEvents[index - 1]);
event.endsSameDay = this.endsSameDay(event);
});
this.canLoadMore = true;
// Schedule notifications for the events retrieved (might have new events).
AddonCalendar.scheduleEventsNotifications(this.onlineEvents);
this.daysLoaded += AddonCalendarProvider.DAYS_INTERVAL;
}
} catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'addon.calendar.errorloadevents', true);
this.loadMoreError = true; // Set to prevent infinite calls with infinite-loading.
}
// Success retrieving events. Get categories if needed.
if (this.getCategories) {
this.getCategories = false;
return this.loadCategories();
}
}
/**
* Function to load more events.
*
* @param infiniteComplete Infinite scroll complete function. Only used from core-infinite-loading.
* @return Resolved when done.
*/
loadMoreEvents(infiniteComplete?: () => void ): void {
this.fetchEvents().finally(() => {
infiniteComplete && infiniteComplete();
});
}
protected filterEvents(): void {
this.filteredEvents = AddonCalendarHelper.getFilteredEvents(this.events, this.filter, this.categories);
}
/**
* Returns if the current state should load categories or not.
*
* @param events Events to parse.
* @return True if categories should be loaded.
*/
protected shouldLoadCategories(events: AddonCalendarEventToDisplay[]): boolean {
if (this.categoriesRetrieved || this.getCategories) {
// Use previous value
return this.getCategories;
}
// Categories not loaded yet. We should get them if there's any category event.
const found = events.some((event) => typeof event.categoryid != 'undefined' && event.categoryid > 0);
return found || this.getCategories;
}
/**
* Load categories to be able to filter events.
*
* @return Promise resolved when done.
*/
protected async loadCategories(): Promise<void> {
try {
const cats = await CoreCourses.getCategories(0, true);
this.categoriesRetrieved = true;
this.categories = {};
// Index categories by ID.
cats.forEach((category) => {
this.categories[category.id] = category;
});
} catch {
// Ignore errors.
}
}
/**
* Merge a period of online events with the offline events of that period.
*
* @param onlineEvents Online events.
* @return Merged events.
*/
protected mergeEvents(onlineEvents: AddonCalendarEventToDisplay[]): AddonCalendarEventToDisplay[] {
if (!this.offlineEvents.length && !this.deletedEvents.length) {
// No offline events, nothing to merge.
return onlineEvents;
}
const start = this.initialTime + (CoreConstants.SECONDS_DAY * this.daysLoaded);
const end = start + (CoreConstants.SECONDS_DAY * AddonCalendarProvider.DAYS_INTERVAL) - 1;
let result = onlineEvents;
if (this.deletedEvents.length) {
// Mark as deleted the events that were deleted in offline.
result.forEach((event) => {
event.deleted = this.deletedEvents.indexOf(event.id) != -1;
});
}
if (this.offlineEvents.length) {
// Remove the online events that were modified in offline.
result = result.filter((event) => {
const offlineEvent = this.offlineEvents.find((ev) => ev.id == event.id);
return !offlineEvent;
});
}
// Now get the offline events that belong to this period.
const periodOfflineEvents = this.offlineEvents.filter((event) => {
if (this.daysLoaded == 0 && event.timestart < start) {
// Display offline events that are previous to current time to allow editing them.
return true;
}
return (event.timestart >= start || event.timestart + event.timeduration >= start) && event.timestart <= end;
});
// Merge both arrays and sort them.
result = result.concat(periodOfflineEvents);
return AddonCalendarHelper.sortEvents(result);
}
/**
* Refresh the data.
*
* @param refresher Refresher.
* @param done Function to call when done.
* @param showErrors Whether to show sync errors to the user.
* @return Promise resolved when done.
*/
async doRefresh(refresher?: IonRefresher, done?: () => void, showErrors?: boolean): Promise<void> {
if (!this.eventsLoaded) {
return;
}
await this.refreshEvents(true, showErrors).finally(() => {
refresher?.complete();
done && done();
});
}
/**
* Refresh the events.
*
* @param sync Whether it should try to synchronize offline events.
* @param showErrors Whether to show sync errors to the user.
* @return Promise resolved when done.
*/
async refreshEvents(sync?: boolean, showErrors?: boolean): Promise<void> {
this.syncIcon = CoreConstants.ICON_LOADING;
const promises: Promise<void>[] = [];
promises.push(AddonCalendar.invalidateEventsList());
promises.push(AddonCalendar.invalidateAllowedEventTypes());
if (this.categoriesRetrieved) {
promises.push(CoreCourses.invalidateCategories(0, true));
this.categoriesRetrieved = false;
}
await Promise.all(promises).finally(() => this.fetchData(true, sync, showErrors));
}
/**
* Check date should be shown on event list for the current event.
* If date has changed from previous to current event it should be shown.
*
* @param event Current event where to show the date.
* @param prevEvent Previous event where to compare the date with.
* @return If date has changed and should be shown.
*/
protected showDate(event: AddonCalendarEventToDisplay, prevEvent?: AddonCalendarEventToDisplay): boolean {
if (!prevEvent) {
// First event, show it.
return true;
}
// Check if day has changed.
return !moment(event.timestart * 1000).isSame(prevEvent.timestart * 1000, 'day');
}
/**
* Check if event ends the same date or not.
*
* @param event Event info.
* @return If date has changed and should be shown.
*/
protected endsSameDay(event: AddonCalendarEventToDisplay): 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');
}
/**
* Show the context menu.
*
* @param event Event.
*/
async openFilter(event: MouseEvent): Promise<void> {
await CoreDomUtils.openPopover({
component: AddonCalendarFilterPopoverComponent,
componentProps: {
courses: this.courses,
filter: this.filter,
},
event,
});
}
/**
* Open page to create/edit an event.
*
* @param eventId Event ID to edit.
*/
openEdit(eventId?: number): void {
this.eventId = undefined;
eventId = eventId || 0;
const params: Params = {};
if (this.filter.courseId) {
params.courseId = this.filter.courseId;
}
CoreNavigator.navigateToSitePath(`calendar/edit/${eventId}`, { params });
}
/**
* Open calendar events settings.
*/
openSettings(): void {
CoreNavigator.navigateToSitePath('/calendar/settings');
}
/**
* Navigate to a particular event.
*
* @param eventId Event to load.
*/
gotoEvent(eventId: number): void {
this.eventId = eventId;
if (eventId <= 0) {
// It's an offline event, go to the edit page.
this.openEdit(eventId);
} else {
CoreNavigator.navigateToSitePath(`/calendar/event/${eventId}`);
}
}
/**
* Find an event and mark it as deleted.
*
* @param eventId Event ID.
* @param deleted Whether to mark it as deleted or not.
*/
protected markAsDeleted(eventId: number, deleted: boolean): void {
const event = this.onlineEvents.find((event) => event.id == eventId);
if (event) {
event.deleted = deleted;
}
}
/**
* Page destroyed.
*/
ngOnDestroy(): void {
this.obsDefaultTimeChange?.off();
this.newEventObserver?.off();
this.discardedObserver?.off();
this.editEventObserver?.off();
this.deleteEventObserver?.off();
this.undeleteEventObserver?.off();
this.syncObserver?.off();
this.manualSyncObserver?.off();
this.filterChangedObserver?.off();
this.onlineObserver?.unsubscribe();
}
}

View File

@ -1,5 +0,0 @@
:host {
ion-note {
max-width: 30%;
}
}

View File

@ -125,36 +125,6 @@ export class AddonCalendarProvider {
},
];
/**
* Check if a certain site allows deleting events.
*
* @param siteId Site Id. If not defined, use current site.
* @return Promise resolved with true if can delete.
* @since 3.3
*/
async canDeleteEvents(siteId?: string): Promise<boolean> {
try {
const site = await CoreSites.getSite(siteId);
return this.canDeleteEventsInSite(site);
} catch {
return false;
}
}
/**
* Check if a certain site allows deleting events.
*
* @param site Site. If not defined, use current site.
* @return Whether events can be deleted.
* @since 3.3
*/
canDeleteEventsInSite(site?: CoreSite): boolean {
site = site || CoreSites.getCurrentSite();
return !!site?.wsAvailable('core_calendar_delete_calendar_events');
}
/**
* Check if a certain site allows creating and editing events.
*
@ -186,67 +156,6 @@ export class AddonCalendarProvider {
return !!site?.isVersionGreaterEqualThan('3.7.1');
}
/**
* Check if a certain site allows viewing events in monthly view.
*
* @param siteId Site Id. If not defined, use current site.
* @return Promise resolved with true if monthly view is supported.
* @since 3.4
*/
async canViewMonth(siteId?: string): Promise<boolean> {
try {
const site = await CoreSites.getSite(siteId);
return this.canViewMonthInSite(site);
} catch {
return false;
}
}
/**
* Check if a certain site allows viewing events in monthly view.
*
* @param site Site. If not defined, use current site.
* @return Whether monthly view is supported.
* @since 3.4
*/
canViewMonthInSite(site?: CoreSite): boolean {
site = site || CoreSites.getCurrentSite();
return !!site?.wsAvailable('core_calendar_get_calendar_monthly_view');
}
/**
* Gets the site main calendar page path.
*
* @param site Site. If not defined, use current site.
* @return Main calendar page path of the site.
*/
getMainCalendarPagePath(site?: CoreSite): string {
return AddonCalendarMainMenuHandlerService.PAGE_NAME + (this.canViewMonthInSite(site) ? '' : '/list');
}
/**
* Removes expired events from local DB.
*
* @param siteId ID of the site the event belongs to. If not defined, use current site.
* @return Promise resolved when done.
*/
async cleanExpiredEvents(siteId?: string): Promise<void> {
const site = await CoreSites.getSite(siteId);
if (this.canViewMonthInSite(site)) {
// Site supports monthly view, don't clean expired events because user can see past events.
return;
}
const events = await site.getDb().getRecordsSelect<AddonCalendarEventDBRecord>(
EVENTS_TABLE,
'timestart + timeduration < ?',
[CoreTimeUtils.timestamp()],
);
await Promise.all(events.map((event) => this.deleteLocalEvent(event.id!, siteId)));
}
/**
* Delete an event.
*
@ -367,12 +276,8 @@ export class AddonCalendarProvider {
return;
}
// Check which page we should load.
const site = await CoreSites.getSite(notification.siteId);
const pageName = this.getMainCalendarPagePath(site);
CoreNavigator.navigateToSitePath(
pageName,
AddonCalendarMainMenuHandlerService.PAGE_NAME,
{
siteId: notification.siteId,
preferCurrentTab: false,
@ -695,7 +600,6 @@ export class AddonCalendarProvider {
* @param id Event ID.
* @param siteId ID of the site. If not defined, use current site.
* @return Promise resolved when the event data is retrieved.
* @since 3.4
*/
async getEventById(id: number, siteId?: string): Promise<AddonCalendarEvent> {
const site = await CoreSites.getSite(siteId);
@ -742,10 +646,6 @@ export class AddonCalendarProvider {
const record: AddonCalendarGetEventsEvent | AddonCalendarEvent | AddonCalendarEventDBRecord =
await site.getDb().getRecord(EVENTS_TABLE, { id: id });
if (!this.isGetEventByIdAvailableInSite(site)) {
return record as AddonCalendarGetEventsEvent;
}
const eventConverted = record as AddonCalendarEvent;
const originalEvent = record as AddonCalendarGetEventsEvent;
const recordAsRecord = record as AddonCalendarEventDBRecord;
@ -994,10 +894,6 @@ export class AddonCalendarProvider {
};
const response: AddonCalendarGetCalendarEventsWSResponse =
await site.read('core_calendar_get_calendar_events', params, preSets);
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.
this.storeEventsInLocalDB(response.events, siteId);
}
return response.events;
}
@ -1059,12 +955,8 @@ export class AddonCalendarProvider {
const params: AddonCalendarGetCalendarMonthlyViewWSParams = {
year: year,
month: month,
mini: true, // Set mini to 1 to prevent returning the course selector HTML.
};
// This parameter requires Moodle 3.5.
if (site.isVersionGreaterEqualThan('3.5')) {
// Set mini to 1 to prevent returning the course selector HTML.
params.mini = true;
}
if (courseId) {
params.courseid = courseId;
}
@ -1406,36 +1298,6 @@ export class AddonCalendarProvider {
return this.isCalendarDisabledInSite(site);
}
/**
* Check if the get event by ID WS is available.
*
* @param siteId Site Id. If not defined, use current site.
* @return Promise resolved with true if available.
* @since 3.4
*/
async isGetEventByIdAvailable(siteId?: string): Promise<boolean> {
try {
const site = await CoreSites.getSite(siteId);
return this.isGetEventByIdAvailableInSite(site);
} catch {
return false;
}
}
/**
* Check if the get event by ID WS is available in a certain site.
*
* @param site Site. If not defined, use current site.
* @return Whether it's available.
* @since 3.4
*/
isGetEventByIdAvailableInSite(site?: CoreSite): boolean {
site = site || CoreSites.getCurrentSite();
return !!site?.wsAvailable('core_calendar_get_calendar_event_by_id');
}
/**
* Get the next events for all the sites and schedules their notifications.
* If an event notification time is 0, cancel its scheduled notification (if any).
@ -1450,7 +1312,7 @@ export class AddonCalendarProvider {
const siteIds = await CoreSites.getSitesIds();
const promises = siteIds.map((siteId: string) => this.cleanExpiredEvents(siteId).then(async() => {
const promises = siteIds.map((siteId: string) => async () => {
if (notificationsEnabled) {
// Check if calendar is disabled for the site.
const disabled = await this.isDisabled(siteId);
@ -1462,7 +1324,7 @@ export class AddonCalendarProvider {
}
return;
}));
});
await Promise.all(promises);
}
@ -1995,7 +1857,7 @@ export type AddonCalendarMonth = {
date: CoreWSDate;
periodname: string; // Periodname.
includenavigation: boolean; // Includenavigation.
initialeventsloaded: boolean; // @since 3.5. Initialeventsloaded.
initialeventsloaded: boolean; // Initialeventsloaded.
previousperiod: CoreWSDate;
previousperiodlink: string; // Previousperiodlink.
previousperiodname: string; // Previousperiodname.
@ -2151,7 +2013,7 @@ export type AddonCalendarGetEventsEvent = {
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).
categoryid?: number; // Category id (only for category events).
groupid: number; // Group id.
userid: number; // User id.
repeatid: number; // Repeat id.

View File

@ -46,7 +46,7 @@ export class AddonCalendarMainMenuHandlerService implements CoreMainMenuHandler
return {
icon: 'far-calendar',
title: 'addon.calendar.calendar',
page: AddonCalendar.getMainCalendarPagePath(),
page: AddonCalendarMainMenuHandlerService.PAGE_NAME,
class: 'addon-calendar-handler',
};
}

View File

@ -111,13 +111,9 @@ export class AddonCalendarViewLinkHandlerService extends CoreContentLinksHandler
return false;
}
return AddonCalendar.isDisabled(siteId).then((disabled) => {
if (disabled) {
return false;
}
const disabled = await AddonCalendar.isDisabled(siteId);
return AddonCalendar.canViewMonth(siteId);
});
return !disabled;
}
}

View File

@ -125,17 +125,6 @@ export class AddonMessageOutputAirnotifierProvider {
return site.invalidateWsCacheForKey(this.getUserDevicesCacheKey());
}
/**
* Returns whether or not the plugin is enabled for the current site.
*
* @return True if enabled, false otherwise.
* @since 3.2
*/
isEnabled(): boolean {
return CoreSites.wsAvailableInCurrentSite('message_airnotifier_enable_device') &&
CoreSites.wsAvailableInCurrentSite('message_airnotifier_get_user_devices');
}
}
export const AddonMessageOutputAirnotifier = makeSingleton(AddonMessageOutputAirnotifierProvider);

View File

@ -15,7 +15,6 @@
import { Injectable } from '@angular/core';
import { AddonMessageOutputHandler, AddonMessageOutputHandlerData } from '@addons/messageoutput/services/messageoutput-delegate';
import { AddonMessageOutputAirnotifierProvider } from '../airnotifier';
import { makeSingleton } from '@singletons';
/**
@ -29,15 +28,13 @@ export class AddonMessageOutputAirnotifierHandlerService implements AddonMessage
name = 'AddonMessageOutputAirnotifier';
processorName = 'airnotifier';
constructor(private airnotifierProvider: AddonMessageOutputAirnotifierProvider) {}
/**
* Whether or not the module is enabled for the site.
*
* @return True if enabled, false otherwise.
*/
async isEnabled(): Promise<boolean> {
return this.airnotifierProvider.isEnabled();
return true;
}
/**

View File

@ -27,12 +27,12 @@ export const AddonMessagesDiscussionRoute: Route = {
function buildRoutes(injector: Injector): Routes {
return [
{
path: 'index', // 3.5 or lower.
path: 'index', // 3.5.
loadChildren: () =>
import('./pages/discussions-35/discussions.module').then(m => m.AddonMessagesDiscussions35PageModule),
},
{
path: 'contacts-35', // 3.5 or lower.
path: 'contacts-35', // 3.5.
loadChildren: () => import('./pages/contacts-35/contacts.module').then(m => m.AddonMessagesContacts35PageModule),
},
{

View File

@ -747,58 +747,37 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
*/
protected async markMessagesAsRead(forceMark: boolean): Promise<void> {
let readChanged = false;
let messageUnreadFound = false;
if (AddonMessages.isMarkAllMessagesReadEnabled()) {
let messageUnreadFound = false;
// Mark all messages at a time if there is any unread message.
if (forceMark) {
messageUnreadFound = true;
} else if (this.groupMessagingEnabled) {
messageUnreadFound = !!((this.conversation?.unreadcount && this.conversation?.unreadcount > 0) &&
(this.conversationId && this.conversationId > 0));
} else {
// If an unread message is found, mark all messages as read.
messageUnreadFound = this.messages.some((message) =>
message.useridfrom != this.currentUserId && ('read' in message && !message.read));
}
if (messageUnreadFound) {
this.setUnreadLabelPosition();
if (this.groupMessagingEnabled) {
await AddonMessages.markAllConversationMessagesRead(this.conversationId!);
} else {
await AddonMessages.markAllMessagesRead(this.userId);
// Mark all messages as read.
this.messages.forEach((message) => {
if ('read' in message) {
message.read = true;
}
});
}
readChanged = true;
}
// Mark all messages at a time if there is any unread message.
if (forceMark) {
messageUnreadFound = true;
} else if (this.groupMessagingEnabled) {
messageUnreadFound = !!((this.conversation?.unreadcount && this.conversation?.unreadcount > 0) &&
(this.conversationId && this.conversationId > 0));
} else {
// If an unread message is found, mark all messages as read.
messageUnreadFound = this.messages.some((message) =>
message.useridfrom != this.currentUserId && ('read' in message && !message.read));
}
if (messageUnreadFound) {
this.setUnreadLabelPosition();
const promises: Promise<void>[] = [];
// Mark each message as read one by one.
this.messages.forEach((message) => {
// If the message is unread, call AddonMessages.markMessageRead.
if (message.useridfrom != this.currentUserId && 'read' in message && !message.read) {
promises.push(AddonMessages.markMessageRead(message.id).then(() => {
readChanged = true;
if (this.groupMessagingEnabled) {
await AddonMessages.markAllConversationMessagesRead(this.conversationId!);
} else {
await AddonMessages.markAllMessagesRead(this.userId);
// Mark all messages as read.
this.messages.forEach((message) => {
if ('read' in message) {
message.read = true;
}
});
}
return;
}));
}
});
await Promise.all(promises);
readChanged = true;
}
if (readChanged) {

View File

@ -17,7 +17,7 @@
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
</ion-refresher>
<core-search-box *ngIf="search.enabled" (onSubmit)="searchMessage($event)" (onClear)="clearSearch()"
<core-search-box (onSubmit)="searchMessage($event)" (onClear)="clearSearch()"
[placeholder]=" 'addon.messages.message' | translate" autocorrect="off" spellcheck="false" lengthCheck="2"
[disabled]="!loaded" searchArea="AddonMessagesDiscussions" [autoFocus]="false"></core-search-box>

View File

@ -56,7 +56,6 @@ export class AddonMessagesDiscussions35Page implements OnInit, OnDestroy {
discussionUserId?: number;
search = {
enabled: false,
showResults: false,
results: <AddonMessagesMessageAreaContact[]> [],
loading: '',
@ -179,7 +178,6 @@ export class AddonMessagesDiscussions35Page implements OnInit, OnDestroy {
*/
protected async fetchData(): Promise<void> {
this.loadingMessage = this.loadingMessages;
this.search.enabled = AddonMessages.isSearchMessagesEnabled();
const promises: Promise<unknown>[] = [];

View File

@ -45,7 +45,7 @@ export class AddonMessagesMainMenuHandlerService implements CoreMainMenuHandler,
title: 'addon.messages.messages',
page: AddonMessagesMainMenuHandlerService.PAGE_NAME,
class: 'addon-messages-handler',
showBadge: true, // Do not check isMessageCountEnabled because we'll use fallback it not enabled.
showBadge: true,
badge: '',
badgeA11yText: 'addon.messages.unreadconversations',
loading: true,
@ -199,8 +199,7 @@ export class AddonMessagesMainMenuHandlerService implements CoreMainMenuHandler,
* @return True if is a sync process, false otherwise.
*/
isSync(): boolean {
// This is done to use only wifi if using the fallback function.
return !AddonMessages.isMessageCountEnabled() && !AddonMessages.isGroupMessagingEnabled();
return false;
}
/**

View File

@ -34,9 +34,7 @@ export class AddonMessagesSettingsHandlerService implements CoreSettingsHandler
* @return Whether or not the handler is enabled on a site level.
*/
async isEnabled(): Promise<boolean> {
const messagingEnabled = await AddonMessages.isPluginEnabled();
return messagingEnabled && AddonMessages.isMessagePreferencesEnabled();
return await AddonMessages.isPluginEnabled();
}
/**

View File

@ -1567,9 +1567,8 @@ export class AddonMessagesProvider {
self: result.types[AddonMessagesProvider.MESSAGE_CONVERSATION_TYPE_SELF] || 0,
};
} else if (this.isMessageCountEnabled()) {
// @since 3.2
const params: { useridto: number } = {
} else {
const params: AddonMessageGetUnreadConversationsCountWSParams = {
useridto: site.getUserId(),
};
const preSets: CoreSiteWSPreSets = {
@ -1577,37 +1576,11 @@ export class AddonMessagesProvider {
typeExpected: 'number',
};
const count: number = await site.read('core_message_get_unread_conversations_count', params, preSets);
const count = await site.read<number>('core_message_get_unread_conversations_count', params, preSets);
counts = { favourites: 0, individual: count, group: 0, self: 0 };
} else {
// Fallback call.
const params: AddonMessagesGetMessagesWSParams = {
read: false,
limitfrom: 0,
limitnum: AddonMessagesProvider.LIMIT_MESSAGES + 1,
useridto: site.getUserId(),
useridfrom: 0,
};
const response = await this.getMessages(params, {}, siteId);
// Count the discussions by filtering same senders.
const discussions = {};
response.messages.forEach((message) => {
discussions[message.useridto] = 1;
});
const count = Object.keys(discussions).length;
counts = {
favourites: 0,
individual: count,
group: 0,
self: 0,
orMore: count > AddonMessagesProvider.LIMIT_MESSAGES,
};
}
// Notify the new counts so all views are updated.
CoreEvents.trigger(AddonMessagesProvider.UNREAD_CONVERSATION_COUNTS_EVENT, counts, site.id);
@ -1936,8 +1909,7 @@ export class AddonMessagesProvider {
// @since 3.6
return site.invalidateWsCacheForKey(this.getCacheKeyForUnreadConversationCounts());
} else if (this.isMessageCountEnabled()) {
// @since 3.2
} else {
return site.invalidateWsCacheForKey(this.getCacheKeyForMessageCount(site.getUserId()));
}
}
@ -2016,37 +1988,6 @@ export class AddonMessagesProvider {
}
}
/**
* Returns whether or not we can mark all messages as read.
*
* @return If related WS is available on current site.
* @since 3.2
*/
isMarkAllMessagesReadEnabled(): boolean {
return CoreSites.wsAvailableInCurrentSite('core_message_mark_all_conversation_messages_as_read') ||
CoreSites.wsAvailableInCurrentSite('core_message_mark_all_messages_as_read');
}
/**
* Returns whether or not we can count unread messages.
*
* @return True if enabled, false otherwise.
* @since 3.2
*/
isMessageCountEnabled(): boolean {
return CoreSites.wsAvailableInCurrentSite('core_message_get_unread_conversations_count');
}
/**
* Returns whether or not the message preferences are enabled for the current site.
*
* @return True if enabled, false otherwise.
* @since 3.2
*/
isMessagePreferencesEnabled(): boolean {
return CoreSites.wsAvailableInCurrentSite('core_message_get_user_message_preferences');
}
/**
* Returns whether or not messaging is enabled for a certain site.
*
@ -2105,15 +2046,6 @@ export class AddonMessagesProvider {
return site.canUseAdvancedFeature('messaging');
}
/**
* Returns whether or not we can search messages.
*
* @since 3.2
*/
isSearchMessagesEnabled(): boolean {
return CoreSites.wsAvailableInCurrentSite('core_message_data_for_messagearea_search_messages');
}
/**
* Returns whether or not self conversation is supported in a certain site.
*
@ -3691,6 +3623,13 @@ type AddonMessagesSetFavouriteConversationsWSParams = {
conversations: number[];
};
/**
* Params of core_message_get_unread_conversations_count WS.
*/
type AddonMessageGetUnreadConversationsCountWSParams = {
useridto: number; // The user id who received the message, 0 for any user.
};
/**
* Data sent by UNREAD_CONVERSATION_COUNTS_EVENT event.
*/

View File

@ -96,7 +96,7 @@
<h2 *ngIf="assign.teamsubmission">{{ 'addon.mod_assign.numberofteams' | translate }}</h2>
<h2 *ngIf="!assign.teamsubmission">{{ 'addon.mod_assign.numberofparticipants' | translate }}</h2>
</ion-label>
<ion-badge slot="end" *ngIf="showNumbers" color="primary">
<ion-badge slot="end" color="primary">
<span aria-hidden="true">{{ summary.participantcount }}</span>
<span class="sr-only" *ngIf="!assign.teamsubmission">
{{ 'addon.mod_assign.numberofparticipantscountdescription' | translate:{count: summary.participantcount} }}
@ -109,12 +109,12 @@
<!-- Summary of submissions with draft status. -->
<ion-item class="ion-text-wrap" *ngIf="assign.submissiondrafts && summary && summary.submissionsenabled"
[class.hide-detail]="showNumbers && !summary.submissiondraftscount"
[class.hide-detail]="!summary.submissiondraftscount"
detail="true"
[button]="!showNumbers || summary.submissiondraftscount"
[button]="summary.submissiondraftscount"
(click)="goToSubmissionList(submissionStatusDraft, !!summary.submissiondraftscount)">
<ion-label><h2>{{ 'addon.mod_assign.numberofdraftsubmissions' | translate }}</h2></ion-label>
<ion-badge slot="end" *ngIf="showNumbers" color="primary">
<ion-badge slot="end" color="primary">
<span aria-hidden="true">{{ summary.submissiondraftscount }}</span>
<span class="sr-only">
{{ 'addon.mod_assign.numberofdraftsubmissionscountdescription' | translate:
@ -125,12 +125,12 @@
<!-- Summary of submissions with submitted status. -->
<ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled"
[class.hide-detail]="showNumbers && !summary.submissionssubmittedcount"
[class.hide-detail]="!summary.submissionssubmittedcount"
detail="true"
[button]="!showNumbers || summary.submissionssubmittedcount"
[button]="summary.submissionssubmittedcount"
(click)="goToSubmissionList(submissionStatusSubmitted, !!summary.submissionssubmittedcount)">
<ion-label><h2>{{ 'addon.mod_assign.numberofsubmittedassignments' | translate }}</h2></ion-label>
<ion-badge slot="end" *ngIf="showNumbers" color="primary">
<ion-badge slot="end" color="primary">
<span aria-hidden="true">{{ summary.submissionssubmittedcount }}</span>
<span class="sr-only">
{{ 'addon.mod_assign.numberofsubmittedassignmentscountdescription' | translate:
@ -140,7 +140,7 @@
</ion-item>
<!-- Summary of submissions that need grading. -->
<ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled && !assign.teamsubmission && showNumbers"
<ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled && !assign.teamsubmission"
[class.hide-detail]="!needsGradingAvailable"
detail="true"
[button]="needsGradingAvailable"

View File

@ -63,7 +63,6 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
canViewOwnSubmission = false; // Whether the user can view their own submission.
timeRemaining?: string; // Message about time remaining to submit.
lateSubmissions?: string; // Message about late submissions.
showNumbers = true; // Whether to show number of submissions with each status.
summary?: AddonModAssignSubmissionGradingSummary; // The grading summary.
needsGradingAvailable = false; // Whether we can see the submissions that need grading.
@ -235,8 +234,6 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
// Check if groupmode is enabled to avoid showing wrong numbers.
this.groupInfo = await CoreGroups.getActivityGroupInfo(this.assign.cmid, false);
this.showNumbers = (this.groupInfo.groups && this.groupInfo.groups.length == 0) ||
this.currentSite!.isVersionGreaterEqualThan('3.5');
await this.setGroup(CoreGroups.validateGroupId(this.group, this.groupInfo));
@ -296,9 +293,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
}
}
this.needsGradingAvailable =
(submissionStatus.gradingsummary?.submissionsneedgradingcount || 0) > 0 &&
this.currentSite!.isVersionGreaterEqualThan('3.2');
this.needsGradingAvailable = (submissionStatus.gradingsummary?.submissionsneedgradingcount || 0) > 0;
}
/**
@ -308,7 +303,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
* @param hasSubmissions If the status has any submission.
*/
goToSubmissionList(status?: string, hasSubmissions = false): void {
if (typeof status != 'undefined' && !hasSubmissions && this.showNumbers) {
if (typeof status != 'undefined' && !hasSubmissions) {
return;
}

View File

@ -649,7 +649,6 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
this.gradeInfo = await CoreCourse.getModuleBasicGradeInfo(this.moduleId);
if (!this.gradeInfo) {
// It won't get gradeinfo on 3.1.
return;
}
@ -966,7 +965,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
}
// Treat outcomes.
if (this.gradeInfo.outcomes && AddonModAssign.isOutcomesEditEnabled()) {
if (this.gradeInfo.outcomes) {
this.gradeInfo.outcomes.forEach((outcome) => {
if (outcome.scale) {
outcome.options =
@ -981,8 +980,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
}
// Get grade items.
const grades = <CoreGradesFormattedItem[]>
await CoreGradesHelper.getGradeModuleItems(this.courseId, this.moduleId, this.submitId);
const grades = await CoreGradesHelper.getGradeModuleItems(this.courseId, this.moduleId, this.submitId);
const outcomes: AddonModAssignGradeOutcome[] = [];
@ -1091,16 +1089,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
submissionStatus.lastattempt.submissiongroupmemberswhoneedtosubmit
) {
submissionStatus.lastattempt.submissiongroupmemberswhoneedtosubmit.forEach((member) => {
if (this.blindMarking) {
// Users not blinded! (Moodle < 3.1.1, 3.2).
promises.push(AddonModAssign.getAssignmentUserMappings(this.assign!.id, member, {
cmId: this.moduleId,
}).then((blindId) => {
this.membersToSubmitBlind.push(blindId);
return;
}));
} else {
if (!this.blindMarking) {
promises.push(CoreUser.getProfile(member, this.courseId).then((profile) => {
this.membersToSubmit.push(profile);

View File

@ -72,13 +72,6 @@
</ion-label>
</ion-item>
</ng-container>
<ion-card class="ion-text-wrap core-warning-card" *ngIf="!haveAllParticipants">
<ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_assign.notallparticipantsareshown' | translate }}</ion-label>
</ion-item>
</ion-card>
</ion-list>
</core-loading>
</core-split-view>

View File

@ -55,7 +55,6 @@ export class AddonModAssignSubmissionListPage implements AfterViewInit, OnDestro
assign?: AddonModAssignAssign; // Assignment.
submissions: AddonModAssignSubmissionListManager; // List of submissions
loaded = false; // Whether data has been loaded.
haveAllParticipants = true; // Whether all participants have been loaded.
groupId = 0; // Group ID to show.
courseId!: number; // Course ID the assignment belongs to.
moduleId!: number; // Module ID the submission belongs to.
@ -202,16 +201,6 @@ export class AddonModAssignSubmissionListPage implements AfterViewInit, OnDestro
async setGroup(groupId: number): Promise<void> {
this.groupId = groupId;
this.haveAllParticipants = true;
if (!CoreSites.getCurrentSite()?.wsAvailable('mod_assign_list_participants')) {
// Submissions are not displayed in Moodle 3.1 without the local plugin, see MOBILE-2968.
this.haveAllParticipants = false;
this.submissions.resetItems();
return;
}
// Fetch submissions and grades.
const submissions =
await AddonModAssignHelper.getSubmissionsUserData(

View File

@ -398,13 +398,9 @@ export class AddonModAssignHelperProvider {
groupId?: number,
options: CoreSitesCommonWSOptions = {},
): Promise<AddonModAssignSubmissionFormatted[]> {
// Create new options including all existing ones.
const modOptions: CoreCourseCommonModWSOptions = { cmId: assign.cmid, ...options };
const parts = await this.getParticipants(assign, groupId, options);
const blind = assign.blindmarking && !assign.revealidentities;
const promises: Promise<void>[] = [];
const result: AddonModAssignSubmissionFormatted[] = [];
const participants: {[id: number]: AddonModAssignParticipant} = CoreUtils.arrayToObject(parts, 'id');
@ -434,31 +430,12 @@ export class AddonModAssignHelperProvider {
submission.groupname = participant.groupname;
}
let promise = Promise.resolve();
if (submission.userid && submission.userid > 0 && blind) {
// Blind but not blinded! (Moodle < 3.1.1, 3.2).
delete submission.userid;
promise = AddonModAssign.getAssignmentUserMappings(assign.id, submission.submitid, modOptions)
.then((blindId) => {
submission.blindid = blindId;
return;
});
// Add to the list.
if (submission.userfullname || submission.blindid) {
result.push(submission);
}
promises.push(promise.then(() => {
// Add to the list.
if (submission.userfullname || submission.blindid) {
result.push(submission);
}
return;
}));
});
await Promise.all(promises);
// Create a submission for each participant left in the list (the participants already treated were removed).
CoreUtils.objectToArray(participants).forEach((participant: AddonModAssignParticipant) => {
const submission = this.createEmptySubmission();

View File

@ -37,7 +37,7 @@ import { CoreCourseLogHelper } from '@features/course/services/log-helper';
import { CoreUtils } from '@services/utils/utils';
import { CoreApp } from '@services/app';
import { CoreNetworkError } from '@classes/errors/network-error';
import { CoreGradesFormattedItem, CoreGradesFormattedRow, CoreGradesHelper } from '@features/grades/services/grades-helper';
import { CoreGradesFormattedItem, CoreGradesHelper } from '@features/grades/services/grades-helper';
import { AddonModAssignSubmissionDelegate } from './submission-delegate';
import { AddonModAssignFeedbackDelegate } from './feedback-delegate';
@ -457,21 +457,20 @@ export class AddonModAssignSyncProvider extends CoreCourseActivitySyncBaseProvid
}
// If grade has been modified from gradebook, do not use offline.
const grades: CoreGradesFormattedItem[] | CoreGradesFormattedRow[] =
await CoreGradesHelper.getGradeModuleItems(courseId, assign.cmid, userId, undefined, siteId, true);
const grades = await CoreGradesHelper.getGradeModuleItems(courseId, assign.cmid, userId, undefined, siteId, true);
const gradeInfo = await CoreCourse.getModuleBasicGradeInfo(assign.cmid, siteId);
// Override offline grade and outcomes based on the gradebook data.
grades.forEach((grade: CoreGradesFormattedItem | CoreGradesFormattedRow) => {
if ('gradedategraded' in grade && (grade.gradedategraded || 0) >= offlineData.timemodified) {
grades.forEach((grade: CoreGradesFormattedItem) => {
if ((grade.gradedategraded || 0) >= offlineData.timemodified) {
if (!grade.outcomeid && !grade.scaleid) {
if (gradeInfo && gradeInfo.scale) {
offlineData.grade = this.getSelectedScaleId(gradeInfo.scale, grade.grade || '');
} else {
offlineData.grade = parseFloat(grade.grade || '');
}
} else if (gradeInfo && grade.outcomeid && AddonModAssign.isOutcomesEditEnabled() && gradeInfo.outcomes) {
} else if (gradeInfo && grade.outcomeid && gradeInfo.outcomes) {
gradeInfo.outcomes.forEach((outcome, index) => {
if (outcome.scale && grade.itemnumber == index) {
offlineData.outcomes[grade.itemnumber] = this.getSelectedScaleId(

View File

@ -90,8 +90,6 @@ export class AddonModAssignProvider {
static readonly SUBMITTED_FOR_GRADING_EVENT = 'addon_mod_assign_submitted_for_grading';
static readonly GRADED_EVENT = 'addon_mod_assign_graded';
protected gradingOfflineEnabled: {[siteId: string]: boolean} = {};
/**
* Check if the user can submit in offline. This should only be used if submissionStatus.lastattempt.cansubmit cannot
* be used (offline usage).
@ -151,7 +149,7 @@ export class AddonModAssignProvider {
return {
isBlind: !userId ? false : !!isBlind,
groupId: site.isVersionGreaterEqualThan('3.5') ? groupId || 0 : 0,
groupId: groupId || 0,
userId: userId || site.getUserId(),
};
}
@ -662,10 +660,6 @@ export class AddonModAssignProvider {
groupId = groupId || 0;
const site = await CoreSites.getSite(options.siteId);
if (!site.wsAvailable('mod_assign_list_participants')) {
// Silently fail if is not available. (needs Moodle version >= 3.2)
throw new CoreError('mod_assign_list_participants WS is only available 3.2 onwards');
}
const params: AddonModAssignListParticipantsWSParams = {
assignid: assignId,
@ -836,47 +830,6 @@ export class AddonModAssignProvider {
await site.invalidateWsCacheForKeyStartingWith(this.listParticipantsPrefixCacheKey(assignId));
}
/**
* Convenience function to check if grading offline is enabled.
*
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with boolean: whether grading offline is enabled.
*/
protected async isGradingOfflineEnabled(siteId?: string): Promise<boolean> {
siteId = siteId || CoreSites.getCurrentSiteId();
if (typeof this.gradingOfflineEnabled[siteId] != 'undefined') {
return this.gradingOfflineEnabled[siteId];
}
this.gradingOfflineEnabled[siteId] = await CoreGrades.isGradeItemsAvailable(siteId);
return this.gradingOfflineEnabled[siteId];
}
/**
* Outcomes only can be edited if mod_assign_submit_grading_form is available.
*
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with true if outcomes edit is enabled, rejected or resolved with false otherwise.
* @since 3.2
*/
async isOutcomesEditEnabled(siteId?: string): Promise<boolean> {
const site = await CoreSites.getSite(siteId);
return site.wsAvailable('mod_assign_submit_grading_form');
}
/**
* Check if assignments plugin is enabled in a certain site.
*
* @param siteId Site ID. If not defined, current site.
* @return Whether the plugin is enabled.
*/
isPluginEnabled(): boolean {
return true;
}
/**
* Check if a submission is open. This function is based on Moodle's submissions_open.
*
@ -1261,25 +1214,6 @@ export class AddonModAssignProvider {
return false;
};
// Grading offline is only allowed if WS of grade items is enabled to avoid inconsistency.
const enabled = await this.isGradingOfflineEnabled(siteId);
if (!enabled) {
await this.submitGradingFormOnline(
assignId,
userId,
grade,
attemptNumber,
addAttempt,
workflowState,
applyToAll,
outcomes,
pluginData,
siteId,
);
return true;
}
if (!CoreApp.isOnline()) {
// App is offline, store the action.
return storeOffline();
@ -1345,58 +1279,35 @@ export class AddonModAssignProvider {
const site = await CoreSites.getSite(siteId);
userId = userId || site.getUserId();
if (site.wsAvailable('mod_assign_submit_grading_form')) {
// WS available @since 3.2.
const jsonData = {
grade,
attemptnumber: attemptNumber,
addattempt: addAttempt ? 1 : 0,
workflowstate: workflowState,
applytoall: applyToAll ? 1 : 0,
};
const jsonData = {
grade,
attemptnumber: attemptNumber,
addattempt: addAttempt ? 1 : 0,
workflowstate: workflowState,
applytoall: applyToAll ? 1 : 0,
};
for (const index in outcomes) {
jsonData['outcome_' + index + '[' + userId + ']'] = outcomes[index];
}
for (const index in pluginData) {
jsonData[index] = pluginData[index];
}
const serialized = CoreInterceptor.serialize(jsonData, true);
const params: AddonModAssignSubmitGradingFormWSParams = {
assignmentid: assignId,
userid: userId,
jsonformdata: JSON.stringify(serialized),
};
const warnings = await site.write<CoreWSExternalWarning[]>('mod_assign_submit_grading_form', params);
if (warnings.length) {
// The WebService returned warnings, reject.
throw new CoreWSError(warnings[0]);
}
return;
for (const index in outcomes) {
jsonData['outcome_' + index + '[' + userId + ']'] = outcomes[index];
}
// WS not available, fallback to save_grade.
const params: AddonModAssignSaveGradeWSParams = {
for (const index in pluginData) {
jsonData[index] = pluginData[index];
}
const serialized = CoreInterceptor.serialize(jsonData, true);
const params: AddonModAssignSubmitGradingFormWSParams = {
assignmentid: assignId,
userid: userId,
grade: grade,
attemptnumber: attemptNumber,
addattempt: addAttempt,
workflowstate: workflowState,
applytoall: applyToAll,
plugindata: pluginData,
};
const preSets: CoreSiteWSPreSets = {
responseExpected: false,
jsonformdata: JSON.stringify(serialized),
};
await site.write('mod_assign_save_grade', params, preSets);
const warnings = await site.write<CoreWSExternalWarning[]>('mod_assign_submit_grading_form', params);
if (warnings.length) {
// The WebService returned warnings, reject.
throw new CoreWSError(warnings[0]);
}
}
}
@ -1431,7 +1342,7 @@ export type AddonModAssignAssign = {
timemodified: number; // Last time assignment was modified.
completionsubmit: number; // If enabled, set activity as complete following submission.
cutoffdate: number; // Date after which submission is not accepted without an extension.
gradingduedate?: number; // @since 3.3. The expected date for marking the submissions.
gradingduedate?: number; // The expected date for marking the submissions.
teamsubmission: number; // If enabled, students submit as a team.
requireallteammemberssubmit: number; // If enabled, all team members must submit.
teamsubmissiongroupingid: number; // The grouping id for the team submission groups.
@ -1443,13 +1354,13 @@ export type AddonModAssignAssign = {
markingworkflow: number; // Enable marking workflow.
markingallocation: number; // Enable marking allocation.
requiresubmissionstatement: number; // Student must accept submission statement.
preventsubmissionnotingroup?: number; // @since 3.2. Prevent submission not in group.
submissionstatement?: string; // @since 3.2. Submission statement formatted.
submissionstatementformat?: number; // @since 3.2. Submissionstatement format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
preventsubmissionnotingroup?: number; // Prevent submission not in group.
submissionstatement?: string; // Submission statement formatted.
submissionstatementformat?: number; // Submissionstatement format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
configs: AddonModAssignConfig[]; // Configuration settings.
intro?: string; // Assignment intro, not allways returned because it deppends on the activity configuration.
introformat?: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
introfiles?: CoreWSExternalFile[]; // @since 3.2.
introfiles?: CoreWSExternalFile[];
introattachments?: CoreWSExternalFile[];
};
@ -1494,7 +1405,7 @@ export type AddonModAssignSubmission = {
assignment?: number; // Assignment id.
latest?: number; // Latest attempt.
plugins?: AddonModAssignPlugin[]; // Plugins.
gradingstatus?: string; // @since 3.2. Grading status.
gradingstatus?: string; // Grading status.
};
/**
@ -1539,7 +1450,7 @@ export type AddonModAssignSubmissionAttempt = {
locked: boolean; // Whether new submissions are locked.
graded: boolean; // Whether the submission is graded.
canedit: boolean; // Whether the user can edit the current submission.
caneditowner?: boolean; // @since 3.2. Whether the owner of the submission can edit it.
caneditowner?: boolean; // Whether the owner of the submission can edit it.
cansubmit: boolean; // Whether the user can submit.
extensionduedate: number; // Extension due date.
blindmarking: boolean; // Whether blind marking is enabled.
@ -1610,7 +1521,7 @@ export type AddonModAssignParticipant = {
interests?: string; // User interests (separated by commas).
firstaccess?: number; // First access to the site (0 if never).
lastaccess?: number; // Last access to the site (0 if never).
suspended?: boolean; // @since 3.2. Suspend user account, either false to enable user login or true to disable it.
suspended?: boolean; // Suspend user account, either false to enable user login or true to disable it.
description?: string; // User profile description.
descriptionformat?: number; // Int format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
city?: string; // Home city of the user.
@ -1647,7 +1558,7 @@ export type AddonModAssignParticipant = {
}[];
submitted: boolean; // Have they submitted their assignment.
requiregrading: boolean; // Is their submission waiting for grading.
grantedextension?: boolean; // @since 3.3. Have they been granted an extension.
grantedextension?: boolean; // Have they been granted an extension.
groupid?: number; // For group assignments this is the group id.
groupname?: string; // For group assignments this is the group name.
};
@ -1815,45 +1726,6 @@ type AddonModAssignSubmitGradingFormWSParams = {
jsonformdata: string; // The data from the grading form, encoded as a json array.
};
/**
* Params of mod_assign_save_grade WS.
*/
type AddonModAssignSaveGradeWSParams = {
assignmentid: number; // The assignment id to operate on.
userid: number; // The student id to operate on.
grade: number; // The new grade for this user. Ignored if advanced grading used.
attemptnumber: number; // The attempt number (-1 means latest attempt).
addattempt: boolean; // Allow another attempt if the attempt reopen method is manual.
workflowstate: string; // The next marking workflow state.
applytoall: boolean; // If true, this grade will be applied to all members of the group (for group assignments).
plugindata?: AddonModAssignSavePluginData; // Plugin data.
advancedgradingdata?: {
guide?: {
criteria: {
criterionid: number; // Criterion id.
fillings?: { // Filling.
criterionid: number; // Criterion id.
levelid?: number; // Level id.
remark?: string; // Remark.
remarkformat?: number; // Remark format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
score: number; // Maximum score.
}[];
}[];
}; // Items.
rubric?: {
criteria: {
criterionid: number; // Criterion id.
fillings?: { // Filling.
criterionid: number; // Criterion id.
levelid?: number; // Level id.
remark?: string; // Remark.
remarkformat?: number; // Remark format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
}[];
}[];
}; // Items.
}; // Advanced grading data.
};
/**
* Assignment grade outcomes.
*/

View File

@ -20,7 +20,6 @@ import { makeSingleton } from '@singletons';
import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/course';
import { CoreCourseModule } from '@features/course/services/course-helper';
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
import { AddonModAssign } from '../assign';
/**
* Handler to support assign modules.
@ -54,7 +53,7 @@ export class AddonModAssignModuleHandlerService implements CoreCourseModuleHandl
* @return Whether or not the handler is enabled on a site level.
*/
async isEnabled(): Promise<boolean> {
return AddonModAssign.isPluginEnabled();
return true;
}
/**

View File

@ -202,15 +202,6 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref
return CoreCourse.invalidateModule(module.id);
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return A boolean, or a promise resolved with a boolean, indicating if the handler is enabled.
*/
async isEnabled(): Promise<boolean> {
return AddonModAssign.isPluginEnabled();
}
/**
* @inheritdoc
*/
@ -391,10 +382,7 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref
// Participiants already fetched, we don't need to ignore cache now.
const participants = await AddonModAssignHelper.getParticipants(assign, group.id, { siteId });
// Fail silently (Moodle < 3.2).
await CoreUtils.ignoreErrors(
CoreUser.prefetchUserAvatars(participants, 'profileimageurl', siteId),
);
await CoreUser.prefetchUserAvatars(participants, 'profileimageurl', siteId);
return;
}));

View File

@ -16,7 +16,6 @@ import { AddonModAssignAssign, AddonModAssignSubmission, AddonModAssignPlugin }
import { AddonModAssignSubmissionHandler } from '@addons/mod/assign/services/submission-delegate';
import { Injectable, Type } from '@angular/core';
import { CoreComments } from '@features/comments/services/comments';
import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons';
import { AddonModAssignSubmissionCommentsComponent } from '../component/comments';
@ -87,18 +86,14 @@ export class AddonModAssignSubmissionCommentsHandlerService implements AddonModA
plugin: AddonModAssignPlugin,
siteId?: string,
): Promise<void> {
// Fail silently (Moodle < 3.1.1, 3.2)
await CoreUtils.ignoreErrors(
CoreComments.getComments(
'module',
assign.cmid,
'assignsubmission_comments',
submission.id,
'submission_comments',
0,
siteId,
),
await CoreComments.getComments(
'module',
assign.cmid,
'assignsubmission_comments',
submission.id,
'submission_comments',
0,
siteId,
);
}

View File

@ -24,7 +24,6 @@ import { AddonModAssignSubmissionHandler } from '@addons/mod/assign/services/sub
import { Injectable, Type } from '@angular/core';
import { CoreError } from '@classes/errors/error';
import { CoreFileHelper } from '@services/file-helper';
import { CoreSites } from '@services/sites';
import { CoreTextUtils } from '@services/utils/text';
import { CoreUtils } from '@services/utils/utils';
import { CoreWSFile } from '@services/ws';
@ -224,11 +223,7 @@ export class AddonModAssignSubmissionOnlineTextHandlerService implements AddonMo
* @return Whether or not the handler is enabled for edit on a site level.
*/
isEnabledForEdit(): boolean {
// There's a bug in Moodle 3.1.0 that doesn't allow submitting HTML, so we'll disable this plugin in that case.
// Bug was fixed in 3.1.1 minor release and in 3.2.
const currentSite = CoreSites.getCurrentSite();
return !!currentSite?.isVersionGreaterEqualThan('3.1.1') || !!currentSite?.checkIfAppUsesLocalMobile();
return true;
}
/**

View File

@ -441,7 +441,7 @@ export type AddonModBookBookWSData = {
name: string; // Book name.
intro: string; // The Book intro.
introformat: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
introfiles?: CoreWSExternalFile[]; // @since 3.2.
introfiles?: CoreWSExternalFile[];
numbering: number; // Book numbering configuration.
navstyle: number; // Book navigation style configuration.
customtitles: number; // Book custom titles type.

View File

@ -46,7 +46,7 @@
<ion-button class="ion-margin ion-text-wrap" expand="block" color="primary" (click)="enterChat()">
{{ 'addon.mod_chat.enterchat' | translate }}
</ion-button>
<ion-button class="ion-margin ion-text-wrap" expand="block" color="light" *ngIf="sessionsAvailable" (click)="viewSessions()">
<ion-button class="ion-margin ion-text-wrap" expand="block" color="light" (click)="viewSessions()">
{{ 'addon.mod_chat.viewreport' | translate }}
</ion-button>
</ng-container>

View File

@ -34,7 +34,6 @@ export class AddonModChatIndexComponent extends CoreCourseModuleMainActivityComp
component = AddonModChatProvider.COMPONENT;
moduleName = 'chat';
chat?: AddonModChatChat;
sessionsAvailable = false;
chatInfo?: {
date: string;
fromnow: string;
@ -89,8 +88,6 @@ export class AddonModChatIndexComponent extends CoreCourseModuleMainActivityComp
}
this.dataRetrieved.emit(this.chat);
this.sessionsAvailable = await AddonModChat.areSessionsAvailable();
} finally {
this.fillContextMenu(refresh);
}

View File

@ -217,19 +217,6 @@ export class AddonModChatProvider {
return site.read('mod_chat_get_chat_users', params, preSets);
}
/**
* Return whether WS for passed sessions are available.
*
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with a boolean.
* @since 3.5
*/
async areSessionsAvailable(siteId?: string): Promise<boolean> {
const site = await CoreSites.getSite(siteId);
return site.wsAvailable('mod_chat_get_sessions') && site.wsAvailable('mod_chat_get_session_messages');
}
/**
* Get chat sessions.
*
@ -238,7 +225,6 @@ export class AddonModChatProvider {
* @param showAll Whether to include incomplete sessions or not.
* @param options Other options.
* @return Promise resolved with the list of sessions.
* @since 3.5
*/
async getSessions(
chatId: number,
@ -275,7 +261,6 @@ export class AddonModChatProvider {
* @param groupId Group ID, 0 means that the function will determine the user group.
* @param options Other options.
* @return Promise resolved with the list of messages.
* @since 3.5
*/
async getSessionMessages(
chatId: number,
@ -461,7 +446,7 @@ export type AddonModChatChat = {
name: string; // Chat name.
intro: string; // The Chat intro.
introformat: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
introfiles?: CoreWSExternalFile[]; // @since 3.2.
introfiles?: CoreWSExternalFile[];
chatmethod?: string; // Chat method (sockets, ajax, header_js).
keepdays?: number; // Keep days.
studentlogs?: number; // Student logs visible to everyone.

View File

@ -20,7 +20,6 @@ import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
import { makeSingleton } from '@singletons';
import { AddonModChatIndexComponent } from '../../components/index';
import { AddonModChat } from '../chat';
/**
* Handler to support chat modules.
@ -59,6 +58,7 @@ export class AddonModChatModuleHandlerService implements CoreCourseModuleHandler
icon: CoreCourse.getModuleIconSrc(this.modName, 'modicon' in module ? module.modicon : undefined),
title: module.name,
class: 'addon-mod_chat-handler',
showDownloadButton: true,
action(event: Event, module: CoreCourseModule, courseId: number, options?: CoreNavigationOptions): void {
options = options || {};
options.params = options.params || {};
@ -69,20 +69,9 @@ export class AddonModChatModuleHandlerService implements CoreCourseModuleHandler
},
};
this.checkDownloadButton(data);
return data;
}
/**
* Check whether download button should be displayed.
*
* @param data Handler data.
*/
protected async checkDownloadButton(data: CoreCourseModuleHandlerData): Promise<void> {
data.showDownloadButton = await AddonModChat.areSessionsAvailable();
}
/**
* @inheritdoc
*/

View File

@ -32,13 +32,6 @@ export class AddonModChatPrefetchHandlerService extends CoreCourseActivityPrefet
modName = 'chat';
component = AddonModChatProvider.COMPONENT;
/**
* @inheritdoc
*/
async isEnabled(): Promise<boolean> {
return AddonModChat.areSessionsAvailable();
}
/**
* @inheritdoc
*/

View File

@ -484,7 +484,7 @@ export type AddonModChoiceChoice = {
name: string; // Choice name.
intro: string; // The choice intro.
introformat: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
introfiles?: CoreWSExternalFile[]; // @since 3.2.
introfiles?: CoreWSExternalFile[];
publish?: boolean; // If choice is published.
showresults?: number; // 0 never, 1 after answer, 2 after close, 3 always.
display?: number; // Display mode (vertical, horizontal).

View File

@ -950,19 +950,6 @@ export class AddonModDataProvider {
await site.invalidateWsCacheForKey(this.getEntryCacheKey(dataId, entryId));
}
/**
* Return whether or not the plugin is enabled in a certain site. Plugin is enabled if the database WS are available.
*
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise.
* @since 3.3
*/
async isPluginEnabled(siteId?: string): Promise<boolean> {
const site = await CoreSites.getSite(siteId);
return site.wsAvailable('mod_data_get_data_access_information');
}
/**
* Report the database as being viewed.
*

View File

@ -17,7 +17,6 @@ import { Params } from '@angular/router';
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { makeSingleton } from '@singletons';
import { AddonModData } from '../data';
import { AddonModDataHelper } from '../data-helper';
/**
@ -56,7 +55,7 @@ export class AddonModDataApproveLinkHandlerService extends CoreContentLinksHandl
return false;
}
return AddonModData.isPluginEnabled(siteId);
return true;
}
}

View File

@ -17,7 +17,6 @@ import { Params } from '@angular/router';
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { makeSingleton } from '@singletons';
import { AddonModData } from '../data';
import { AddonModDataHelper } from '../data-helper';
/**
@ -54,7 +53,7 @@ export class AddonModDataDeleteLinkHandlerService extends CoreContentLinksHandle
return false;
}
return AddonModData.isPluginEnabled(siteId);
return true;
}
}

View File

@ -20,7 +20,6 @@ import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator';
import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons';
import { AddonModData } from '../data';
import { AddonModDataModuleHandlerService } from './module';
/**
@ -72,7 +71,7 @@ export class AddonModDataEditLinkHandlerService extends CoreContentLinksHandlerB
return false;
}
return AddonModData.isPluginEnabled(siteId);
return true;
}
}

View File

@ -15,7 +15,6 @@
import { Injectable } from '@angular/core';
import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler';
import { makeSingleton } from '@singletons';
import { AddonModData } from '../data';
/**
* Handler to treat links to data.
@ -29,12 +28,5 @@ export class AddonModDataIndexLinkHandlerService extends CoreContentLinksModuleI
super('AddonModData', 'data', 'd');
}
/**
* @inheritdoc
*/
isEnabled(siteId: string): Promise<boolean> {
return AddonModData.isPluginEnabled(siteId);
}
}
export const AddonModDataIndexLinkHandler = makeSingleton(AddonModDataIndexLinkHandlerService);

View File

@ -15,7 +15,6 @@
import { Injectable } from '@angular/core';
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
import { makeSingleton } from '@singletons';
import { AddonModData } from '../data';
/**
* Handler to treat links to data list page.
@ -29,12 +28,5 @@ export class AddonModDataListLinkHandlerService extends CoreContentLinksModuleLi
super('AddonModData', 'data');
}
/**
* @inheritdoc
*/
isEnabled(siteId?: string): Promise<boolean> {
return AddonModData.isPluginEnabled(siteId);
}
}
export const AddonModDataListLinkHandler = makeSingleton(AddonModDataListLinkHandlerService);

View File

@ -20,7 +20,6 @@ import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
import { makeSingleton } from '@singletons';
import { AddonModDataIndexComponent } from '../../components/index';
import { AddonModData } from '../data';
/**
* Handler to support data modules.
@ -50,8 +49,8 @@ export class AddonModDataModuleHandlerService implements CoreCourseModuleHandler
/**
* @inheritdoc
*/
isEnabled(): Promise<boolean> {
return AddonModData.isPluginEnabled();
async isEnabled(): Promise<boolean> {
return true;
}
/**

View File

@ -203,13 +203,6 @@ export class AddonModDataPrefetchHandlerService extends CoreCourseActivityPrefet
return true;
}
/**
* @inheritdoc
*/
async isEnabled(): Promise<boolean> {
return AddonModData.isPluginEnabled();
}
/**
* @inheritdoc
*/

View File

@ -20,7 +20,6 @@ import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator';
import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons';
import { AddonModData } from '../data';
import { AddonModDataModuleHandlerService } from './module';
/**
@ -87,7 +86,7 @@ export class AddonModDataShowLinkHandlerService extends CoreContentLinksHandlerB
return false;
}
return AddonModData.isPluginEnabled(siteId);
return true;
}
}

View File

@ -17,7 +17,6 @@ import { CoreTagFeedComponent } from '@features/tag/components/feed/feed';
import { CoreTagAreaHandler } from '@features/tag/services/tag-area-delegate';
import { CoreTagFeedElement, CoreTagHelper } from '@features/tag/services/tag-helper';
import { makeSingleton } from '@singletons';
import { AddonModData } from '../data';
/**
* Handler to support tags.
@ -32,7 +31,7 @@ export class AddonModDataTagAreaHandlerService implements CoreTagAreaHandler {
* @inheritdoc
*/
async isEnabled(): Promise<boolean> {
return AddonModData.isPluginEnabled();
return true;
}
/**

View File

@ -1089,20 +1089,6 @@ export class AddonModFeedbackProvider {
return CoreUtils.promiseWorks(site.read('mod_feedback_get_last_completed', params, preSets));
}
/**
* Return whether or not the plugin is enabled in a certain site. Plugin is enabled if the feedback WS are available.
*
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise.
* @since 3.3
*/
async isPluginEnabled(siteId?: string): Promise<boolean> {
const site = await CoreSites.getSite(siteId);
return site.wsAvailable('mod_feedback_get_feedbacks_by_courses') &&
site.wsAvailable('mod_feedback_get_feedback_access_information');
}
/**
* Report the feedback as being viewed.
*

View File

@ -19,7 +19,6 @@ import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator';
import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons';
import { AddonModFeedback } from '../feedback';
import { AddonModFeedbackModuleHandlerService } from './module';
/**
@ -84,7 +83,7 @@ export class AddonModFeedbackAnalysisLinkHandlerService extends CoreContentLinks
return false;
}
return AddonModFeedback.isPluginEnabled(siteId);
return true;
}
}

View File

@ -19,7 +19,6 @@ import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator';
import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons';
import { AddonModFeedback } from '../feedback';
import { AddonModFeedbackModuleHandlerService } from './module';
/**
@ -72,7 +71,7 @@ export class AddonModFeedbackCompleteLinkHandlerService extends CoreContentLinks
return false;
}
return AddonModFeedback.isPluginEnabled(siteId);
return true;
}
}

View File

@ -15,7 +15,6 @@
import { Injectable } from '@angular/core';
import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler';
import { makeSingleton } from '@singletons';
import { AddonModFeedback } from '../feedback';
/**
* Handler to treat links to feedback.
@ -29,19 +28,6 @@ export class AddonModFeedbackIndexLinkHandlerService extends CoreContentLinksMod
super('AddonModFeedback', 'feedback');
}
/**
* Check if the handler is enabled for a certain site (site + user) and a URL.
*
* @param siteId The site ID.
* @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param courseId Course ID related to the URL. Optional but recommended.
* @return Whether the handler is enabled for the URL and site.
*/
isEnabled(): Promise<boolean> {
return AddonModFeedback.isPluginEnabled();
}
}
export const AddonModFeedbackIndexLinkHandler = makeSingleton(AddonModFeedbackIndexLinkHandlerService);

View File

@ -15,7 +15,6 @@
import { Injectable } from '@angular/core';
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
import { makeSingleton } from '@singletons';
import { AddonModFeedback } from '../feedback';
/**
* Handler to treat links to feedback list page.
@ -29,13 +28,6 @@ export class AddonModFeedbackListLinkHandlerService extends CoreContentLinksModu
super('AddonModFeedback', 'feedback');
}
/**
* @inheritdoc
*/
isEnabled(): Promise<boolean> {
return AddonModFeedback.isPluginEnabled();
}
}
export const AddonModFeedbackListLinkHandler = makeSingleton(AddonModFeedbackListLinkHandlerService);

View File

@ -19,7 +19,6 @@ import { CoreCourseModule } from '@features/course/services/course-helper';
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
import { makeSingleton } from '@singletons';
import { AddonModFeedback } from '../feedback';
import { AddonModFeedbackIndexComponent } from '../../components/index';
/**
@ -48,8 +47,8 @@ export class AddonModFeedbackModuleHandlerService implements CoreCourseModuleHan
/**
* @inheritdoc
*/
isEnabled(): Promise<boolean> {
return AddonModFeedback.isPluginEnabled();
async isEnabled(): Promise<boolean> {
return true;
}
/**

View File

@ -110,13 +110,6 @@ export class AddonModFeedbackPrefetchHandlerService extends CoreCourseActivityPr
return accessData.isopen;
}
/**
* @inheritdoc
*/
isEnabled(): Promise<boolean> {
return AddonModFeedback.isPluginEnabled();
}
/**
* @inheritdoc
*/

View File

@ -19,7 +19,6 @@ import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator';
import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons';
import { AddonModFeedback } from '../feedback';
import { AddonModFeedbackModuleHandlerService } from './module';
/**
@ -72,7 +71,7 @@ export class AddonModFeedbackPrintLinkHandlerService extends CoreContentLinksHan
return false;
}
return AddonModFeedback.isPluginEnabled(siteId);
return true;
}
}

View File

@ -19,7 +19,6 @@ import { CorePushNotificationsNotificationBasicData } from '@features/pushnotifi
import { CoreUrlUtils } from '@services/utils/url';
import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons';
import { AddonModFeedback } from '../feedback';
import { AddonModFeedbackHelper } from '../feedback-helper';
/**
@ -39,7 +38,7 @@ export class AddonModFeedbackPushClickHandlerService implements CorePushNotifica
if (CoreUtils.isTrueOrOne(notification.notif) && notification.moodlecomponent == 'mod_feedback' &&
(notification.name == 'submission' || notification.name == 'message')) {
return AddonModFeedback.isPluginEnabled(notification.site);
return true;
}
return false;

View File

@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
import { CoreContentLinksHandlerBase } from '@features/contentlinks/classes/base-handler';
import { CoreContentLinksAction } from '@features/contentlinks/services/contentlinks-delegate';
import { makeSingleton } from '@singletons';
import { AddonModFeedback } from '../feedback';
import { AddonModFeedbackHelper } from '../feedback-helper';
/**
@ -50,7 +49,7 @@ export class AddonModFeedbackShowEntriesLinkHandlerService extends CoreContentLi
return false;
}
return AddonModFeedback.isPluginEnabled(siteId);
return true;
}
}

View File

@ -19,7 +19,6 @@ import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator';
import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons';
import { AddonModFeedback } from '../feedback';
import { AddonModFeedbackModuleHandlerService } from './module';
/**
* Content links handler for feedback show non respondents.
@ -67,7 +66,7 @@ export class AddonModFeedbackShowNonRespondentsLinkHandlerService extends CoreCo
return false;
}
return AddonModFeedback.isPluginEnabled(siteId);
return true;
}
}

View File

@ -18,7 +18,6 @@ import { Params } from '@angular/router';
import { CoreCourseModuleMainResourceComponent } from '@features/course/classes/main-resource-component';
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
import { CoreCourse } from '@features/course/services/course';
import { CoreApp } from '@services/app';
import { CoreNavigator } from '@services/navigator';
import { Md5 } from 'ts-md5';
import { AddonModFolder, AddonModFolderFolder, AddonModFolderProvider } from '../../services/folder';
@ -41,7 +40,6 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo
@Input() subfolder?: AddonModFolderFolderFormattedData; // Subfolder to show.
component = AddonModFolderProvider.COMPONENT;
canGetFolder = false;
contents?: AddonModFolderFolderFormattedData;
constructor(@Optional() courseContentsPage?: CoreCourseContentsPage) {
@ -54,8 +52,6 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo
async ngOnInit(): Promise<void> {
super.ngOnInit();
this.canGetFolder = AddonModFolder.isGetFolderWSAvailable();
if (this.subfolder) {
this.description = this.folderInstance ? this.folderInstance.intro : this.module.description;
this.contents = this.subfolder;
@ -98,18 +94,8 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo
*/
protected async fetchContent(refresh = false): Promise<void> {
try {
if (this.canGetFolder) {
this.folderInstance = await AddonModFolder.getFolder(this.courseId, this.module.id);
await CoreCourse.loadModuleContents(this.module, this.courseId, undefined, false, refresh);
} else {
const module = await CoreCourse.getModule(this.module.id, this.courseId);
if (!module.contents.length && this.module.contents.length && !CoreApp.isOnline()) {
// The contents might be empty due to a cached data. Use the old ones.
module.contents = this.module.contents;
}
this.module = module;
}
this.folderInstance = await AddonModFolder.getFolder(this.courseId, this.module.id);
await CoreCourse.loadModuleContents(this.module, this.courseId, undefined, false, refresh);
this.dataRetrieved.emit(this.folderInstance || this.module);

View File

@ -122,16 +122,6 @@ export class AddonModFolderProvider {
await site.invalidateWsCacheForKey(this.getFolderCacheKey(courseId));
}
/**
* Returns whether or not getFolder WS available or not.
*
* @return If WS is available.
* @since 3.3
*/
isGetFolderWSAvailable(): boolean {
return CoreSites.wsAvailableInCurrentSite('mod_folder_get_folders_by_courses');
}
/**
* Report a folder as being viewed.
*

View File

@ -35,10 +35,7 @@ export class AddonModFolderPrefetchHandlerService extends CoreCourseResourcePref
const promises: Promise<unknown>[] = [];
promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
if (AddonModFolder.isGetFolderWSAvailable()) {
promises.push(AddonModFolder.getFolder(courseId, module.id));
}
promises.push(AddonModFolder.getFolder(courseId, module.id));
await Promise.all(promises);
}

View File

@ -359,12 +359,7 @@ export class AddonModForumNewDiscussionPage implements OnInit, OnDestroy, CanLea
* @return Promise resolved with the list of groups.
*/
protected addAllParticipantsOption(groups: CoreGroup[], check: boolean): Promise<CoreGroup[]> {
if (!AddonModForum.isAllParticipantsFixed()) {
// All participants has a bug, don't add it.
return Promise.resolve(groups);
}
let promise;
let promise: Promise<boolean>;
if (check) {
// We need to check if the user can add a discussion to all participants.

View File

@ -308,15 +308,6 @@ export class AddonModForumProvider {
return index >= 0 ? posts.splice(index, 1).pop() : undefined;
}
/**
* There was a bug adding new discussions to All Participants (see MDL-57962). Check if it's fixed.
*
* @return True if fixed, false otherwise.
*/
isAllParticipantsFixed(): boolean {
return !!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan(['3.1.5', '3.2.2']);
}
/**
* Returns whether or not getDiscussionPost WS available or not.
*

View File

@ -162,7 +162,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
this.glossary = await AddonModGlossary.getGlossary(this.courseId, this.module.id);
this.description = this.glossary.intro || this.description;
this.canAdd = (AddonModGlossary.isPluginEnabledForEditing() && !!this.glossary.canaddentry) || false;
this.canAdd = !!this.glossary.canaddentry || false;
this.dataRetrieved.emit(this.glossary);

View File

@ -22,7 +22,6 @@ import { CoreRatingInfo } from '@features/rating/services/rating';
import { CoreTagItem } from '@features/tag/services/tag';
import { CoreApp } from '@services/app';
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
import { CoreTextUtils } from '@services/utils/text';
import { CoreUtils } from '@services/utils/utils';
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
import { makeSingleton, Translate } from '@singletons';
@ -964,11 +963,6 @@ export class AddonModGlossaryProvider {
});
}
// Workaround for bug MDL-57737.
if (!site.isVersionGreaterEqualThan('3.2.2')) {
params.definition = CoreTextUtils.cleanTags(params.definition);
}
const response = await site.write<AddonModGlossaryAddEntryWSResponse>('mod_glossary_add_entry', params);
return response.entryid;
@ -1007,16 +1001,6 @@ export class AddonModGlossaryProvider {
}
}
/**
* Return whether or not the plugin is enabled for editing in the current site. Plugin is enabled if the glossary WS are
* available.
*
* @return Whether the glossary editing is available or not.
*/
isPluginEnabledForEditing(): boolean {
return !!CoreSites.getCurrentSite()?.wsAvailable('mod_glossary_add_entry');
}
/**
* Report a glossary as being viewed.
*

View File

@ -19,7 +19,7 @@ import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/c
import { CoreCourses } from '@features/courses/services/courses';
import { CoreUser } from '@features/user/services/user';
import { CoreFilepool } from '@services/filepool';
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreWSFile } from '@services/ws';
import { makeSingleton } from '@singletons';
@ -73,16 +73,12 @@ export class AddonModGlossaryPrefetchHandlerService extends CoreCourseActivityPr
): CoreWSFile[] {
let files = this.getIntroFilesFromInstance(module, glossary);
const getInlineFiles = CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.2');
// Get entries files.
entries.forEach((entry) => {
files = files.concat(entry.attachments || []);
if (getInlineFiles && entry.definitioninlinefiles && entry.definitioninlinefiles.length) {
if (entry.definitioninlinefiles && entry.definitioninlinefiles.length) {
files = files.concat(entry.definitioninlinefiles);
} else if (entry.definition && !getInlineFiles) {
files = files.concat(CoreFilepool.extractDownloadableFilesFromHtmlAsFakeFileObjects(entry.definition));
}
});

View File

@ -744,6 +744,7 @@ export class AddonModH5PActivityProvider {
* Delete launcher.
*
* @return Promise resolved when the launcher file is deleted.
* @since 3.9
*/
async isPluginEnabled(siteId?: string): Promise<boolean> {
const site = await CoreSites.getSite(siteId);
@ -788,7 +789,7 @@ export class AddonModH5PActivityProvider {
const site = await CoreSites.getSite(options.siteId);
if (!site.wsAvailable('mod_h5pactivity_log_report_viewed')) {
// Site doesn't support the WS, stop.
// Site doesn't support the WS, stop. Added in Moodle 3.11.
return;
}

View File

@ -19,7 +19,7 @@ import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreWSFile } from '@services/ws';
import { makeSingleton } from '@singletons';
import { AddonModLabel, AddonModLabelLabel, AddonModLabelProvider } from '../label';
import { AddonModLabel, AddonModLabelProvider } from '../label';
/**
* Handler to prefetch labels.
@ -37,13 +37,9 @@ export class AddonModLabelPrefetchHandlerService extends CoreCourseResourcePrefe
* @inheritdoc
*/
async getIntroFiles(module: CoreCourseAnyModuleData, courseId: number, ignoreCache?: boolean): Promise<CoreWSFile[]> {
let label: AddonModLabelLabel | undefined;
if (AddonModLabel.isGetLabelAvailableForSite()) {
label = await AddonModLabel.getLabel(courseId, module.id, {
readingStrategy: ignoreCache ? CoreSitesReadingStrategy.ONLY_NETWORK : undefined,
});
}
const label = await AddonModLabel.getLabel(courseId, module.id, {
readingStrategy: ignoreCache ? CoreSitesReadingStrategy.ONLY_NETWORK : undefined,
});
return this.getIntroFilesFromInstance(module, label);
}

View File

@ -136,32 +136,6 @@ export class AddonModLabelProvider {
await CoreUtils.allPromises(promises);
}
/**
* Check if the site has the WS to get label data.
*
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with boolean: whether it's available.
* @since 3.3
*/
async isGetLabelAvailable(siteId?: string): Promise<boolean> {
const site = await CoreSites.getSite(siteId);
return site.wsAvailable('mod_label_get_labels_by_courses');
}
/**
* Check if the site has the WS to get label data.
*
* @param site Site. If not defined, current site.
* @return Whether it's available.
* @since 3.3
*/
isGetLabelAvailableForSite(site?: CoreSite): boolean {
site = site || CoreSites.getCurrentSite();
return !!site?.wsAvailable('mod_label_get_labels_by_courses');
}
}
export const AddonModLabel = makeSingleton(AddonModLabelProvider);

View File

@ -82,21 +82,6 @@ export class AddonModLessonGradeLinkHandlerService extends CoreContentLinksModul
}
}
/**
* Check if the handler is enabled for a certain site (site + user) and a URL.
* If not defined, defaults to true.
*
* @param siteId The site ID.
* @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param courseId Course ID related to the URL. Optional but recommended.
* @return Whether the handler is enabled for the URL and site.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async isEnabled(siteId: string, url: string, params: Record<string, string>, courseId?: number): Promise<boolean> {
return AddonModLesson.isPluginEnabled(siteId);
}
}
export const AddonModLessonGradeLinkHandler = makeSingleton(AddonModLessonGradeLinkHandlerService);

View File

@ -66,21 +66,6 @@ export class AddonModLessonIndexLinkHandlerService extends CoreContentLinksModul
}];
}
/**
* Check if the handler is enabled for a certain site (site + user) and a URL.
* If not defined, defaults to true.
*
* @param siteId The site ID.
* @param url The URL to treat.
* @param params The params of the URL. E.g. 'mysite.com?id=1' -> {id: 1}
* @param courseId Course ID related to the URL. Optional but recommended.
* @return Whether the handler is enabled for the URL and site.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
isEnabled(siteId: string, url: string, params: Record<string, string>, courseId?: number): Promise<boolean> {
return AddonModLesson.isPluginEnabled(siteId);
}
/**
* Navigate to a lesson module (index page) with a fixed password.
*

View File

@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
import { makeSingleton } from '@singletons';
import { AddonModLesson } from '../lesson';
/**
* Handler to treat links to lesson list page.
@ -30,16 +29,6 @@ export class AddonModLessonListLinkHandlerService extends CoreContentLinksModule
super('AddonModLesson', 'lesson');
}
/**
* Check if the handler is enabled on a site level.
*
* @return Promise resolved with boolean: whether or not the handler is enabled on a site level.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
isEnabled(siteId: string, url: string, params: Record<string, string>, courseId?: number): Promise<boolean> {
return AddonModLesson.isPluginEnabled(siteId);
}
}
export const AddonModLessonListLinkHandler = makeSingleton(AddonModLessonListLinkHandlerService);

View File

@ -18,7 +18,6 @@ import { CoreConstants } from '@/core/constants';
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
import { CoreCourse, CoreCourseAnyModuleData, CoreCourseWSModule } from '@features/course/services/course';
import { CoreCourseModule } from '@features/course/services/course-helper';
import { AddonModLesson } from '../lesson';
import { AddonModLessonIndexComponent } from '../../components/index';
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
@ -52,8 +51,8 @@ export class AddonModLessonModuleHandlerService implements CoreCourseModuleHandl
*
* @return Promise resolved with boolean: whether or not the handler is enabled on a site level.
*/
isEnabled(): Promise<boolean> {
return AddonModLesson.isPluginEnabled();
async isEnabled(): Promise<boolean> {
return true;
}
/**

View File

@ -221,15 +221,6 @@ export class AddonModLessonPrefetchHandlerService extends CoreCourseActivityPref
(accessInfo.preventaccessreasons.length == 1 && AddonModLesson.isPasswordProtected(accessInfo));
}
/**
* Whether or not the handler is enabled on a site level.
*
* @return Promise resolved with a boolean indicating if the handler is enabled.
*/
isEnabled(): Promise<boolean> {
return AddonModLesson.isPluginEnabled();
}
/**
* @inheritdoc
*/

View File

@ -20,7 +20,6 @@ import { CoreCourse } from '@features/course/services/course';
import { CoreNavigator } from '@services/navigator';
import { CoreDomUtils } from '@services/utils/dom';
import { makeSingleton } from '@singletons';
import { AddonModLesson } from '../lesson';
import { AddonModLessonModuleHandlerService } from './module';
/**
@ -81,7 +80,7 @@ export class AddonModLessonReportLinkHandlerService extends CoreContentLinksHand
return false;
}
return AddonModLesson.isPluginEnabled(siteId);
return true;
}
/**

View File

@ -2710,19 +2710,6 @@ export class AddonModLessonProvider {
return false;
}
/**
* Return whether or not the plugin is enabled in a certain site. Plugin is enabled if the lesson WS are available.
*
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with true if plugin is enabled, rejected or resolved with false otherwise.
*/
async isPluginEnabled(siteId?: string): Promise<boolean> {
const site = await CoreSites.getSite(siteId);
// All WS were introduced at the same time so checking one is enough.
return site.wsAvailable('mod_lesson_get_lesson_access_information');
}
/**
* Check if a page is a question page or a content page.
*

View File

@ -331,7 +331,7 @@ export type AddonModLtiLti = {
name: string; // LTI name.
intro?: string; // The LTI intro.
introformat?: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
introfiles?: CoreWSExternalFile[]; // @since 3.2.
introfiles?: CoreWSExternalFile[];
timecreated?: number; // Time of creation.
timemodified?: number; // Time of last modification.
typeid?: number; // Type id.

View File

@ -15,7 +15,7 @@
import { Component, OnInit, Optional } from '@angular/core';
import { CoreCourseModuleMainResourceComponent } from '@features/course/classes/main-resource-component';
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
import { CoreCourse, CoreCourseWSModule } from '@features/course/services/course';
import { CoreCourse } from '@features/course/services/course';
import { CoreTextUtils } from '@services/utils/text';
import { CoreUtils } from '@services/utils/utils';
import { AddonModPageProvider, AddonModPagePage, AddonModPage } from '../../services/page';
@ -32,12 +32,11 @@ import { AddonModPageHelper } from '../../services/page-helper';
export class AddonModPageIndexComponent extends CoreCourseModuleMainResourceComponent implements OnInit {
component = AddonModPageProvider.COMPONENT;
canGetPage = false;
contents?: string;
displayDescription = true;
displayTimemodified = true;
timemodified?: number;
page?: CoreCourseWSModule | AddonModPagePage;
page?: AddonModPagePage;
warning?: string;
protected fetchContentDefaultError = 'addon.mod_page.errorwhileloadingthepage';
@ -52,8 +51,6 @@ export class AddonModPageIndexComponent extends CoreCourseModuleMainResourceComp
async ngOnInit(): Promise<void> {
super.ngOnInit();
this.canGetPage = AddonModPage.isGetPageWSAvailable();
await this.loadContent();
try {
@ -103,21 +100,13 @@ export class AddonModPageIndexComponent extends CoreCourseModuleMainResourceComp
*/
protected async loadPageData(): Promise<void> {
// Get latest title, description and some extra data. Data should've been updated in download.
const page = this.canGetPage ?
await AddonModPage.getPageData(this.courseId, this.module.id) :
await CoreCourse.getModule(this.module.id, this.courseId);
this.page = await AddonModPage.getPageData(this.courseId, this.module.id);
this.description = 'intro' in page ? page.intro : page.description;
this.dataRetrieved.emit(page);
if (!this.canGetPage) {
return;
}
this.page = page;
this.description = this.page.intro;
this.dataRetrieved.emit(this.page);
// Check if description and timemodified should be displayed.
if ('displayoptions' in this.page) {
if (this.page.displayoptions) {
const options: Record<string, string | boolean> =
CoreTextUtils.unserialize(this.page.displayoptions) || {};

View File

@ -42,10 +42,7 @@ export class AddonModPagePrefetchHandlerService extends CoreCourseResourcePrefet
const promises: Promise<unknown>[] = [];
promises.push(super.downloadOrPrefetch(module, courseId, prefetch));
if (AddonModPage.isGetPageWSAvailable()) {
promises.push(AddonModPage.getPageData(courseId, module.id));
}
promises.push(AddonModPage.getPageData(courseId, module.id));
await Promise.all(promises);
}

View File

@ -124,16 +124,6 @@ export class AddonModPageProvider {
await site.invalidateWsCacheForKey(this.getPageCacheKey(courseId));
}
/**
* Returns whether or not getPage WS available or not.
*
* @return If WS is available.
* @since 3.3
*/
isGetPageWSAvailable(): boolean {
return CoreSites.wsAvailableInCurrentSite('mod_page_get_pages_by_courses');
}
/**
* Return whether or not the plugin is enabled.
*

View File

@ -18,7 +18,6 @@ import { Component, OnDestroy, OnInit, Optional } from '@angular/core';
import { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component';
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
import { CoreCourse } from '@features/course/services/course';
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
import { IonContent } from '@ionic/angular';
import { CoreNavigator } from '@services/navigator';
@ -154,7 +153,7 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
// If the site doesn't support check updates, always prefetch it because we cannot tell if there's something new.
const isDownloaded = this.currentStatus == CoreConstants.DOWNLOADED;
if (isDownloaded && CoreCourseModulePrefetchDelegate.canCheckUpdates()) {
if (isDownloaded) {
// Already downloaded, open it.
return this.openQuiz();
}
@ -168,7 +167,7 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
// Success downloading, open quiz.
this.openQuiz();
} catch (error) {
if (this.hasOffline || (isDownloaded && !CoreCourseModulePrefetchDelegate.canCheckUpdates())) {
if (this.hasOffline) {
// Error downloading but there is something offline, allow continuing it.
// If the site doesn't support check updates, continue too because we cannot tell if there's something new.
this.openQuiz();
@ -647,9 +646,7 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
if (data) {
this.gradebookData = {
grade: 'graderaw' in data && data.graderaw !== undefined && data.graderaw !== null ?
data.graderaw :
(data.grade !== undefined && data.grade !== null ? Number(data.grade) : undefined),
grade: data.graderaw ?? (data.grade !== undefined && data.grade !== null ? Number(data.grade) : undefined),
feedback: data.feedback,
};
}

View File

@ -111,7 +111,6 @@ export class AddonModQuizPrefetchHandlerService extends CoreCourseActivityPrefet
attempts: AddonModQuizAttemptWSData[],
siteId?: string,
): Promise<CoreWSFile[]> {
const getInlineFiles = CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.2');
let files: CoreWSFile[] = [];
await Promise.all(attempts.map(async (attempt) => {
@ -131,12 +130,8 @@ export class AddonModQuizPrefetchHandlerService extends CoreCourseActivityPrefet
siteId,
});
if (getInlineFiles && feedback.feedbackinlinefiles?.length) {
if (feedback.feedbackinlinefiles?.length) {
files = files.concat(feedback.feedbackinlinefiles);
} else if (feedback.feedbacktext && !getInlineFiles) {
files = files.concat(
CoreFilepool.extractDownloadableFilesFromHtmlAsFakeFileObjects(feedback.feedbacktext),
);
}
}));
@ -526,7 +521,7 @@ export class AddonModQuizPrefetchHandlerService extends CoreCourseActivityPrefet
try {
const gradebookData = await AddonModQuiz.getGradeFromGradebook(quiz.course, quiz.coursemodule, true, siteId);
if (gradebookData && 'graderaw' in gradebookData && gradebookData.graderaw !== undefined) {
if (gradebookData && gradebookData.graderaw !== undefined) {
await AddonModQuiz.getFeedbackForGrade(quiz.id, gradebookData.graderaw, modOptions);
}
} catch {

View File

@ -19,7 +19,7 @@ import { CoreWSError } from '@classes/errors/wserror';
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
import { CoreGradesFormattedItem, CoreGradesFormattedRow, CoreGradesHelper } from '@features/grades/services/grades-helper';
import { CoreGradesFormattedItem, CoreGradesHelper } from '@features/grades/services/grades-helper';
import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications';
import {
CoreQuestion,
@ -647,7 +647,7 @@ export class AddonModQuizProvider {
ignoreCache?: boolean,
siteId?: string,
userId?: number,
): Promise<CoreGradesFormattedItem | CoreGradesFormattedRow | undefined> {
): Promise<CoreGradesFormattedItem | undefined> {
const items = await CoreGradesHelper.getGradeModuleItems(
courseId,

View File

@ -16,7 +16,7 @@ import { Component, OnDestroy, OnInit, Optional } from '@angular/core';
import { CoreError } from '@classes/errors/error';
import { CoreCourseModuleMainResourceComponent } from '@features/course/classes/main-resource-component';
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
import { CoreCourse, CoreCourseWSModule } from '@features/course/services/course';
import { CoreCourse } from '@features/course/services/course';
import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate';
import { CoreApp } from '@services/app';
import { CoreFileHelper } from '@services/file-helper';
@ -30,7 +30,6 @@ import {
AddonModResource,
AddonModResourceCustomData,
AddonModResourceProvider,
AddonModResourceResource,
} from '../../services/resource';
import { AddonModResourceHelper } from '../../services/resource-helper';
@ -45,7 +44,6 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
component = AddonModResourceProvider.COMPONENT;
canGetResource = false;
mode = '';
src = '';
contentText = '';
@ -69,7 +67,6 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
async ngOnInit(): Promise<void> {
super.ngOnInit();
this.canGetResource = AddonModResource.isGetResourceWSAvailable();
this.isIOS = CoreApp.isIOS();
this.isOnline = CoreApp.isOnline();
@ -110,26 +107,17 @@ export class AddonModResourceIndexComponent extends CoreCourseModuleMainResource
throw new CoreError(Translate.instant('core.filenotfound'));
}
let resource: AddonModResourceResource | CoreCourseWSModule | undefined;
let options: AddonModResourceCustomData = {};
let hasCalledDownloadResource = false;
// Get the resource instance to get the latest name/description and to know if it's embedded.
if (this.canGetResource) {
resource = await AddonModResource.getResourceData(this.courseId, this.module.id);
this.description = resource.intro || '';
options = resource.displayoptions ? CoreTextUtils.unserialize(resource.displayoptions) : {};
} else {
resource = await CoreCourse.getModule(this.module.id, this.courseId);
this.description = resource.description || '';
options = resource.customdata ? CoreTextUtils.unserialize(CoreTextUtils.parseJSON(resource.customdata)) : {};
}
const resource = await AddonModResource.getResourceData(this.courseId, this.module.id);
this.description = resource.intro || '';
const options: AddonModResourceCustomData =
resource.displayoptions ? CoreTextUtils.unserialize(resource.displayoptions) : {};
try {
if (resource) {
this.displayDescription = typeof options.printintro == 'undefined' || !!options.printintro;
this.dataRetrieved.emit(resource);
}
this.displayDescription = typeof options.printintro == 'undefined' || !!options.printintro;
this.dataRetrieved.emit(resource);
if (AddonModResourceHelper.isDisplayedInIframe(this.module)) {
hasCalledDownloadResource = true;

View File

@ -156,7 +156,7 @@ export class AddonModResourceModuleHandlerService implements CoreCourseModuleHan
if ('customdata' in module && typeof module.customdata != 'undefined') {
options = CoreTextUtils.unserialize(CoreTextUtils.parseJSON(module.customdata));
} else if (AddonModResource.isGetResourceWSAvailable()) {
} else {
// Get the resource data.
promises.push(AddonModResource.getResourceData(courseId, module.id).then((info) => {
infoFiles = info.contentfiles;

View File

@ -67,10 +67,7 @@ export class AddonModResourcePrefetchHandlerService extends CoreCourseResourcePr
const promises: Promise<unknown>[] = [];
promises.push(super.downloadOrPrefetch(module, courseId, prefetch, dirPath));
if (AddonModResource.isGetResourceWSAvailable()) {
promises.push(AddonModResource.getResourceData(courseId, module.id));
}
promises.push(AddonModResource.getResourceData(courseId, module.id));
await Promise.all(promises);
}

View File

@ -130,16 +130,6 @@ export class AddonModResourceProvider {
await site.invalidateWsCacheForKey(this.getResourceCacheKey(courseId));
}
/**
* Returns whether or not getResource WS available or not.
*
* @return If WS is abalaible.
* @since 3.3
*/
isGetResourceWSAvailable(): boolean {
return CoreSites.wsAvailableInCurrentSite('mod_resource_get_resources_by_courses');
}
/**
* Return whether or not the plugin is enabled.
*

View File

@ -1612,11 +1612,6 @@ export class AddonModScormProvider {
};
const wsFunction = 'mod_scorm_insert_scorm_tracks';
// Check if the method is available, use a prefixed version if possible.
if (!currentSite.wsAvailable(wsFunction, false)) {
return false;
}
try {
const response = CoreWS.syncCall<AddonModScormInsertScormTracksWSResponse>(wsFunction, params, preSets);

View File

@ -322,7 +322,7 @@ export type AddonModSurveySurvey = {
name: string; // Survey name.
intro?: string; // The Survey intro.
introformat?: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
introfiles?: CoreWSExternalFile[]; // @since 3.2.
introfiles?: CoreWSExternalFile[];
template?: number; // Survey type.
days?: number; // Days.
questions?: string; // Question ids.

View File

@ -36,7 +36,6 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
component = AddonModUrlProvider.COMPONENT;
canGetUrl = false;
url?: string;
name?: string;
shouldEmbed = false;
@ -58,8 +57,6 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
async ngOnInit(): Promise<void> {
super.ngOnInit();
this.canGetUrl = AddonModUrl.isGetUrlWSAvailable();
await this.loadContent();
if ((this.shouldIframe ||
@ -86,9 +83,6 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
*/
protected async fetchContent(refresh = false): Promise<void> {
try {
if (!this.canGetUrl) {
throw null;
}
// Fetch the module data.
const url = await AddonModUrl.getUrl(this.courseId, this.module.id);
@ -110,7 +104,7 @@ export class AddonModUrlIndexComponent extends CoreCourseModuleMainResourceCompo
await this.calculateDisplayOptions(url);
} catch {
// Fallback in case is not prefetched or not available.
// Fallback in case is not prefetched.
const mod =
await CoreCourse.getModule(this.module.id, this.courseId, undefined, false, false, undefined, 'url');

View File

@ -175,7 +175,7 @@ export class AddonModUrlModuleHandlerService implements CoreCourseModuleHandler
if (canHandle) {
// URL handled by the app, open it directly.
return true;
} else if (AddonModUrl.isGetUrlWSAvailable()) {
} else {
// Not handled by the app, check the display type.
const url = await CoreUtils.ignoreErrors(AddonModUrl.getUrl(courseId, module.id));
const displayType = AddonModUrl.getFinalDisplayType(url);
@ -183,8 +183,6 @@ export class AddonModUrlModuleHandlerService implements CoreCourseModuleHandler
return displayType == CoreConstants.RESOURCELIB_DISPLAY_OPEN ||
displayType == CoreConstants.RESOURCELIB_DISPLAY_POPUP;
}
return false;
} catch {
return false;
}

View File

@ -206,16 +206,6 @@ export class AddonModUrlProvider {
await site.invalidateWsCacheForKey(this.getUrlCacheKey(courseId));
}
/**
* Returns whether or not getUrl WS available or not.
*
* @return If WS is abalaible.
* @since 3.3
*/
isGetUrlWSAvailable(): boolean {
return CoreSites.wsAvailableInCurrentSite('mod_url_get_urls_by_courses');
}
/**
* Report the url as being viewed.
*

View File

@ -178,9 +178,7 @@ export class AddonModWikiProvider {
if (section) {
params.section = section;
}
// This parameter requires Moodle 3.2. It saves network usage.
if (lockOnly && site.isVersionGreaterEqualThan('3.2')) {
if (lockOnly) {
params.lockonly = true;
}

View File

@ -15,7 +15,7 @@
import { Injectable } from '@angular/core';
import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler';
import { makeSingleton } from '@singletons';
import { AddonModWorkshopProvider, AddonModWorkshop } from '../workshop';
import { AddonModWorkshopProvider } from '../workshop';
/**
* Handler to treat links to workshop.
*/
@ -28,12 +28,5 @@ export class AddonModWorkshopIndexLinkHandlerService extends CoreContentLinksMod
super(AddonModWorkshopProvider.COMPONENT, 'workshop', 'w');
}
/**
* @inheritdoc
*/
isEnabled(siteId: string): Promise<boolean> {
return AddonModWorkshop.isPluginEnabled(siteId);
}
}
export const AddonModWorkshopIndexLinkHandler = makeSingleton(AddonModWorkshopIndexLinkHandlerService);

Some files were not shown because too many files have changed in this diff Show More