diff --git a/scripts/langindex.json b/scripts/langindex.json index 6d97093db..2736fd5a9 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -2326,6 +2326,7 @@ "core.userdeleted": "moodle", "core.userdetails": "moodle", "core.usernotfullysetup": "error", + "core.usersuspended": "moodle", "core.users": "moodle", "core.view": "moodle", "core.viewcode": "local_moodlemobileapp", diff --git a/src/core/classes/site.ts b/src/core/classes/site.ts index 8989abfde..50ba03d5c 100644 --- a/src/core/classes/site.ts +++ b/src/core/classes/site.ts @@ -615,6 +615,12 @@ export class CoreSite { CoreEvents.trigger(CoreEvents.USER_DELETED, { params: data }, this.id); error.message = Translate.instant('core.userdeleted'); + throw new CoreWSError(error); + } else if (error.errorcode === 'wsaccessusersuspended') { + // User suspended, trigger event. + CoreEvents.trigger(CoreEvents.USER_SUSPENDED, { params: data }, this.id); + error.message = Translate.instant('core.usersuspended'); + throw new CoreWSError(error); } else if (error.errorcode === 'forcepasswordchangenotice') { // Password Change Forced, trigger event. Try to get data from cache, the event will handle the error. diff --git a/src/core/features/user/pages/profile/profile.html b/src/core/features/user/pages/profile/profile.html index 1d12c3003..e135eced7 100644 --- a/src/core/features/user/pages/profile/profile.html +++ b/src/core/features/user/pages/profile/profile.html @@ -88,6 +88,7 @@ + diff --git a/src/core/features/user/pages/profile/profile.page.ts b/src/core/features/user/pages/profile/profile.page.ts index e23ff8f3c..a4cdef678 100644 --- a/src/core/features/user/pages/profile/profile.page.ts +++ b/src/core/features/user/pages/profile/profile.page.ts @@ -53,6 +53,7 @@ export class CoreUserProfilePage implements OnInit, OnDestroy { isLoadingHandlers = false; user?: CoreUserProfile; isDeleted = false; + isSuspended = false; isEnrolled = true; rolesFormatted?: string; actionHandlers: CoreUserProfileHandlerData[] = []; @@ -114,6 +115,7 @@ export class CoreUserProfilePage implements OnInit, OnDestroy { await CoreUser.logView(this.userId, this.courseId, this.user.fullname); } catch (error) { this.isDeleted = error?.errorcode === 'userdeleted'; + this.isSuspended = error?.errorcode === 'wsaccessusersuspended'; this.isEnrolled = error?.errorcode !== 'notenrolledprofile'; } } finally { diff --git a/src/core/features/user/services/user.ts b/src/core/features/user/services/user.ts index 15e2236ad..c74c9642d 100644 --- a/src/core/features/user/services/user.ts +++ b/src/core/features/user/services/user.ts @@ -22,7 +22,7 @@ import { CoreUserOffline } from './user-offline'; import { CoreLogger } from '@singletons/logger'; import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; import { makeSingleton, Translate } from '@singletons'; -import { CoreEvents } from '@singletons/events'; +import { CoreEvents, CoreEventSiteData, CoreEventUserDeletedData, CoreEventUserSuspendedData } from '@singletons/events'; import { CoreStatusWithWarningsWSResponse, CoreWSExternalWarning } from '@services/ws'; import { CoreError } from '@classes/errors/error'; import { USERS_TABLE_NAME, CoreUserDBRecord } from './database/user'; @@ -61,24 +61,8 @@ export class CoreUserProvider { constructor() { this.logger = CoreLogger.getInstance('CoreUserProvider'); - CoreEvents.on(CoreEvents.USER_DELETED, (data) => { - // Search for userid in params. - let userId = 0; - - if (data.params.userid) { - userId = data.params.userid; - } else if (data.params.userids) { - userId = data.params.userids[0]; - } else if (data.params.field === 'id' && data.params.values && data.params.values.length) { - userId = data.params.values[0]; - } else if (data.params.userlist && data.params.userlist.length) { - userId = data.params.userlist[0].userid; - } - - if (userId > 0) { - this.deleteStoredUser(userId, data.siteId); - } - }); + CoreEvents.on(CoreEvents.USER_DELETED, data => this.handleUserKickedOutEvent(data)); + CoreEvents.on(CoreEvents.USER_SUSPENDED, data => this.handleUserKickedOutEvent(data)); } /** @@ -153,6 +137,32 @@ export class CoreUserProvider { return result.profileimageurl!; } + /** + * Handle an event where a user was kicked out of the site. + * + * @param data Event data. + */ + async handleUserKickedOutEvent( + data: CoreEventSiteData & (CoreEventUserDeletedData | CoreEventUserSuspendedData), + ): Promise { + // Search for userid in params. + let userId = 0; + + if (data.params.userid) { + userId = data.params.userid; + } else if (data.params.userids) { + userId = data.params.userids[0]; + } else if (data.params.field === 'id' && data.params.values && data.params.values.length) { + userId = data.params.values[0]; + } else if (data.params.userlist && data.params.userlist.length) { + userId = data.params.userlist[0].userid; + } + + if (userId > 0) { + await this.deleteStoredUser(userId, data.siteId); + } + } + /** * Store user basic information in local DB to be retrieved if the WS call fails. * diff --git a/src/core/lang.json b/src/core/lang.json index 6690dc4bb..f31ccea49 100644 --- a/src/core/lang.json +++ b/src/core/lang.json @@ -326,6 +326,7 @@ "userdeleted": "This user account has been deleted", "userdetails": "User details", "usernotfullysetup": "User not fully set-up", + "usersuspended": "This user account has been suspended", "users": "Users", "view": "View", "viewcode": "View code", diff --git a/src/core/services/utils/utils.ts b/src/core/services/utils/utils.ts index 2b72fb6c3..9d79f6f63 100644 --- a/src/core/services/utils/utils.ts +++ b/src/core/services/utils/utils.ts @@ -862,6 +862,7 @@ export class CoreUtilsProvider { error.errorcode != 'userdeleted' && error.errorcode != 'upgraderunning' && error.errorcode != 'forcepasswordchangenotice' && error.errorcode != 'usernotfullysetup' && error.errorcode != 'sitepolicynotagreed' && error.errorcode != 'sitemaintenance' && + error.errorcode != 'wsaccessusersuspended' && !this.isExpiredTokenError(error))); } diff --git a/src/core/singletons/events.ts b/src/core/singletons/events.ts index ecc3a9ad8..21b0594ef 100644 --- a/src/core/singletons/events.ts +++ b/src/core/singletons/events.ts @@ -43,6 +43,7 @@ export interface CoreEventsData { [CoreEvents.COURSE_STATUS_CHANGED]: CoreEventCourseStatusChanged; [CoreEvents.PACKAGE_STATUS_CHANGED]: CoreEventPackageStatusChanged; [CoreEvents.USER_DELETED]: CoreEventUserDeletedData; + [CoreEvents.USER_SUSPENDED]: CoreEventUserSuspendedData; [CoreEvents.FORM_ACTION]: CoreEventFormActionData; [CoreEvents.NOTIFICATION_SOUND_CHANGED]: CoreEventNotificationSoundChangedData; [CoreEvents.SELECT_COURSE_TAB]: CoreEventSelectCourseTabData; @@ -79,6 +80,7 @@ export class CoreEvents { static readonly COMPLETION_MODULE_VIEWED = 'completion_module_viewed'; static readonly MANUAL_COMPLETION_CHANGED = 'manual_completion_changed'; static readonly USER_DELETED = 'user_deleted'; + static readonly USER_SUSPENDED = 'user_suspended'; static readonly PACKAGE_STATUS_CHANGED = 'package_status_changed'; static readonly COURSE_STATUS_CHANGED = 'course_status_changed'; static readonly SECTION_STATUS_CHANGED = 'section_status_changed'; @@ -302,6 +304,14 @@ export type CoreEventUserDeletedData = { params: any; // Params sent to the WS that failed. }; +/** + * Data passed to USER_SUSPENDED event. + */ +export type CoreEventUserSuspendedData = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + params: any; // Params sent to the WS that failed. +}; + export enum CoreEventFormAction { CANCEL = 'cancel', SUBMIT = 'submit',