diff --git a/src/addons/badges/services/badges.ts b/src/addons/badges/services/badges.ts index 939f18552df..2aed4eb2227 100644 --- a/src/addons/badges/services/badges.ts +++ b/src/addons/badges/services/badges.ts @@ -15,7 +15,7 @@ import { Injectable } from '@angular/core'; import { CoreSites } from '@services/sites'; import { CoreWSExternalWarning } from '@services/ws'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; import { CoreError } from '@classes/errors/error'; diff --git a/src/addons/block/myoverview/components/myoverview/myoverview.ts b/src/addons/block/myoverview/components/myoverview/myoverview.ts index efe60ab1425..e749a714589 100644 --- a/src/addons/block/myoverview/components/myoverview/myoverview.ts +++ b/src/addons/block/myoverview/components/myoverview/myoverview.ts @@ -26,7 +26,7 @@ import { CoreCoursesHelper, CoreEnrolledCourseDataWithExtraInfoAndOptions } from import { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper'; import { CoreCourseOptionsDelegate } from '@features/course/services/course-options-delegate'; import { CoreBlockBaseComponent } from '@features/block/classes/base-block-component'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreUtils } from '@services/utils/utils'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; diff --git a/src/addons/block/recentlyaccessedcourses/components/recentlyaccessedcourses/recentlyaccessedcourses.ts b/src/addons/block/recentlyaccessedcourses/components/recentlyaccessedcourses/recentlyaccessedcourses.ts index 82d1834c3c6..e45b1b6fea7 100644 --- a/src/addons/block/recentlyaccessedcourses/components/recentlyaccessedcourses/recentlyaccessedcourses.ts +++ b/src/addons/block/recentlyaccessedcourses/components/recentlyaccessedcourses/recentlyaccessedcourses.ts @@ -30,7 +30,7 @@ import { CoreCourseOptionsDelegate } from '@features/course/services/course-opti import { AddonCourseCompletion } from '@addons/coursecompletion/services/coursecompletion'; import { CoreBlockBaseComponent } from '@features/block/classes/base-block-component'; import { CoreUtils } from '@services/utils/utils'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; /** * Component to render a recent courses block. diff --git a/src/addons/block/recentlyaccesseditems/services/recentlyaccesseditems.ts b/src/addons/block/recentlyaccesseditems/services/recentlyaccesseditems.ts index cbf2c518789..13ca419b700 100644 --- a/src/addons/block/recentlyaccesseditems/services/recentlyaccesseditems.ts +++ b/src/addons/block/recentlyaccesseditems/services/recentlyaccesseditems.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreCourse } from '@features/course/services/course'; -import { CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { makeSingleton } from '@singletons'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; diff --git a/src/addons/block/starredcourses/components/starredcourses/starredcourses.ts b/src/addons/block/starredcourses/components/starredcourses/starredcourses.ts index 7f75e68bdab..f3382532527 100644 --- a/src/addons/block/starredcourses/components/starredcourses/starredcourses.ts +++ b/src/addons/block/starredcourses/components/starredcourses/starredcourses.ts @@ -24,7 +24,7 @@ import { CoreCourseOptionsDelegate } from '@features/course/services/course-opti import { AddonCourseCompletion } from '@addons/coursecompletion/services/coursecompletion'; import { CoreBlockBaseComponent } from '@features/block/classes/base-block-component'; import { CoreUtils } from '@services/utils/utils'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { AddonBlockStarredCourse, AddonBlockStarredCourses } from '../../services/starredcourses'; /** diff --git a/src/addons/block/starredcourses/services/starredcourses.ts b/src/addons/block/starredcourses/services/starredcourses.ts index 140bce94e8d..5b7e8834d9f 100644 --- a/src/addons/block/starredcourses/services/starredcourses.ts +++ b/src/addons/block/starredcourses/services/starredcourses.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreSites } from '@services/sites'; -import { CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { makeSingleton } from '@singletons'; const ROOT_CACHE_KEY = 'AddonBlockStarredCourses:'; diff --git a/src/addons/block/timeline/services/timeline.ts b/src/addons/block/timeline/services/timeline.ts index b24aff0a279..84cb541117a 100644 --- a/src/addons/block/timeline/services/timeline.ts +++ b/src/addons/block/timeline/services/timeline.ts @@ -24,7 +24,7 @@ import { } from '@addons/calendar/services/calendar'; import moment from 'moment-timezone'; import { makeSingleton } from '@singletons'; -import { CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; // Cache key was maintained from block myoverview when blocks were splitted. const ROOT_CACHE_KEY = 'myoverview:'; diff --git a/src/addons/blog/services/blog.ts b/src/addons/blog/services/blog.ts index c3491951e98..9b91ee30726 100644 --- a/src/addons/blog/services/blog.ts +++ b/src/addons/blog/services/blog.ts @@ -13,7 +13,8 @@ // limitations under the License. import { Injectable } from '@angular/core'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; +import { CoreSite } from '@classes/sites/site'; import { CoreTagItem } from '@features/tag/services/tag'; import { CoreSites } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; diff --git a/src/addons/calendar/pages/edit-event/edit-event.ts b/src/addons/calendar/pages/edit-event/edit-event.ts index 993603f9e1a..20e9d23f480 100644 --- a/src/addons/calendar/pages/edit-event/edit-event.ts +++ b/src/addons/calendar/pages/edit-event/edit-event.ts @@ -34,7 +34,7 @@ import { import { AddonCalendarOffline } from '../../services/calendar-offline'; import { AddonCalendarEventTypeOption, AddonCalendarHelper } from '../../services/calendar-helper'; import { AddonCalendarSync, AddonCalendarSyncProvider } from '../../services/calendar-sync'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { Translate } from '@singletons'; import { CoreFilterHelper } from '@features/filter/services/filter-helper'; import { AddonCalendarOfflineEventDBRecord } from '../../services/database/calendar-offline'; diff --git a/src/addons/calendar/services/calendar.ts b/src/addons/calendar/services/calendar.ts index c7b4067ee1d..9bafd3be76c 100644 --- a/src/addons/calendar/services/calendar.ts +++ b/src/addons/calendar/services/calendar.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreSites } from '@services/sites'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreNetwork } from '@services/network'; import { CoreTextUtils } from '@services/utils/text'; import { CoreTimeUtils } from '@services/utils/time'; @@ -50,6 +50,7 @@ import { } from '@features/reminders/services/reminders'; import { CoreReminderDBRecord } from '@features/reminders/services/database/reminders'; import { CoreEvents } from '@singletons/events'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaCalendar:'; diff --git a/src/addons/competency/services/competency.ts b/src/addons/competency/services/competency.ts index 7f83cc0c2eb..d3c30b34eef 100644 --- a/src/addons/competency/services/competency.ts +++ b/src/addons/competency/services/competency.ts @@ -13,7 +13,8 @@ // limitations under the License. import { Injectable } from '@angular/core'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCommentsArea } from '@features/comments/services/comments'; import { CoreCourseSummary, CoreCourseModuleSummary } from '@features/course/services/course'; import { CoreUserSummary } from '@features/user/services/user'; diff --git a/src/addons/coursecompletion/services/coursecompletion.ts b/src/addons/coursecompletion/services/coursecompletion.ts index 5b257367bb1..53825c48c8c 100644 --- a/src/addons/coursecompletion/services/coursecompletion.ts +++ b/src/addons/coursecompletion/services/coursecompletion.ts @@ -17,12 +17,13 @@ import { CoreLogger } from '@singletons/logger'; import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; import { CoreCourses } from '@features/courses/services/courses'; -import { CoreSite, CoreSiteWSPreSets, WSObservable } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreStatusWithWarningsWSResponse, CoreWSExternalWarning } from '@services/ws'; import { makeSingleton } from '@singletons'; import { CoreError } from '@classes/errors/error'; import { asyncObservable, firstValueFrom } from '@/core/utils/rxjs'; import { map } from 'rxjs/operators'; +import { CoreSiteWSPreSets, WSObservable } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaCourseCompletion:'; diff --git a/src/addons/enrol/guest/services/guest.ts b/src/addons/enrol/guest/services/guest.ts index c9b77b7d518..dc5bcfdf956 100644 --- a/src/addons/enrol/guest/services/guest.ts +++ b/src/addons/enrol/guest/services/guest.ts @@ -13,7 +13,8 @@ // limitations under the License. import { Injectable } from '@angular/core'; -import { CoreSiteWSPreSets, CoreSite } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; +import { CoreSite } from '@classes/sites/site'; import { CoreEnrolEnrolmentInfo } from '@features/enrol/services/enrol'; import { CoreSites } from '@services/sites'; import { CoreWSExternalWarning } from '@services/ws'; diff --git a/src/addons/enrol/self/services/self.ts b/src/addons/enrol/self/services/self.ts index 178268decc8..a3aea2138f2 100644 --- a/src/addons/enrol/self/services/self.ts +++ b/src/addons/enrol/self/services/self.ts @@ -14,7 +14,8 @@ import { Injectable } from '@angular/core'; import { CoreWSError } from '@classes/errors/wserror'; -import { CoreSiteWSPreSets, CoreSite } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCoursesProvider } from '@features/courses/services/courses'; import { CoreSites } from '@services/sites'; import { CoreStatusWithWarningsWSResponse } from '@services/ws'; diff --git a/src/addons/filter/activitynames/services/handlers/activitynames.ts b/src/addons/filter/activitynames/services/handlers/activitynames.ts index 8b0ab6909e1..22610dd1d47 100644 --- a/src/addons/filter/activitynames/services/handlers/activitynames.ts +++ b/src/addons/filter/activitynames/services/handlers/activitynames.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/algebra/services/handlers/algebra.ts b/src/addons/filter/algebra/services/handlers/algebra.ts index 4b7859f55bb..f77e374cf14 100644 --- a/src/addons/filter/algebra/services/handlers/algebra.ts +++ b/src/addons/filter/algebra/services/handlers/algebra.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/censor/services/handlers/censor.ts b/src/addons/filter/censor/services/handlers/censor.ts index 8b62c4c3de5..2f4213fe6b0 100644 --- a/src/addons/filter/censor/services/handlers/censor.ts +++ b/src/addons/filter/censor/services/handlers/censor.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/data/services/handlers/data.ts b/src/addons/filter/data/services/handlers/data.ts index cd81af23e99..7cea88a9d45 100644 --- a/src/addons/filter/data/services/handlers/data.ts +++ b/src/addons/filter/data/services/handlers/data.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/emailprotect/services/handlers/emailprotect.ts b/src/addons/filter/emailprotect/services/handlers/emailprotect.ts index 0fa214c4616..d800e7111f6 100644 --- a/src/addons/filter/emailprotect/services/handlers/emailprotect.ts +++ b/src/addons/filter/emailprotect/services/handlers/emailprotect.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/emoticon/services/handlers/emoticon.ts b/src/addons/filter/emoticon/services/handlers/emoticon.ts index dab7d5e75f9..02847ea42ea 100644 --- a/src/addons/filter/emoticon/services/handlers/emoticon.ts +++ b/src/addons/filter/emoticon/services/handlers/emoticon.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/glossary/services/handlers/glossary.ts b/src/addons/filter/glossary/services/handlers/glossary.ts index fab73b6ebbe..4c769b0965d 100644 --- a/src/addons/filter/glossary/services/handlers/glossary.ts +++ b/src/addons/filter/glossary/services/handlers/glossary.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/mathjaxloader/services/handlers/mathjaxloader.ts b/src/addons/filter/mathjaxloader/services/handlers/mathjaxloader.ts index 5d40042a93a..7589f5be83c 100644 --- a/src/addons/filter/mathjaxloader/services/handlers/mathjaxloader.ts +++ b/src/addons/filter/mathjaxloader/services/handlers/mathjaxloader.ts @@ -21,7 +21,7 @@ import { CoreSites } from '@services/sites'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUtils } from '@services/utils/utils'; import { CoreEvents } from '@singletons/events'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/multilang/services/handlers/multilang.ts b/src/addons/filter/multilang/services/handlers/multilang.ts index 657ba27b6e2..c8e127d6a52 100644 --- a/src/addons/filter/multilang/services/handlers/multilang.ts +++ b/src/addons/filter/multilang/services/handlers/multilang.ts @@ -17,7 +17,7 @@ import { Injectable } from '@angular/core'; import { CoreLang } from '@services/lang'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFilter, CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/tex/services/handlers/tex.ts b/src/addons/filter/tex/services/handlers/tex.ts index 479e7921655..80365429038 100644 --- a/src/addons/filter/tex/services/handlers/tex.ts +++ b/src/addons/filter/tex/services/handlers/tex.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/tidy/services/handlers/tidy.ts b/src/addons/filter/tidy/services/handlers/tidy.ts index 542046dc0da..a40633a09d2 100644 --- a/src/addons/filter/tidy/services/handlers/tidy.ts +++ b/src/addons/filter/tidy/services/handlers/tidy.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/filter/urltolink/services/handlers/urltolink.ts b/src/addons/filter/urltolink/services/handlers/urltolink.ts index 4c27a49863e..9429361752b 100644 --- a/src/addons/filter/urltolink/services/handlers/urltolink.ts +++ b/src/addons/filter/urltolink/services/handlers/urltolink.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFilterDefaultHandler } from '@features/filter/services/handlers/default-filter'; import { CoreFilterFormatTextOptions } from '@features/filter/services/filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/addons/messageoutput/airnotifier/services/airnotifier.ts b/src/addons/messageoutput/airnotifier/services/airnotifier.ts index 7324fc45a2d..e8c94d7b42b 100644 --- a/src/addons/messageoutput/airnotifier/services/airnotifier.ts +++ b/src/addons/messageoutput/airnotifier/services/airnotifier.ts @@ -17,7 +17,7 @@ import { Injectable } from '@angular/core'; import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites'; import { CoreWSExternalWarning } from '@services/ws'; import { CoreConstants } from '@/core/constants'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreError } from '@classes/errors/error'; import { CoreWSError } from '@classes/errors/wserror'; import { makeSingleton, Translate } from '@singletons'; @@ -25,6 +25,7 @@ import { CoreEvents, CoreEventSiteData } from '@singletons/events'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreUtils } from '@services/utils/utils'; import { CorePath } from '@singletons/path'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaMessageOutputAirnotifier:'; diff --git a/src/addons/messages/services/messages-sync.ts b/src/addons/messages/services/messages-sync.ts index fdfbe6bad2a..ef66db7918a 100644 --- a/src/addons/messages/services/messages-sync.ts +++ b/src/addons/messages/services/messages-sync.ts @@ -31,7 +31,7 @@ import { CoreConstants } from '@/core/constants'; import { CoreUser } from '@features/user/services/user'; import { CoreError } from '@classes/errors/error'; import { CoreTextErrorObject, CoreTextUtils } from '@services/utils/text'; -import { CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; /** * Service to sync messages. diff --git a/src/addons/messages/services/messages.ts b/src/addons/messages/services/messages.ts index b4a6e6cc63d..158756a45d1 100644 --- a/src/addons/messages/services/messages.ts +++ b/src/addons/messages/services/messages.ts @@ -26,13 +26,14 @@ import { import { CoreUtils } from '@services/utils/utils'; import { CoreTimeUtils } from '@services/utils/time'; import { CoreEvents } from '@singletons/events'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreWSExternalWarning } from '@services/ws'; import { makeSingleton } from '@singletons'; import { CoreError } from '@classes/errors/error'; import { AddonMessagesSyncEvents, AddonMessagesSyncProvider } from './messages-sync'; import { CoreWSError } from '@classes/errors/wserror'; import { AddonNotificationsPreferencesNotificationProcessorState } from '@addons/notifications/services/notifications'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaMessages:'; diff --git a/src/addons/mod/assign/components/index/index.ts b/src/addons/mod/assign/components/index/index.ts index e72b848c7d6..45cd4195fcd 100644 --- a/src/addons/mod/assign/components/index/index.ts +++ b/src/addons/mod/assign/components/index/index.ts @@ -15,7 +15,7 @@ import { Component, Optional, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { Params } from '@angular/router'; import { CoreError } from '@classes/errors/error'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component'; import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; import { IonContent } from '@ionic/angular'; diff --git a/src/addons/mod/assign/services/assign.ts b/src/addons/mod/assign/services/assign.ts index ce34faf773d..413b4ac2616 100644 --- a/src/addons/mod/assign/services/assign.ts +++ b/src/addons/mod/assign/services/assign.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreInterceptor } from '@classes/interceptor'; import { CoreWSExternalWarning, CoreWSExternalFile, CoreWSFile } from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; @@ -35,6 +35,7 @@ import { AddonModAssignAutoSyncData, AddonModAssignManualSyncData, AddonModAssig import { CoreFormFields } from '@singletons/form'; import { CoreFileHelper } from '@services/file-helper'; import { CoreIonicColorNames } from '@singletons/colors'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModAssign:'; diff --git a/src/addons/mod/bigbluebuttonbn/services/bigbluebuttonbn.ts b/src/addons/mod/bigbluebuttonbn/services/bigbluebuttonbn.ts index dd1e40225a5..eb226fe30a5 100644 --- a/src/addons/mod/bigbluebuttonbn/services/bigbluebuttonbn.ts +++ b/src/addons/mod/bigbluebuttonbn/services/bigbluebuttonbn.ts @@ -15,7 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; import { CoreWSError } from '@classes/errors/wserror'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites'; diff --git a/src/addons/mod/book/services/book.ts b/src/addons/mod/book/services/book.ts index 19a86c64361..69ec1c32959 100644 --- a/src/addons/mod/book/services/book.ts +++ b/src/addons/mod/book/services/book.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreTagItem } from '@features/tag/services/tag'; import { CoreWSExternalWarning, CoreWSExternalFile, CoreWS } from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; @@ -26,6 +26,7 @@ import { CoreTextUtils } from '@services/utils/text'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreFile } from '@services/file'; import { CoreError } from '@classes/errors/error'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; /** * Constants to define how the chapters and subchapters of a book should be displayed in that table of contents. diff --git a/src/addons/mod/chat/services/chat.ts b/src/addons/mod/chat/services/chat.ts index e413d72df14..08556ab36eb 100644 --- a/src/addons/mod/chat/services/chat.ts +++ b/src/addons/mod/chat/services/chat.ts @@ -14,7 +14,8 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreUser } from '@features/user/services/user'; diff --git a/src/addons/mod/choice/services/choice.ts b/src/addons/mod/choice/services/choice.ts index 055b7affb03..260d1b01ab7 100644 --- a/src/addons/mod/choice/services/choice.ts +++ b/src/addons/mod/choice/services/choice.ts @@ -15,7 +15,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; import { CoreWSError } from '@classes/errors/wserror'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreNetwork } from '@services/network'; @@ -26,6 +26,7 @@ import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWar import { makeSingleton, Translate } from '@singletons'; import { AddonModChoiceOffline } from './choice-offline'; import { AddonModChoiceAutoSyncData, AddonModChoiceSyncProvider } from './choice-sync'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModChoice:'; diff --git a/src/addons/mod/data/services/data.ts b/src/addons/mod/data/services/data.ts index a433b1bc0d5..7bffea41d7f 100644 --- a/src/addons/mod/data/services/data.ts +++ b/src/addons/mod/data/services/data.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreRatingInfo } from '@features/rating/services/rating'; @@ -29,6 +29,7 @@ import { makeSingleton, Translate } from '@singletons'; import { AddonModDataFieldsDelegate } from './data-fields-delegate'; import { AddonModDataOffline } from './data-offline'; import { AddonModDataAutoSyncData, AddonModDataSyncProvider } from './data-sync'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModData:'; diff --git a/src/addons/mod/feedback/pages/form/form.ts b/src/addons/mod/feedback/pages/form/form.ts index 65f34f18cbb..928f705831a 100644 --- a/src/addons/mod/feedback/pages/form/form.ts +++ b/src/addons/mod/feedback/pages/form/form.ts @@ -13,7 +13,7 @@ // limitations under the License. import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourse, CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseModuleData } from '@features/course/services/course-helper'; import { CanLeave } from '@guards/can-leave'; diff --git a/src/addons/mod/feedback/services/feedback.ts b/src/addons/mod/feedback/services/feedback.ts index f44148a9713..31a29f930d9 100644 --- a/src/addons/mod/feedback/services/feedback.ts +++ b/src/addons/mod/feedback/services/feedback.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreNetwork } from '@services/network'; @@ -25,6 +25,7 @@ import { CoreWSExternalFile, CoreWSExternalWarning, CoreWSStoredFile } from '@se import { makeSingleton, Translate } from '@singletons'; import { AddonModFeedbackOffline } from './feedback-offline'; import { AddonModFeedbackAutoSyncData, AddonModFeedbackSyncProvider } from './feedback-sync'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'AddonModFeedback:'; diff --git a/src/addons/mod/folder/services/folder.ts b/src/addons/mod/folder/services/folder.ts index ab4f8f4507c..459ca6b1205 100644 --- a/src/addons/mod/folder/services/folder.ts +++ b/src/addons/mod/folder/services/folder.ts @@ -14,7 +14,8 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourse } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites'; diff --git a/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts b/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts index a32c5f97ecb..8dccdcb0250 100644 --- a/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts +++ b/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts @@ -86,7 +86,7 @@ export class AddonModForumPostOptionsMenuComponent implements OnInit { */ protected setOpenInBrowserUrl(): void { const site = CoreSites.getRequiredCurrentSite(); - if (!CoreSites.shouldDisplayInformativeLinks(site)) { + if (!site.shouldDisplayInformativeLinks()) { return; } diff --git a/src/addons/mod/forum/pages/discussion/discussion.ts b/src/addons/mod/forum/pages/discussion/discussion.ts index 3d40cf2da8d..0779c78fa1d 100644 --- a/src/addons/mod/forum/pages/discussion/discussion.ts +++ b/src/addons/mod/forum/pages/discussion/discussion.ts @@ -167,7 +167,7 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes const currentSite = CoreSites.getCurrentSite(); this.isOnline = CoreNetwork.isOnline(); - this.externalUrl = currentSite && CoreSites.shouldDisplayInformativeLinks(currentSite) ? + this.externalUrl = currentSite && currentSite.shouldDisplayInformativeLinks() ? currentSite.createSiteUrl('/mod/forum/discuss.php', { d: this.discussionId.toString() }) : undefined; this.onlineObserver = CoreNetwork.onChange().subscribe(() => { diff --git a/src/addons/mod/forum/services/forum.ts b/src/addons/mod/forum/services/forum.ts index 650dbefcc30..5c1184ab510 100644 --- a/src/addons/mod/forum/services/forum.ts +++ b/src/addons/mod/forum/services/forum.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreRatingInfo } from '@features/rating/services/rating'; @@ -29,6 +29,7 @@ import { CoreUtils } from '@services/utils/utils'; import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning, CoreWSStoredFile } from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; import { AddonModForumOffline, AddonModForumOfflineDiscussion, AddonModForumReplyOptions } from './forum-offline'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModForum:'; diff --git a/src/addons/mod/glossary/services/glossary.ts b/src/addons/mod/glossary/services/glossary.ts index bb5e1eb0f2d..f6257a11ec8 100644 --- a/src/addons/mod/glossary/services/glossary.ts +++ b/src/addons/mod/glossary/services/glossary.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreFileUploaderStoreFilesResult } from '@features/fileuploader/services/fileuploader'; @@ -28,6 +28,7 @@ import { makeSingleton, Translate } from '@singletons'; import { CoreEvents } from '@singletons/events'; import { AddonModGlossaryEntryDBRecord, ENTRIES_TABLE_NAME } from './database/glossary'; import { AddonModGlossaryOffline } from './glossary-offline'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; export const GLOSSARY_ENTRY_ADDED = 'addon_mod_glossary_entry_added'; export const GLOSSARY_ENTRY_UPDATED = 'addon_mod_glossary_entry_updated'; diff --git a/src/addons/mod/h5pactivity/components/index/index.ts b/src/addons/mod/h5pactivity/components/index/index.ts index 7af2521021a..b95684ca090 100644 --- a/src/addons/mod/h5pactivity/components/index/index.ts +++ b/src/addons/mod/h5pactivity/components/index/index.ts @@ -16,7 +16,7 @@ import { Component, Optional, OnInit, OnDestroy, Output, EventEmitter } from '@a import { IonContent } from '@ionic/angular'; import { CoreConstants } from '@/core/constants'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component'; import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; import { CoreH5PDisplayOptions } from '@features/h5p/classes/core'; diff --git a/src/addons/mod/h5pactivity/services/h5pactivity.ts b/src/addons/mod/h5pactivity/services/h5pactivity.ts index 5a23aa738a6..561a5e37bbc 100644 --- a/src/addons/mod/h5pactivity/services/h5pactivity.ts +++ b/src/addons/mod/h5pactivity/services/h5pactivity.ts @@ -17,7 +17,7 @@ import { Injectable } from '@angular/core'; import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites'; import { CoreWSExternalWarning, CoreWSExternalFile, CoreWSFile } from '@services/ws'; import { CoreUtils } from '@services/utils/utils'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreH5P } from '@features/h5p/services/h5p'; import { CoreH5PDisplayOptions } from '@features/h5p/classes/core'; @@ -27,6 +27,7 @@ import { CoreWSError } from '@classes/errors/wserror'; import { CoreError } from '@classes/errors/error'; import { AddonModH5PActivityAutoSyncData, AddonModH5PActivitySyncProvider } from './h5pactivity-sync'; import { CoreTime } from '@singletons/time'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; export const MOD_H5PACTIVITY_STATE_ID = 'state'; diff --git a/src/addons/mod/imscp/services/imscp.ts b/src/addons/mod/imscp/services/imscp.ts index 304ff4ff25f..d756a88ce2e 100644 --- a/src/addons/mod/imscp/services/imscp.ts +++ b/src/addons/mod/imscp/services/imscp.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourse, CoreCourseModuleContentFile } from '@features/course/services/course'; import { CoreCourseModuleData } from '@features/course/services/course-helper'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; @@ -26,6 +26,7 @@ import { CoreUtils } from '@services/utils/utils'; import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; import { CorePath } from '@singletons/path'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModImscp:'; diff --git a/src/addons/mod/label/services/label.ts b/src/addons/mod/label/services/label.ts index b37ddffb954..07f3c076723 100644 --- a/src/addons/mod/label/services/label.ts +++ b/src/addons/mod/label/services/label.ts @@ -14,7 +14,8 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; +import { CoreSite } from '@classes/sites/site'; import { CoreFilepool } from '@services/filepool'; import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; diff --git a/src/addons/mod/lesson/services/lesson.ts b/src/addons/mod/lesson/services/lesson.ts index af0b4945164..37ce3389d93 100644 --- a/src/addons/mod/lesson/services/lesson.ts +++ b/src/addons/mod/lesson/services/lesson.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreGradesProvider } from '@features/grades/services/grades'; @@ -28,6 +28,7 @@ import { CoreEvents } from '@singletons/events'; import { AddonModLessonPasswordDBRecord, PASSWORD_TABLE_NAME } from './database/lesson'; import { AddonModLessonOffline, AddonModLessonPageAttemptRecord } from './lesson-offline'; import { AddonModLessonAutoSyncData, AddonModLessonSyncProvider } from './lesson-sync'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModLesson:'; diff --git a/src/addons/mod/lti/services/lti.ts b/src/addons/mod/lti/services/lti.ts index 989432eab32..29f8f2aec4f 100644 --- a/src/addons/mod/lti/services/lti.ts +++ b/src/addons/mod/lti/services/lti.ts @@ -15,7 +15,8 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreFile } from '@services/file'; import { CorePlatform } from '@services/platform'; diff --git a/src/addons/mod/page/services/page.ts b/src/addons/mod/page/services/page.ts index 19579a5e8a1..af285f171fb 100644 --- a/src/addons/mod/page/services/page.ts +++ b/src/addons/mod/page/services/page.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreSitesCommonWSOptions, CoreSites } from '@services/sites'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreWSExternalWarning, CoreWSExternalFile } from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; import { CoreFilepool } from '@services/filepool'; @@ -22,6 +22,7 @@ import { CoreCourse } from '@features/course/services/course'; import { CoreUtils } from '@services/utils/utils'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreError } from '@classes/errors/error'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModPage:'; diff --git a/src/addons/mod/quiz/services/quiz.ts b/src/addons/mod/quiz/services/quiz.ts index 0c155e0b9b1..487e6f388b1 100644 --- a/src/addons/mod/quiz/services/quiz.ts +++ b/src/addons/mod/quiz/services/quiz.ts @@ -17,7 +17,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; import { CoreWSError } from '@classes/errors/wserror'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreGradesFormattedItem, CoreGradesHelper } from '@features/grades/services/grades-helper'; @@ -40,6 +40,7 @@ import { AddonModQuizAccessRuleDelegate } from './access-rules-delegate'; import { AddonModQuizAttempt } from './quiz-helper'; import { AddonModQuizOffline, AddonModQuizQuestionsWithAnswers } from './quiz-offline'; import { AddonModQuizAutoSyncData, AddonModQuizSyncProvider } from './quiz-sync'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModQuiz:'; diff --git a/src/addons/mod/resource/services/resource.ts b/src/addons/mod/resource/services/resource.ts index 2b0d1afe35c..6d9c451a764 100644 --- a/src/addons/mod/resource/services/resource.ts +++ b/src/addons/mod/resource/services/resource.ts @@ -14,7 +14,8 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourse } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreFilepool } from '@services/filepool'; diff --git a/src/addons/mod/scorm/services/scorm.ts b/src/addons/mod/scorm/services/scorm.ts index 0754ec8a35a..8fe7759d551 100644 --- a/src/addons/mod/scorm/services/scorm.ts +++ b/src/addons/mod/scorm/services/scorm.ts @@ -15,7 +15,7 @@ import { CoreConstants } from '@/core/constants'; import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreFilepool } from '@services/filepool'; @@ -31,6 +31,7 @@ import { CoreEvents } from '@singletons/events'; import { CorePath } from '@singletons/path'; import { AddonModScormOffline } from './scorm-offline'; import { AddonModScormAutoSyncEventData, AddonModScormSyncProvider } from './scorm-sync'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; // Private constants. const VALID_STATUSES = ['notattempted', 'passed', 'completed', 'failed', 'incomplete', 'browsed', 'suspend']; diff --git a/src/addons/mod/survey/services/survey.ts b/src/addons/mod/survey/services/survey.ts index 8786e7d0ed6..cb7d670b3f4 100644 --- a/src/addons/mod/survey/services/survey.ts +++ b/src/addons/mod/survey/services/survey.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreNetwork } from '@services/network'; @@ -24,6 +24,7 @@ import { CoreUtils } from '@services/utils/utils'; import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; import { AddonModSurveyOffline } from './survey-offline'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModSurvey:'; diff --git a/src/addons/mod/url/services/url.ts b/src/addons/mod/url/services/url.ts index 216ac680c2a..2e9ac211133 100644 --- a/src/addons/mod/url/services/url.ts +++ b/src/addons/mod/url/services/url.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreWSExternalWarning, CoreWSExternalFile } from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; import { CoreConstants } from '@/core/constants'; @@ -23,6 +23,7 @@ import { CoreCourse } from '@features/course/services/course'; import { CoreUtils } from '@services/utils/utils'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreError } from '@classes/errors/error'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModUrl:'; diff --git a/src/addons/mod/wiki/services/wiki.ts b/src/addons/mod/wiki/services/wiki.ts index dc79309ebcc..93fc4afea36 100644 --- a/src/addons/mod/wiki/services/wiki.ts +++ b/src/addons/mod/wiki/services/wiki.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreTagItem } from '@features/tag/services/tag'; @@ -28,6 +28,7 @@ import { CoreEvents } from '@singletons/events'; import { AddonModWikiPageDBRecord } from './database/wiki'; import { AddonModWikiOffline } from './wiki-offline'; import { AddonModWikiAutoSyncData, AddonModWikiManualSyncData, AddonModWikiSyncProvider } from './wiki-sync'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModWiki:'; diff --git a/src/addons/mod/workshop/services/workshop.ts b/src/addons/mod/workshop/services/workshop.ts index a866a4c8e4f..e84468991c3 100644 --- a/src/addons/mod/workshop/services/workshop.ts +++ b/src/addons/mod/workshop/services/workshop.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreCourseLogHelper } from '@features/course/services/log-helper'; import { CoreGradesMenuItem } from '@features/grades/services/grades-helper'; @@ -28,6 +28,7 @@ import { CoreFormFields } from '@singletons/form'; import { AddonModWorkshopOffline } from './workshop-offline'; import { AddonModWorkshopAutoSyncData, AddonModWorkshopSyncProvider } from './workshop-sync'; import { ADDON_MOD_WORKSHOP_COMPONENT } from '@addons/mod/workshop/constants'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaModWorkshop:'; diff --git a/src/addons/notes/services/notes.ts b/src/addons/notes/services/notes.ts index 0c2cfd8db4b..e15e81d6414 100644 --- a/src/addons/notes/services/notes.ts +++ b/src/addons/notes/services/notes.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreWSError } from '@classes/errors/wserror'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreUser } from '@features/user/services/user'; import { CoreNetwork } from '@services/network'; import { CoreSites } from '@services/sites'; @@ -22,6 +22,7 @@ import { CoreUtils } from '@services/utils/utils'; import { CoreWSExternalWarning } from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; import { AddonNotesOffline } from './notes-offline'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmaNotes:'; diff --git a/src/addons/notifications/services/notifications.ts b/src/addons/notifications/services/notifications.ts index 268551e63da..aeaf0660f7e 100644 --- a/src/addons/notifications/services/notifications.ts +++ b/src/addons/notifications/services/notifications.ts @@ -19,11 +19,12 @@ import { CoreWSExternalWarning } from '@services/ws'; import { CoreTextUtils } from '@services/utils/text'; import { CoreTimeUtils } from '@services/utils/time'; import { CoreUser, USER_NOREPLY_USER } from '@features/user/services/user'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreLogger } from '@singletons/logger'; import { Translate, makeSingleton } from '@singletons'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { AddonNotificationsPushNotification } from './handlers/push-click'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; declare module '@singletons/events' { diff --git a/src/addons/privatefiles/services/privatefiles.ts b/src/addons/privatefiles/services/privatefiles.ts index d1194fdba9a..3d5e4797d8f 100644 --- a/src/addons/privatefiles/services/privatefiles.ts +++ b/src/addons/privatefiles/services/privatefiles.ts @@ -17,7 +17,7 @@ import { Injectable } from '@angular/core'; import { CoreSites } from '@services/sites'; import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreWSExternalWarning } from '@services/ws'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; const ROOT_CACHE_KEY = 'mmaFiles:'; diff --git a/src/addons/remotethemes/services/remotethemes-handler.ts b/src/addons/remotethemes/services/remotethemes-handler.ts index cf2673c1ac7..c4c96e5b58d 100644 --- a/src/addons/remotethemes/services/remotethemes-handler.ts +++ b/src/addons/remotethemes/services/remotethemes-handler.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreConstants } from '@/core/constants'; -import { CoreSitePublicConfigResponse } from '@classes/site'; +import { CoreSitePublicConfigResponse } from '@classes/sites/unauthenticated-site'; import { CoreFile } from '@services/file'; import { CoreFilepool } from '@services/filepool'; import { CoreSites } from '@services/sites'; diff --git a/src/addons/report/insights/services/insights.ts b/src/addons/report/insights/services/insights.ts index 509e4fe448d..ff4f322a646 100644 --- a/src/addons/report/insights/services/insights.ts +++ b/src/addons/report/insights/services/insights.ts @@ -15,7 +15,7 @@ import { Injectable } from '@angular/core'; import { CoreSites } from '@services/sites'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; import { CoreWSExternalWarning } from '@services/ws'; import { CoreWSError } from '@classes/errors/wserror'; diff --git a/src/core/classes/delegate.ts b/src/core/classes/delegate.ts index adc2023f036..2dd5141c9f0 100644 --- a/src/core/classes/delegate.ts +++ b/src/core/classes/delegate.ts @@ -14,7 +14,7 @@ import { CoreSites } from '@services/sites'; import { CoreEvents } from '@singletons/events'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreLogger } from '@singletons/logger'; /** diff --git a/src/core/classes/page-load-watcher.ts b/src/core/classes/page-load-watcher.ts index e062e3b9810..870dcc2ac38 100644 --- a/src/core/classes/page-load-watcher.ts +++ b/src/core/classes/page-load-watcher.ts @@ -18,7 +18,7 @@ import { Subscription } from 'rxjs'; import { AsyncDirective } from './async-directive'; import { PageLoadsManager } from './page-loads-manager'; import { CorePromisedValue } from './promised-value'; -import { WSObservable } from './site'; +import { WSObservable } from './sites/authenticated-site'; /** * Class to watch requests from a page load (including requests from page sub-components). diff --git a/src/core/classes/site.ts b/src/core/classes/sites/authenticated-site.ts similarity index 58% rename from src/core/classes/site.ts rename to src/core/classes/sites/authenticated-site.ts index c090d7dd713..758b3bcbbed 100644 --- a/src/core/classes/site.ts +++ b/src/core/classes/sites/authenticated-site.ts @@ -12,84 +12,43 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { InAppBrowserObject, InAppBrowserOptions } from '@ionic-native/in-app-browser'; -import { Md5 } from 'ts-md5/dist/md5'; - import { CoreApp } from '@services/app'; import { CoreNetwork } from '@services/network'; -import { CoreDB } from '@services/db'; -import { CoreEvents } from '@singletons/events'; -import { CoreFile } from '@services/file'; +import { CoreEventData, CoreEvents } from '@singletons/events'; import { CoreWS, CoreWSPreSets, - CoreWSFileUploadOptions, - CoreWSAjaxPreSets, - CoreWSExternalWarning, - CoreWSUploadFileResult, CoreWSPreSetsSplitRequest, CoreWSTypeExpected, } from '@services/ws'; import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; -import { CoreTimeUtils } from '@services/utils/time'; -import { CoreUrlUtils } from '@services/utils/url'; -import { CoreUtils, CoreUtilsOpenInBrowserOptions } from '@services/utils/utils'; +import { CoreUtils } from '@services/utils/utils'; import { CoreConstants } from '@/core/constants'; -import { SQLiteDB } from '@classes/sqlitedb'; import { CoreError } from '@classes/errors/error'; import { CoreWSError } from '@classes/errors/wserror'; import { CoreLogger } from '@singletons/logger'; import { Translate } from '@singletons'; -import { CoreIonLoadingElement } from './ion-loading'; import { CoreLang, CoreLangFormat } from '@services/lang'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; -import { asyncInstance, AsyncInstance } from '../utils/async-instance'; -import { CoreDatabaseTable } from './database/database-table'; -import { CoreDatabaseCachingStrategy } from './database/database-table-proxy'; -import { CoreSilentError } from './errors/silenterror'; +import { CoreSilentError } from '../errors/silenterror'; import { CorePromisedValue } from '@classes/promised-value'; -import { - CONFIG_TABLE, - CoreSiteConfigDBRecord, - CoreSiteLastViewedDBRecord, - CoreSiteWSCacheRecord, - LAST_VIEWED_TABLE, - WS_CACHE_TABLE, -} from '@services/database/sites'; import { Observable, ObservableInput, ObservedValueOf, OperatorFunction, Subject } from 'rxjs'; import { finalize, map, mergeMap } from 'rxjs/operators'; -import { firstValueFrom } from '../utils/rxjs'; +import { firstValueFrom } from '../../utils/rxjs'; import { CoreSiteError } from '@classes/errors/siteerror'; import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config'; -import { CoreLoginHelper } from '@features/login/services/login-helper'; -import { CorePath } from '@singletons/path'; +import { CoreSiteInfo, CoreSiteInfoResponse, CoreSitePublicConfigResponse, CoreUnauthenticatedSite } from './unauthenticated-site'; +import { Md5 } from 'ts-md5'; +import { CoreUrlUtils } from '@services/utils/url'; +import { CoreSiteWSCacheRecord } from '@services/database/sites'; import { CoreErrorLogs } from '@singletons/error-logs'; -import { CoreFilepool } from '@services/filepool'; /** - * QR Code type enumeration. + * Class that represents a site (combination of site + user) where the user has authenticated but the site hasn't been validated + * yet, it might be a site not supported by the app. */ -export enum CoreSiteQRCodeType { - QR_CODE_DISABLED = 0, // QR code disabled value - QR_CODE_URL = 1, // QR code type URL value - QR_CODE_LOGIN = 2, // QR code type login value -} - -// WS that we allow to call even if the site is logged out. -const ALLOWED_LOGGEDOUT_WS = [ - 'core_user_remove_user_device', -]; - -/** - * Class that represents a site (combination of site + user). - * It will have all the site data and provide utility functions regarding a site. - * To add tables to the site's database, please use registerSiteSchema exported in @services/sites.ts. This will make sure that - * the tables are created in all the sites, not just the current one. - * - * @todo Refactor this class to improve "temporary" sites support (not fully authenticated). - */ -export class CoreSite { +export class CoreAuthenticatedSite extends CoreUnauthenticatedSite { static readonly REQUEST_QUEUE_FORCE_WS = false; // Use "tool_mobile_call_external_functions" even for calling a single function. @@ -117,108 +76,49 @@ export class CoreSite { }; // Possible cache update frequencies. - protected readonly UPDATE_FREQUENCIES = [ + protected static readonly UPDATE_FREQUENCIES = [ CoreConstants.CONFIG.cache_update_frequency_usually || 420000, CoreConstants.CONFIG.cache_update_frequency_often || 1200000, CoreConstants.CONFIG.cache_update_frequency_sometimes || 3600000, CoreConstants.CONFIG.cache_update_frequency_rarely || 43200000, ]; - // Rest of variables. + // WS that we allow to call even if the site is logged out. + protected static readonly ALLOWED_LOGGEDOUT_WS = [ + 'core_user_remove_user_device', + ]; + + token: string; + privateToken?: string; + infos?: CoreSiteInfo; + protected logger: CoreLogger; - protected db?: SQLiteDB; - protected cacheTable: AsyncInstance>; - protected configTable: AsyncInstance>; - protected lastViewedTable: AsyncInstance>; protected cleanUnicode = false; - protected lastAutoLogin = 0; protected offlineDisabled = false; + private memoryCache: Record = {}; + // eslint-disable-next-line @typescript-eslint/no-explicit-any protected ongoingRequests: Record | undefined>> = {}; protected requestQueue: RequestQueueItem[] = []; protected requestQueueTimeout: number | null = null; - protected tokenPluginFileWorks?: boolean; - protected tokenPluginFileWorksPromise?: Promise; - protected oauthId?: number; /** * Create a site. * - * @param id Site ID. * @param siteUrl Site URL. * @param token Site's WS token. - * @param infos Site info. - * @param privateToken Private token. - * @param config Site public config. - * @param loggedOut Whether user is logged out. + * @param otherData Other data. */ constructor( - public id: string | undefined, - public siteUrl: string, - public token?: string, - public infos?: CoreSiteInfo, - public privateToken?: string, - public config?: CoreSiteConfig, - public loggedOut?: boolean, + siteUrl: string, + token: string, + otherData: CoreAuthenticatedSiteOptionalData = {}, ) { - this.logger = CoreLogger.getInstance('CoreSite'); - this.siteUrl = CoreUrlUtils.removeUrlParams(this.siteUrl); // Make sure the URL doesn't have params. - - this.cacheTable = asyncInstance(() => CoreSites.getSiteTable(WS_CACHE_TABLE, { - siteId: this.getId(), - database: this.getDb(), - config: { cachingStrategy: CoreDatabaseCachingStrategy.None }, - })); - - this.configTable = asyncInstance(() => CoreSites.getSiteTable(CONFIG_TABLE, { - siteId: this.getId(), - database: this.getDb(), - config: { cachingStrategy: CoreDatabaseCachingStrategy.Eager }, - primaryKeyColumns: ['name'], - })); - - this.lastViewedTable = asyncInstance(() => CoreSites.getSiteTable(LAST_VIEWED_TABLE, { - siteId: this.getId(), - database: this.getDb(), - config: { cachingStrategy: CoreDatabaseCachingStrategy.Eager }, - primaryKeyColumns: ['component', 'id'], - })); - this.setInfo(infos); - this.calculateOfflineDisabled(); - - if (this.id) { - this.initDB(); - } - } - - /** - * Initialize the database. - */ - initDB(): void { - this.db = CoreDB.getDB('Site-' + this.id); - } + super(siteUrl, otherData.publicConfig); - /** - * Get site ID. - * - * @returns Site ID. - */ - getId(): string { - if (this.id === undefined) { - // Shouldn't happen for authenticated sites. - throw new CoreError('This site doesn\'t have an ID'); - } - - return this.id; - } - - /** - * Get site URL. - * - * @returns Site URL. - */ - getURL(): string { - return this.siteUrl; + this.logger = CoreLogger.getInstance('CoreAuthenticaedSite'); + this.token = token; + this.privateToken = otherData.privateToken; } /** @@ -227,18 +127,11 @@ export class CoreSite { * @returns Site token. */ getToken(): string { - if (this.token === undefined) { - // Shouldn't happen for authenticated sites. - throw new CoreError('This site doesn\'t have a token'); - } - return this.token; } /** - * Get site info. - * - * @returns Site info. + * @inheritdoc */ getInfo(): CoreSiteInfo | undefined { return this.infos; @@ -253,20 +146,6 @@ export class CoreSite { return this.privateToken; } - /** - * Get site DB. - * - * @returns Site DB. - */ - getDb(): SQLiteDB { - if (!this.db) { - // Shouldn't happen for authenticated sites. - throw new CoreError('Site DB doesn\'t exist'); - } - - return this.db; - } - /** * Get site user's ID. * @@ -290,42 +169,6 @@ export class CoreSite { return this.infos?.siteid || 1; } - /** - * Get site name. - * - * @returns Site name. - */ - async getSiteName(): Promise { - if (this.isDemoModeSite()) { - return CoreConstants.CONFIG.appname; - } - - if (this.infos?.sitename) { - return this.infos?.sitename; - } - - // Fallback. - const isSingleFixedSite = await CoreLoginHelper.isSingleFixedSite(); - - if (isSingleFixedSite) { - const sites = await CoreLoginHelper.getAvailableSites(); - - return sites[0].name; - } - - return ''; - } - - /** - * Set site ID. - * - * @param id New ID. - */ - setId(id: string): void { - this.id = id; - this.initDB(); - } - /** * Set site token. * @@ -350,16 +193,7 @@ export class CoreSite { * @returns Whether is logged out. */ isLoggedOut(): boolean { - return !!this.loggedOut; - } - - /** - * Get OAuth ID. - * - * @returns OAuth ID. - */ - getOAuthId(): number | undefined { - return this.oauthId; + return false; } /** @@ -376,38 +210,6 @@ export class CoreSite { } } - /** - * Set site config. - * - * @param config Config. - */ - setConfig(config: CoreSiteConfig): void { - if (config) { - config.tool_mobile_disabledfeatures = CoreTextUtils.treatDisabledFeatures(config.tool_mobile_disabledfeatures); - } - - this.config = config; - this.calculateOfflineDisabled(); - } - - /** - * Set site logged out. - * - * @param loggedOut True if logged out and needs to authenticate again, false otherwise. - */ - setLoggedOut(loggedOut: boolean): void { - this.loggedOut = !!loggedOut; - } - - /** - * Set OAuth ID. - * - * @param oauthId OAuth ID. - */ - setOAuthId(oauthId: number | undefined): void { - this.oauthId = oauthId; - } - /** * Check if current user is Admin. * Works properly since v3.8. See more in: {@link} https://tracker.moodle.org/browse/MDL-65550 @@ -418,15 +220,6 @@ export class CoreSite { return this.getInfo()?.userissiteadmin ?? false; } - /** - * Check if the user authenticated in the site using an OAuth method. - * - * @returns Whether the user authenticated in the site using an OAuth method. - */ - isOAuth(): boolean { - return this.oauthId != null && this.oauthId !== undefined; - } - /** * Can the user access their private files? * @@ -594,9 +387,9 @@ export class CoreSite { */ // eslint-disable-next-line @typescript-eslint/no-explicit-any requestObservable(method: string, data: any, preSets: CoreSiteWSPreSets): WSObservable { - if (this.isLoggedOut() && !ALLOWED_LOGGEDOUT_WS.includes(method)) { + if (this.isLoggedOut() && !CoreAuthenticatedSite.ALLOWED_LOGGEDOUT_WS.includes(method)) { // Site is logged out, it cannot call WebServices. - CoreEvents.trigger(CoreEvents.SESSION_EXPIRED, {}, this.id); + this.triggerSiteEvent(CoreEvents.SESSION_EXPIRED, {}); // Use a silent error, the SESSION_EXPIRED event will display a message if needed. throw new CoreSilentError(Translate.instant('core.lostconnection')); @@ -841,41 +634,41 @@ export class CoreSite { if (CoreUtils.isExpiredTokenError(error)) { // Session expired, trigger event. - CoreEvents.trigger(CoreEvents.SESSION_EXPIRED, {}, this.id); + this.triggerSiteEvent(CoreEvents.SESSION_EXPIRED, {}); // Change error message. Try to get data from cache, the event will handle the error. error.message = Translate.instant('core.lostconnection'); useSilentError = true; // Use a silent error, the SESSION_EXPIRED event will display a message if needed. } else if (error.errorcode === 'userdeleted' || error.errorcode === 'wsaccessuserdeleted') { // User deleted, trigger event. - CoreEvents.trigger(CoreEvents.USER_DELETED, { params: data }, this.id); + this.triggerSiteEvent(CoreEvents.USER_DELETED, { params: data }); 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); + this.triggerSiteEvent(CoreEvents.USER_SUSPENDED, { params: data }); error.message = Translate.instant('core.usersuspended'); throw new CoreWSError(error); } else if (error.errorcode === 'wsaccessusernologin') { // User suspended, trigger event. - CoreEvents.trigger(CoreEvents.USER_NO_LOGIN, { params: data }, this.id); + this.triggerSiteEvent(CoreEvents.USER_NO_LOGIN, { params: data }); error.message = Translate.instant('core.usernologin'); 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. - CoreEvents.trigger(CoreEvents.PASSWORD_CHANGE_FORCED, {}, this.id); + this.triggerSiteEvent(CoreEvents.PASSWORD_CHANGE_FORCED, {}); error.message = Translate.instant('core.forcepasswordchangenotice'); useSilentError = true; // Use a silent error, the change password page already displays the appropiate info. } else if (error.errorcode === 'usernotfullysetup') { // User not fully setup, trigger event. Try to get data from cache, the event will handle the error. - CoreEvents.trigger(CoreEvents.USER_NOT_FULLY_SETUP, {}, this.id); + this.triggerSiteEvent(CoreEvents.USER_NOT_FULLY_SETUP, {}); error.message = Translate.instant('core.usernotfullysetup'); useSilentError = true; // Use a silent error, the complete profile page already displays the appropiate info. } else if (error.errorcode === 'sitepolicynotagreed') { // Site policy not agreed, trigger event. - CoreEvents.trigger(CoreEvents.SITE_POLICY_NOT_AGREED, {}, this.id); + this.triggerSiteEvent(CoreEvents.SITE_POLICY_NOT_AGREED, {}); error.message = Translate.instant('core.login.sitepolicynotagreederror'); throw new CoreWSError(error); @@ -910,7 +703,7 @@ export class CoreSite { this.saveToCache(method, data, error, preSets); throw new CoreWSError(error); - } else if (preSets.emergencyCache !== undefined && !preSets.emergencyCache) { + } else if (preSets.emergencyCache === false) { this.logger.debug(`WS call '${method}' failed. Emergency cache is forbidden, rejecting.`); throw new CoreWSError(error); @@ -1086,7 +879,7 @@ export class CoreSite { const requests = this.requestQueue; this.requestQueue = []; - if (requests.length == 1 && !CoreSite.REQUEST_QUEUE_FORCE_WS) { + if (requests.length == 1 && !CoreAuthenticatedSite.REQUEST_QUEUE_FORCE_WS) { // Only one request, do a regular web service call. try { const data = await CoreWS.call(requests[0].method, requests[0].data, requests[0].wsPreSets); @@ -1233,7 +1026,7 @@ export class CoreSite { preSets: CoreSiteWSPreSets, emergency?: boolean, ): Promise> { - if (!this.db || !preSets.getFromCache) { + if (!preSets.getFromCache) { throw new CoreError('Get from cache is disabled.'); } @@ -1241,11 +1034,11 @@ export class CoreSite { let entry: CoreSiteWSCacheRecord | undefined; if (preSets.getCacheUsingCacheKey || (emergency && preSets.getEmergencyCacheUsingCacheKey)) { - const entries = await this.cacheTable.getMany({ key: preSets.cacheKey }); + const entries = await this.getCacheEntriesByKey(preSets.cacheKey ?? ''); if (!entries.length) { // Cache key not found, get by params sent. - entry = await this.cacheTable.getOneByPrimaryKey({ id }); + entry = await this.getCacheEntryById(id); } else { if (entries.length > 1) { // More than one entry found. Search the one with same ID as this call. @@ -1257,7 +1050,7 @@ export class CoreSite { } } } else { - entry = await this.cacheTable.getOneByPrimaryKey({ id }); + entry = await this.getCacheEntryById(id); } if (entry === undefined) { @@ -1308,32 +1101,27 @@ export class CoreSite { } /** - * Gets the size of cached data for a specific component or component instance. + * Get cache entry by ID. * - * @param component Component name - * @param componentId Optional component id (if not included, returns sum for whole component) - * @returns Promise resolved when we have calculated the size - */ - async getComponentCacheSize(component: string, componentId?: number): Promise { - const params: Array = [component]; - let extraClause = ''; - if (componentId !== undefined && componentId !== null) { - params.push(componentId); - extraClause = ' AND componentId = ?'; + * @param id Cache ID. + * @returns Cache entry. + */ + protected async getCacheEntryById(id: string): Promise { + if (!this.memoryCache[id]) { + throw new CoreError('Cache entry not found.'); } - return this.cacheTable.reduce( - { - sql: 'SUM(length(data))', - js: (size, record) => size + record.data.length, - jsInitialValue: 0, - }, - { - sql: 'WHERE component = ?' + extraClause, - sqlParams: params, - js: record => record.component === component && (params.length === 1 || record.componentId === componentId), - }, - ); + return this.memoryCache[id]; + } + + /** + * Get cache entries by key. + * + * @param key Cache key. + * @returns Cache entries. + */ + protected async getCacheEntriesByKey(key: string): Promise { + return Object.values(this.memoryCache).filter(entry => entry.key === key); } /** @@ -1355,24 +1143,33 @@ export class CoreSite { // Since 3.7, the expiration time contains the time the entry is modified instead of the expiration time. // We decided to reuse this field to prevent modifying the database table. const id = this.getCacheId(method, data); - const entry = { + const entry: CoreSiteWSCacheRecord = { id, data: JSON.stringify(response), expirationTime: Date.now(), }; if (preSets.cacheKey) { - entry['key'] = preSets.cacheKey; + entry.key = preSets.cacheKey; } if (preSets.component) { - entry['component'] = preSets.component; + entry.component = preSets.component; if (preSets.componentId) { - entry['componentId'] = preSets.componentId; + entry.componentId = preSets.componentId; } } - await this.cacheTable.insert(entry); + await this.storeCacheEntry(entry); + } + + /** + * Store a cache entry. + * + * @param entry Entry to store. + */ + protected async storeCacheEntry(entry: CoreSiteWSCacheRecord): Promise { + this.memoryCache[entry.id] = entry; } /** @@ -1386,68 +1183,15 @@ export class CoreSite { */ // eslint-disable-next-line @typescript-eslint/no-explicit-any protected async deleteFromCache(method: string, data: any, preSets: CoreSiteWSPreSets, allCacheKey?: boolean): Promise { - const id = this.getCacheId(method, data); - if (allCacheKey) { - await this.cacheTable.delete({ key: preSets.cacheKey }); - } else { - await this.cacheTable.deleteByPrimaryKey({ id }); - } - } - - /** - * Deletes WS cache entries for all methods relating to a specific component (and - * optionally component id). - * - * @param component Component name. - * @param componentId Component id. - * @returns Promise resolved when the entries are deleted. - */ - async deleteComponentFromCache(component: string, componentId?: number): Promise { - if (!component) { - return; - } - - const params = { component }; + const entriesToDelete = await this.getCacheEntriesByKey(preSets.cacheKey ?? ''); - if (componentId) { - params['componentId'] = componentId; + entriesToDelete.forEach(entry => { + delete this.memoryCache[entry.id]; + }); + } else { + delete this.memoryCache[this.getCacheId(method, data)]; } - - await this.cacheTable.delete(params); - } - - /* - * Uploads a file using Cordova File API. - * - * @param filePath File path. - * @param options File upload options. - * @param onProgress Function to call on progress. - * @returns Promise resolved when uploaded. - */ - uploadFile( - filePath: string, - options: CoreWSFileUploadOptions, - onProgress?: (event: ProgressEvent) => void, - ): Promise { - if (!options.fileArea) { - options.fileArea = 'draft'; - } - - return CoreWS.uploadFile(filePath, options, { - siteUrl: this.siteUrl, - wsToken: this.token || '', - }, onProgress); - } - - /** - * Invalidates all caches related to the site. - */ - async invalidateCaches(): Promise { - await Promise.all([ - CoreFilepool.invalidateAllFiles(this.getId()), - this.invalidateWsCache(), - ]); } /** @@ -1456,12 +1200,12 @@ export class CoreSite { * @returns Promise resolved when the cache entries are invalidated. */ async invalidateWsCache(): Promise { - this.logger.debug('Invalidate all the cache for site: ' + this.id); - try { - await this.cacheTable.update({ expirationTime: 0 }); + for (const id in this.memoryCache) { + this.memoryCache[id].expirationTime = 0; + } } finally { - CoreEvents.trigger(CoreEvents.WS_CACHE_INVALIDATED, {}, this.getId()); + this.triggerSiteEvent(CoreEvents.WS_CACHE_INVALIDATED, {}); } } @@ -1478,7 +1222,10 @@ export class CoreSite { this.logger.debug('Invalidate cache for key: ' + key); - await this.cacheTable.update({ expirationTime: 0 }, { key }); + const entries = await this.getCacheEntriesByKey(key); + entries.forEach(entry => { + entry.expirationTime = 0; + }); } /** @@ -1488,9 +1235,6 @@ export class CoreSite { * @returns Promise resolved when the cache entries are invalidated. */ async invalidateMultipleWsCacheForKey(keys: string[]): Promise { - if (!this.db) { - throw new CoreError('Site DB not initialized'); - } if (!keys || !keys.length) { return; } @@ -1511,105 +1255,11 @@ export class CoreSite { } this.logger.debug('Invalidate cache for key starting with: ' + key); - - await this.cacheTable.updateWhere({ expirationTime: 0 }, { - sql: 'key LIKE ?', - sqlParams: [key + '%'], - js: record => !!record.key?.startsWith(key), - }); - } - - /** - * Check if tokenpluginfile can be used, and fix the URL afterwards. - * - * @param url The url to be fixed. - * @returns Promise resolved with the fixed URL. - */ - checkAndFixPluginfileURL(url: string): Promise { - return this.checkTokenPluginFile(url).then(() => this.fixPluginfileURL(url)); - } - - /** - * Generic function for adding the wstoken to Moodle urls and for pointing to the correct script. - * Uses CoreUtilsProvider.fixPluginfileURL, passing site's token. - * - * @param url The url to be fixed. - * @returns Fixed URL. - */ - fixPluginfileURL(url: string): string { - const accessKey = this.tokenPluginFileWorks || this.tokenPluginFileWorks === undefined ? - this.infos && this.infos.userprivateaccesskey : undefined; - - return CoreUrlUtils.fixPluginfileURL(url, this.token || '', this.siteUrl, accessKey); - } - - /** - * Deletes site's DB. - * - * @returns Promise to be resolved when the DB is deleted. - */ - async deleteDB(): Promise { - await CoreDB.deleteDB('Site-' + this.id); - } - - /** - * Deletes site's folder. - * - * @returns Promise to be resolved when the DB is deleted. - */ - async deleteFolder(): Promise { - if (!CoreFile.isAvailable() || !this.id) { - return; - } - - const siteFolder = CoreFile.getSiteFolder(this.id); - - // Ignore any errors, removeDir fails if folder doesn't exists. - await CoreUtils.ignoreErrors(CoreFile.removeDir(siteFolder)); - } - - /** - * Get space usage of the site. - * - * @returns Promise resolved with the site space usage (size). - */ - getSpaceUsage(): Promise { - if (CoreFile.isAvailable() && this.id) { - const siteFolderPath = CoreFile.getSiteFolder(this.id); - - return CoreFile.getDirectorySize(siteFolderPath).catch(() => 0); - } else { - return Promise.resolve(0); - } - } - - /** - * Gets an approximation of the cache table usage of the site. - * - * Currently this is just the total length of the data fields in the cache table. - * - * @returns Promise resolved with the total size of all data in the cache table (bytes) - */ - async getCacheUsage(): Promise { - return this.cacheTable.reduce({ - sql: 'SUM(length(data))', - js: (size, record) => size + record.data.length, - jsInitialValue: 0, + Object.values(this.memoryCache).filter(entry => entry.key?.startsWith(key)).forEach(entry => { + entry.expirationTime = 0; }); } - /** - * Gets a total of the file and cache usage. - * - * @returns Promise with the total of getSpaceUsage and getCacheUsage - */ - async getTotalUsage(): Promise { - const space = await this.getSpaceUsage(); - const cache = await this.getCacheUsage(); - - return space + cache; - } - /** * Returns the URL to the documentation of the app, based on Moodle version and current language. * @@ -1623,48 +1273,13 @@ export class CoreSite { } /** - * Returns a url to link an specific page on the site. - * - * @param path Path of the url to go to. - * @param params Object with the params to add. - * @param anchor Anchor text if needed. - * @returns URL with params. - */ - createSiteUrl(path: string, params?: Record, anchor?: string): string { - return CoreUrlUtils.addParamsToUrl(CorePath.concatenatePaths(this.siteUrl, path), params, anchor); - } - - /** - * Check if a URL belongs to this site. - * - * @param url URL to check. - * @returns Whether the URL belongs to this site. - */ - containsUrl(url?: string): boolean { - if (!url) { - return false; - } - - const siteUrl = CoreTextUtils.addEndingSlash(CoreUrlUtils.removeProtocolAndWWW(this.siteUrl)); - url = CoreTextUtils.addEndingSlash(CoreUrlUtils.removeProtocolAndWWW(url)); - - return url.indexOf(siteUrl) == 0; - } - - /** - * Get the public config of this site. - * - * @param options Options. - * @returns Promise resolved with public config. Rejected with an object if error, see CoreWSProvider.callAjax. + * @inheritdoc */ async getPublicConfig(options: { readingStrategy?: CoreSitesReadingStrategy } = {}): Promise { - if (!this.db) { - if (options.readingStrategy === CoreSitesReadingStrategy.ONLY_CACHE) { - throw new CoreError('Cache not available to read public config'); - } - - return this.requestPublicConfig(); - } + const ignoreCache = CoreSitesReadingStrategy.ONLY_NETWORK || CoreSitesReadingStrategy.PREFER_NETWORK; + if (!ignoreCache && this.publicConfig) { + return this.publicConfig; + }; const method = 'tool_mobile_get_public_config'; const cacheId = this.getCacheId(method, {}); @@ -1720,6 +1335,10 @@ export class CoreSite { return config; } catch (error) { + if (cachePreSets.emergencyCache === false) { + throw error; + } + cachePreSets.omitExpires = true; cachePreSets.getFromCache = true; @@ -1733,7 +1352,10 @@ export class CoreSite { } }).then((response) => { // The app doesn't store exceptions for this call, it's safe to assume type CoreSitePublicConfigResponse. - subject.next( response); + response = response; + + this.setPublicConfig(response); + subject.next(response); subject.complete(); return; @@ -1754,296 +1376,12 @@ export class CoreSite { } /** - * Perform a request to the server to get the public config of this site. - * - * @returns Promise resolved with public config. - */ - protected async requestPublicConfig(): Promise { - const preSets: CoreWSAjaxPreSets = { - siteUrl: this.siteUrl, - }; - - let config: CoreSitePublicConfigResponse; - - try { - config = await CoreWS.callAjax('tool_mobile_get_public_config', {}, preSets); - } catch (error) { - if (!error || error.errorcode !== 'codingerror' || (this.getInfo() && !this.isVersionGreaterEqualThan('3.8'))) { - throw error; - } - - // This error probably means that there is a redirect in the site. Try to use a GET request. - preSets.noLogin = true; - preSets.useGet = true; - - try { - config = await CoreWS.callAjax('tool_mobile_get_public_config', {}, preSets); - } catch (error2) { - if (this.getInfo() && this.isVersionGreaterEqualThan('3.8')) { - // GET is supported, return the second error. - throw error2; - } else { - // GET not supported or we don't know if it's supported. Return first error. - throw error; - } - } - } - - // Use the wwwroot returned by the server. - if (config.httpswwwroot) { - this.siteUrl = CoreUrlUtils.removeUrlParams(config.httpswwwroot); // Make sure the URL doesn't have params. - } - - return config; - } - - /** - * Open a URL in browser using auto-login in the Moodle site if available. - * - * @param url The URL to open. - * @param alertMessage If defined, an alert will be shown before opening the browser. - * @param options Other options. - * @returns Promise resolved when done, rejected otherwise. - */ - async openInBrowserWithAutoLogin( - url: string, - alertMessage?: string, - options: CoreUtilsOpenInBrowserOptions = {}, - ): Promise { - await this.openWithAutoLogin(false, url, options, alertMessage); - } - - /** - * Open a URL in browser using auto-login in the Moodle site if available and the URL belongs to the site. - * - * @param url The URL to open. - * @param alertMessage If defined, an alert will be shown before opening the browser. - * @param options Other options. - * @returns Promise resolved when done, rejected otherwise. - * @deprecated since 4.1. Use openInBrowserWithAutoLogin instead, now it always checks that URL belongs to same site. - */ - async openInBrowserWithAutoLoginIfSameSite( - url: string, - alertMessage?: string, - options: CoreUtilsOpenInBrowserOptions = {}, - ): Promise { - return this.openInBrowserWithAutoLogin(url, alertMessage, options); - } - - /** - * Open a URL in inappbrowser using auto-login in the Moodle site if available. + * Check if GET method is supported for AJAX calls. * - * @param url The URL to open. - * @param options Override default options passed to InAppBrowser. - * @param alertMessage If defined, an alert will be shown before opening the inappbrowser. - * @returns Promise resolved when done. + * @returns Whether it's supported. */ - async openInAppWithAutoLogin(url: string, options?: InAppBrowserOptions, alertMessage?: string): Promise { - const iabInstance = await this.openWithAutoLogin(true, url, options, alertMessage); - - return iabInstance; - } - - /** - * Open a URL in inappbrowser using auto-login in the Moodle site if available and the URL belongs to the site. - * - * @param url The URL to open. - * @param options Override default options passed to inappbrowser. - * @param alertMessage If defined, an alert will be shown before opening the inappbrowser. - * @returns Promise resolved when done. - * @deprecated since 4.1. Use openInAppWithAutoLogin instead, now it always checks that URL belongs to same site. - */ - async openInAppWithAutoLoginIfSameSite( - url: string, - options?: InAppBrowserOptions, - alertMessage?: string, - ): Promise { - return this.openInAppWithAutoLogin(url, options, alertMessage); - } - - /** - * Open a URL in browser or InAppBrowser using auto-login in the Moodle site if available. - * - * @param inApp True to open it in InAppBrowser, false to open in browser. - * @param url The URL to open. - * @param options Override default options passed to $cordovaInAppBrowser#open. - * @param alertMessage If defined, an alert will be shown before opening the browser/inappbrowser. - * @returns Promise resolved when done. Resolve param is returned only if inApp=true. - */ - async openWithAutoLogin( - inApp: boolean, - url: string, - options: InAppBrowserOptions & CoreUtilsOpenInBrowserOptions = {}, - alertMessage?: string, - ): Promise { - // Get the URL to open. - const autoLoginUrl = await this.getAutoLoginUrl(url); - - if (alertMessage) { - // Show an alert first. - const alert = await CoreDomUtils.showAlert( - Translate.instant('core.notice'), - alertMessage, - undefined, - 3000, - ); - - await alert.onDidDismiss(); - options.showBrowserWarning = false; // A warning already shown, no need to show another. - } - - options.originalUrl = url; - - // Open the URL. - if (inApp) { - return CoreUtils.openInApp(autoLoginUrl, options); - } else { - return CoreUtils.openInBrowser(autoLoginUrl, options); - } - } - - /** - * Open a URL in browser or InAppBrowser using auto-login in the Moodle site if available and the URL belongs to the site. - * - * @param inApp True to open it in InAppBrowser, false to open in browser. - * @param url The URL to open. - * @param options Override default options passed to inappbrowser. - * @param alertMessage If defined, an alert will be shown before opening the browser/inappbrowser. - * @returns Promise resolved when done. Resolve param is returned only if inApp=true. - * @deprecated since 4.1. Use openWithAutoLogin instead, now it always checks that URL belongs to same site. - */ - async openWithAutoLoginIfSameSite( - inApp: boolean, - url: string, - options: InAppBrowserOptions & CoreUtilsOpenInBrowserOptions = {}, - alertMessage?: string, - ): Promise { - return this.openWithAutoLogin(inApp, url, options, alertMessage); - } - - /** - * Get the config of this site. - * It is recommended to use getStoredConfig instead since it's faster and doesn't use network. - * - * @param name Name of the setting to get. If not set or false, all settings will be returned. - * @param ignoreCache True if it should ignore cached data. - * @returns Promise resolved with site config. - */ - getConfig(name?: undefined, ignoreCache?: boolean): Promise; - getConfig(name: string, ignoreCache?: boolean): Promise; - getConfig(name?: string, ignoreCache?: boolean): Promise { - return firstValueFrom( - this.getConfigObservable( name, ignoreCache ? CoreSitesReadingStrategy.ONLY_NETWORK : undefined), - ); - } - - /** - * Get the config of this site. - * It is recommended to use getStoredConfig instead since it's faster and doesn't use network. - * - * @param name Name of the setting to get. If not set or false, all settings will be returned. - * @param readingStrategy Reading strategy. - * @returns Observable returning site config. - */ - getConfigObservable(name?: undefined, readingStrategy?: CoreSitesReadingStrategy): WSObservable; - getConfigObservable(name: string, readingStrategy?: CoreSitesReadingStrategy): WSObservable; - getConfigObservable(name?: string, readingStrategy?: CoreSitesReadingStrategy): WSObservable { - const preSets: CoreSiteWSPreSets = { - cacheKey: this.getConfigCacheKey(), - ...CoreSites.getReadingStrategyPreSets(readingStrategy), - }; - - return this.readObservable('tool_mobile_get_config', {}, preSets).pipe(map(config => { - if (name) { - // Return the requested setting. - for (const x in config.settings) { - if (config.settings[x].name == name) { - return String(config.settings[x].value); - } - } - - throw new CoreError('Site config not found: ' + name); - } else { - // Return all settings in the same array. - const settings: CoreSiteConfig = {}; - config.settings.forEach((setting) => { - settings[setting.name] = String(setting.value); - }); - - return settings; - } - })); - } - - /** - * Invalidates config WS call. - * - * @returns Promise resolved when the data is invalidated. - */ - async invalidateConfig(): Promise { - await this.invalidateWsCacheForKey(this.getConfigCacheKey()); - } - - /** - * Get cache key for getConfig WS calls. - * - * @returns Cache key. - */ - protected getConfigCacheKey(): string { - return 'tool_mobile_get_config'; - } - - /** - * Get the stored config of this site. - * - * @param name Name of the setting to get. If not set, all settings will be returned. - * @returns Site config or a specific setting. - */ - getStoredConfig(): CoreSiteConfig | undefined; - getStoredConfig(name: string): string | undefined; - getStoredConfig(name?: string): string | CoreSiteConfig | undefined { - if (!this.config) { - return; - } - - if (name) { - return this.config[name]; - } else { - return this.config; - } - } - - /** - * Check if a certain feature is disabled in the site. - * - * @param name Name of the feature to check. - * @returns Whether it's disabled. - */ - isFeatureDisabled(name: string): boolean { - const disabledFeatures = this.getStoredConfig('tool_mobile_disabledfeatures'); - if (!disabledFeatures) { - return false; - } - - const regEx = new RegExp('(,|^)' + CoreTextUtils.escapeForRegex(name) + '(,|$)', 'g'); - - return !!disabledFeatures.match(regEx); - } - - /** - * Calculate if offline is disabled in the site. - */ - calculateOfflineDisabled(): void { - this.offlineDisabled = this.isFeatureDisabled('NoDelegate_CoreOffline'); - } - - /** - * Get whether offline is disabled in the site. - * - * @returns Whether it's disabled. - */ - isOfflineDisabled(): boolean { - return this.offlineDisabled; + protected isAjaxGetSupported(): boolean { + return !!this.getInfo() && this.isVersionGreaterEqualThan('3.8'); } /** @@ -2101,66 +1439,6 @@ export class CoreSite { return false; } - /** - * Given a URL, convert it to a URL that will auto-login if supported. - * - * @param url The URL to convert. - * @param showModal Whether to show a loading modal. - * @returns Promise resolved with the converted URL. - */ - async getAutoLoginUrl(url: string, showModal: boolean = true): Promise { - if (!this.privateToken) { - // No private token, don't change the URL. - return url; - } - - if (!this.containsUrl(url)) { - // URL doesn't belong to the site, don't auto login. - return url; - } - - if (this.lastAutoLogin > 0) { - const timeBetweenRequests = await CoreUtils.ignoreErrors( - this.getConfig('tool_mobile_autologinmintimebetweenreq'), - CoreConstants.SECONDS_MINUTE * 6, - ); - - if (CoreTimeUtils.timestamp() - this.lastAutoLogin < Number(timeBetweenRequests)) { - // Not enough time has passed since last auto login. - return url; - } - } - - const userId = this.getUserId(); - const params = { - privatetoken: this.privateToken, - }; - let modal: CoreIonLoadingElement | undefined; - - if (showModal) { - modal = await CoreDomUtils.showModalLoading(); - } - - try { - // Use write to not use cache. - const data = await this.write('tool_mobile_get_autologin_key', params); - - if (!data.autologinurl || !data.key) { - // Not valid data, return the same URL. - return url; - } - - this.lastAutoLogin = CoreTimeUtils.timestamp(); - - return data.autologinurl + '?userid=' + userId + '&key=' + data.key + '&urltogo=' + encodeURIComponent(url); - } catch (error) { - // Couldn't get autologin key, return the same URL. - return url; - } finally { - modal?.dismiss(); - } - } - /** * Get a version number from a release version. * If release version is valid but not found in the list of Moodle releases, it will use the last released major version. @@ -2176,9 +1454,9 @@ export class CoreSite { return 0; } - if (CoreSite.MOODLE_RELEASES[data.major] === undefined) { + if (CoreAuthenticatedSite.MOODLE_RELEASES[data.major] === undefined) { // Major version not found. Use the last one. - const major = Object.keys(CoreSite.MOODLE_RELEASES).pop(); + const major = Object.keys(CoreAuthenticatedSite.MOODLE_RELEASES).pop(); if (!major) { return 0; } @@ -2186,7 +1464,7 @@ export class CoreSite { data.major = major; } - return CoreSite.MOODLE_RELEASES[data.major] + data.minor; + return CoreAuthenticatedSite.MOODLE_RELEASES[data.major] + data.minor; } /** @@ -2216,7 +1494,7 @@ export class CoreSite { */ protected getNextMajorVersionNumber(version: string): number { const data = this.getMajorAndMinor(version); - const releases = Object.keys(CoreSite.MOODLE_RELEASES); + const releases = Object.keys(CoreAuthenticatedSite.MOODLE_RELEASES); if (!data) { // Invalid version. @@ -2227,52 +1505,10 @@ export class CoreSite { if (position == -1 || position == releases.length - 1) { // Major version not found or it's the last one. Use the last one. - return CoreSite.MOODLE_RELEASES[releases[position]]; - } - - return CoreSite.MOODLE_RELEASES[releases[position + 1]]; - } - - /** - * Deletes a site setting. - * - * @param name The config name. - * @returns Promise resolved when done. - */ - async deleteSiteConfig(name: string): Promise { - await this.configTable.deleteByPrimaryKey({ name }); - } - - /** - * Get a site setting on local device. - * - * @param name The config name. - * @param defaultValue Default value to use if the entry is not found. - * @returns Resolves upon success along with the config data. Reject on failure. - */ - async getLocalSiteConfig(name: string, defaultValue?: T): Promise { - try { - const entry = await this.configTable.getOneByPrimaryKey({ name }); - - return entry.value; - } catch (error) { - if (defaultValue !== undefined) { - return defaultValue; - } - - throw error; + return CoreAuthenticatedSite.MOODLE_RELEASES[releases[position]]; } - } - /** - * Set a site setting on local device. - * - * @param name The config name. - * @param value The config value. Can only store number or strings. - * @returns Promise resolved when done. - */ - async setLocalSiteConfig(name: string, value: number | string): Promise { - await this.configTable.insert({ name, value }); + return CoreAuthenticatedSite.MOODLE_RELEASES[releases[position + 1]]; } /** @@ -2282,8 +1518,9 @@ export class CoreSite { * @returns Expiration delay. */ getExpirationDelay(updateFrequency?: number): number { - updateFrequency = updateFrequency || CoreSite.FREQUENCY_USUALLY; - let expirationDelay = this.UPDATE_FREQUENCIES[updateFrequency] || this.UPDATE_FREQUENCIES[CoreSite.FREQUENCY_USUALLY]; + updateFrequency = updateFrequency || CoreAuthenticatedSite.FREQUENCY_USUALLY; + let expirationDelay = CoreAuthenticatedSite.UPDATE_FREQUENCIES[updateFrequency] || + CoreAuthenticatedSite.UPDATE_FREQUENCIES[CoreAuthenticatedSite.FREQUENCY_USUALLY]; if (CoreNetwork.isNetworkAccessLimited()) { // Not WiFi, increase the expiration delay a 50% to decrease the data usage in this case. @@ -2293,153 +1530,17 @@ export class CoreSite { return expirationDelay; } - /* - * Check if tokenpluginfile script works in the site. - * - * @param url URL to check. - * @returns Promise resolved with boolean: whether it works or not. - */ - checkTokenPluginFile(url: string): Promise { - if (!CoreUrlUtils.canUseTokenPluginFile(url, this.siteUrl, this.infos && this.infos.userprivateaccesskey)) { - // Cannot use tokenpluginfile. - return Promise.resolve(false); - } else if (this.tokenPluginFileWorks !== undefined) { - // Already checked. - return Promise.resolve(this.tokenPluginFileWorks); - } else if (this.tokenPluginFileWorksPromise) { - // Check ongoing, use the same promise. - return this.tokenPluginFileWorksPromise; - } else if (!CoreNetwork.isOnline()) { - // Not online, cannot check it. Assume it's working, but don't save the result. - return Promise.resolve(true); - } - - url = this.fixPluginfileURL(url); - - this.tokenPluginFileWorksPromise = CoreWS.urlWorks(url).then((result) => { - this.tokenPluginFileWorks = result; - - return result; - }); - - return this.tokenPluginFileWorksPromise; - } - /** - * Check if a URL to a file belongs to the site and uses the pluginfileurl or tokenpluginfileurl endpoints. + * Trigger an event. * - * @param url File URL to check. - * @returns Whether it's a site file URL. + * @param eventName Event name. + * @param data Event data. */ - isSitePluginFileUrl(url: string): boolean { - const isPluginFileUrl = CoreUrlUtils.isPluginFileUrl(url) || CoreUrlUtils.isTokenPluginFileUrl(url); - if (!isPluginFileUrl) { - return false; - } - - return this.containsUrl(url); - } - - /** - * Check if a URL to a file belongs to the site and is a theme image file. - * - * @param url File URL to check. - * @returns Whether it's a site theme image URL. - */ - isSiteThemeImageUrl(url: string): boolean { - if (!CoreUrlUtils.isThemeImageUrl(url)) { - return false; - } - - return this.containsUrl(url); - } - - /** - * Deletes last viewed records based on some conditions. - * - * @param conditions Conditions. - * @returns Promise resolved when done. - */ - async deleteLastViewed(conditions?: Partial): Promise { - await this.lastViewedTable.delete(conditions); - } - - /** - * Get a last viewed record for a component+id. - * - * @param component The component. - * @param id ID. - * @returns Resolves with last viewed record, undefined if not found. - */ - async getLastViewed(component: string, id: number): Promise { - try { - return await this.lastViewedTable.getOneByPrimaryKey({ component, id }); - } catch { - // Not found. - } - } - - /** - * Get several last viewed for a certain component. - * - * @param component The component. - * @param ids IDs. If not provided or empty, return all last viewed for a component. - * @returns Resolves with last viewed records, undefined if error. - */ - async getComponentLastViewed(component: string, ids: number[] = []): Promise { - try { - if (!ids.length) { - return await this.lastViewedTable.getMany({ component }); - } - - const whereAndParams = SQLiteDB.getInOrEqual(ids); - - whereAndParams.sql = 'id ' + whereAndParams.sql + ' AND component = ?'; - whereAndParams.params.push(component); - - return await this.lastViewedTable.getManyWhere({ - sql: whereAndParams.sql, - sqlParams: whereAndParams.params, - js: (record) => record.component === component && ids.includes(record.id), - }); - } catch { - // Not found. - } - } - - /** - * Store a last viewed record. - * - * @param component The component. - * @param id ID. - * @param value Last viewed item value. - * @param options Options. - * @returns Promise resolved when done. - */ - async storeLastViewed( - component: string, - id: number, - value: string | number, - options: CoreSiteStoreLastViewedOptions = {}, - ): Promise { - await this.lastViewedTable.insert({ - component, - id, - value: String(value), - data: options.data, - timeaccess: options.timeaccess ?? Date.now(), - }); - } - - /** - * Check if the site is a demo mode site. - * - * @returns Whether the site is a demo mode site. - */ - isDemoModeSite(): boolean { - const demoSiteData = CoreLoginHelper.getDemoModeSiteInfo(); - - return this.containsUrl(demoSiteData?.url); + protected triggerSiteEvent( + eventName: Event, + data?: CoreEventData, + ): void { + CoreEvents.trigger(eventName, data); } } @@ -2508,6 +1609,14 @@ export function chainRequests>( ); } +/** + * Optional data to create an authenticated site. + */ +export type CoreAuthenticatedSiteOptionalData = { + privateToken?: string; + publicConfig?: CoreSitePublicConfigResponse; +}; + /** * PreSets accepted by the WS call. */ @@ -2647,161 +1756,6 @@ type RequestQueueItem = { deferred: CorePromisedValue; }; -/** - * Result of WS core_webservice_get_site_info. - */ -export type CoreSiteInfoResponse = { - sitename: string; // Site name. - username: string; // Username. - firstname: string; // First name. - lastname: string; // Last name. - fullname: string; // User full name. - lang: string; // Current language. - userid: number; // User id. - siteurl: string; // Site url. - userpictureurl: string; // The user profile picture. - functions: { - name: string; // Function name. - version: string; // The version number of the component to which the function belongs. - }[]; - downloadfiles?: number; // 1 if users are allowed to download files, 0 if not. - uploadfiles?: number; // 1 if users are allowed to upload files, 0 if not. - release?: string; // Moodle release number. - version?: string; // Moodle version number. - mobilecssurl?: string; // Mobile custom CSS theme. - advancedfeatures?: { // Advanced features availability. - name: string; // Feature name. - value: number; // Feature value. Usually 1 means enabled. - }[]; - usercanmanageownfiles?: boolean; // True if the user can manage his own files. - userquota?: number; // User quota (bytes). 0 means user can ignore the quota. - usermaxuploadfilesize?: number; // User max upload file size (bytes). -1 means the user can ignore the upload file size. - userhomepage?: CoreSiteInfoUserHomepage; // The default home page for the user. - userprivateaccesskey?: string; // Private user access key for fetching files. - siteid?: number; // Site course ID. - sitecalendartype?: string; // Calendar type set in the site. - usercalendartype?: string; // Calendar typed used by the user. - userissiteadmin?: boolean; // Whether the user is a site admin or not. - theme?: string; // Current theme for the user. -}; - -/** - * Site info, including some calculated data. - */ -export type CoreSiteInfo = CoreSiteInfoResponse & { - functionsByName?: { - [name: string]: { - name: string; // Function name. - version: string; // The version number of the component to which the function belongs. - }; - }; -}; - -/** - * Enum constants that define default user home page. - */ -export enum CoreSiteInfoUserHomepage { - HOMEPAGE_SITE = 0, // Site home. - HOMEPAGE_MY = 1, // Dashboard. - HOMEPAGE_MYCOURSES = 3, // My courses. -} - -/** - * Result of WS tool_mobile_get_config. - */ -export type CoreSiteConfigResponse = { - settings: { // Settings. - name: string; // The name of the setting. - value: string | number; // The value of the setting. - }[]; - warnings?: CoreWSExternalWarning[]; -}; - -/** - * Possible values for 'supportavailability' config. - */ -export const enum CoreSiteConfigSupportAvailability { - Disabled = 0, - Authenticated = 1, - Anyone = 2, -} - -/** - * Site config indexed by name. - */ -export type CoreSiteConfig = Record & { - supportavailability?: string; // String representation of CoreSiteConfigSupportAvailability. - searchbanner?: string; // Search banner text. - searchbannerenable?: string; // Whether search banner is enabled. -}; - -/** - * Result of WS tool_mobile_get_public_config. - */ -export type CoreSitePublicConfigResponse = { - wwwroot: string; // Site URL. - httpswwwroot: string; // Site https URL (if httpslogin is enabled). - sitename: string; // Site name. - guestlogin: number; // Whether guest login is enabled. - rememberusername: number; // Values: 0 for No, 1 for Yes, 2 for optional. - authloginviaemail: number; // Whether log in via email is enabled. - registerauth: string; // Authentication method for user registration. - forgottenpasswordurl: string; // Forgotten password URL. - authinstructions: string; // Authentication instructions. - authnoneenabled: number; // Whether auth none is enabled. - enablewebservices: number; // Whether Web Services are enabled. - enablemobilewebservice: number; // Whether the Mobile service is enabled. - maintenanceenabled: number; // Whether site maintenance is enabled. - maintenancemessage: string; // Maintenance message. - logourl?: string; // The site logo URL. - compactlogourl?: string; // The site compact logo URL. - typeoflogin: TypeOfLogin; // The type of login. 1 for app, 2 for browser, 3 for embedded. - launchurl?: string; // SSO login launch URL. - mobilecssurl?: string; // Mobile custom CSS theme. - // eslint-disable-next-line @typescript-eslint/naming-convention - tool_mobile_disabledfeatures?: string; // Disabled features in the app. - identityproviders?: CoreSiteIdentityProvider[]; // Identity providers. - country?: string; // Default site country. - agedigitalconsentverification?: boolean; // Whether age digital consent verification is enabled. - supportname?: string; // Site support contact name (only if age verification is enabled). - supportemail?: string; // Site support contact email (only if age verification is enabled). - supportavailability?: CoreSiteConfigSupportAvailability; - supportpage?: string; // Site support contact url. - autolang?: number; // Whether to detect default language from browser setting. - lang?: string; // Default language for the site. - langmenu?: number; // Whether the language menu should be displayed. - langlist?: string; // Languages on language menu. - locale?: string; // Sitewide locale. - // eslint-disable-next-line @typescript-eslint/naming-convention - tool_mobile_minimumversion?: string; // Minimum required version to access. - // eslint-disable-next-line @typescript-eslint/naming-convention - tool_mobile_iosappid?: string; // IOS app's unique identifier. - // eslint-disable-next-line @typescript-eslint/naming-convention - tool_mobile_androidappid?: string; // Android app's unique identifier. - // eslint-disable-next-line @typescript-eslint/naming-convention - tool_mobile_setuplink?: string; // App download page. - tool_mobile_qrcodetype?: CoreSiteQRCodeType; // eslint-disable-line @typescript-eslint/naming-convention - warnings?: CoreWSExternalWarning[]; -}; - -/** - * Identity provider. - */ -export type CoreSiteIdentityProvider = { - name: string; // The identity provider name. - iconurl: string; // The icon URL for the provider. - url: string; // The URL of the provider. -}; - -/** - * Result of WS tool_mobile_get_autologin_key. - */ -export type CoreSiteAutologinKeyResult = { - key: string; // Auto-login key for a single usage with time expiration. - autologinurl: string; // Auto-login URL. - warnings?: CoreWSExternalWarning[]; -}; - /** * Result of WS tool_mobile_call_external_functions. */ @@ -2813,14 +1767,6 @@ export type CoreSiteCallExternalFunctionsResult = { }[]; }; -/** - * Options for storeLastViewed. - */ -export type CoreSiteStoreLastViewedOptions = { - data?: string; // Other data. - timeaccess?: number; // Accessed time. If not set, current time. -}; - /** * Info about cached data. */ @@ -2853,12 +1799,3 @@ enum OngoingRequestType { STANDARD = 0, UPDATE_IN_BACKGROUND = 1, } - -/** - * The type of login. 1 for app, 2 for browser, 3 for embedded. - */ -export enum TypeOfLogin { - APP = 1, - BROWSER = 2, // SSO in browser window is required. - EMBEDDED = 3, // SSO in embedded browser is required. -} diff --git a/src/core/classes/sites/site.ts b/src/core/classes/sites/site.ts new file mode 100644 index 00000000000..28cc4023302 --- /dev/null +++ b/src/core/classes/sites/site.ts @@ -0,0 +1,964 @@ +// (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 { InAppBrowserObject, InAppBrowserOptions } from '@ionic-native/in-app-browser'; + +import { CoreNetwork } from '@services/network'; +import { CoreDB } from '@services/db'; +import { CoreEventData, CoreEvents } from '@singletons/events'; +import { CoreFile } from '@services/file'; +import { + CoreWS, + CoreWSFileUploadOptions, + CoreWSExternalWarning, + CoreWSUploadFileResult, +} from '@services/ws'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreTextUtils } from '@services/utils/text'; +import { CoreTimeUtils } from '@services/utils/time'; +import { CoreUrlUtils } from '@services/utils/url'; +import { CoreUtils, CoreUtilsOpenInBrowserOptions } from '@services/utils/utils'; +import { CoreConstants } from '@/core/constants'; +import { SQLiteDB } from '@classes/sqlitedb'; +import { CoreError } from '@classes/errors/error'; +import { CoreLogger } from '@singletons/logger'; +import { Translate } from '@singletons'; +import { CoreIonLoadingElement } from '../ion-loading'; +import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; +import { asyncInstance, AsyncInstance } from '../../utils/async-instance'; +import { CoreDatabaseTable } from '../database/database-table'; +import { CoreDatabaseCachingStrategy } from '../database/database-table-proxy'; +import { + CONFIG_TABLE, + CoreSiteConfigDBRecord, + CoreSiteLastViewedDBRecord, + CoreSiteWSCacheRecord, + LAST_VIEWED_TABLE, + WS_CACHE_TABLE, +} from '@services/database/sites'; +import { map } from 'rxjs/operators'; +import { firstValueFrom } from '../../utils/rxjs'; +import { CoreFilepool } from '@services/filepool'; +import { CoreSiteInfo } from './unauthenticated-site'; +import { CoreAuthenticatedSite, CoreAuthenticatedSiteOptionalData, CoreSiteWSPreSets, WSObservable } from './authenticated-site'; + +/** + * Class that represents a site (combination of site + user). + * It will have all the site data and provide utility functions regarding a site. + */ +export class CoreSite extends CoreAuthenticatedSite { + + id: string; + config?: CoreSiteConfig; + loggedOut?: boolean; + + protected db!: SQLiteDB; + protected cacheTable: AsyncInstance>; + protected configTable: AsyncInstance>; + protected lastViewedTable: AsyncInstance>; + protected lastAutoLogin = 0; + protected tokenPluginFileWorks?: boolean; + protected tokenPluginFileWorksPromise?: Promise; + protected oauthId?: number; + + /** + * Create a site. + * + * @param id Site ID. + * @param siteUrl Site URL. + * @param token Site's WS token. + * @param otherData Other data. + */ + constructor( + id: string, + siteUrl: string, + token: string, + otherData: CoreSiteOptionalData = {}, + ) { + super(siteUrl, token, otherData); + + this.id = id; + this.config = otherData.config; + this.loggedOut = otherData.loggedOut; + this.logger = CoreLogger.getInstance('CoreSite'); + + this.cacheTable = asyncInstance(() => CoreSites.getSiteTable(WS_CACHE_TABLE, { + siteId: this.getId(), + database: this.getDb(), + config: { cachingStrategy: CoreDatabaseCachingStrategy.None }, + })); + + this.configTable = asyncInstance(() => CoreSites.getSiteTable(CONFIG_TABLE, { + siteId: this.getId(), + database: this.getDb(), + config: { cachingStrategy: CoreDatabaseCachingStrategy.Eager }, + primaryKeyColumns: ['name'], + })); + + this.lastViewedTable = asyncInstance(() => CoreSites.getSiteTable(LAST_VIEWED_TABLE, { + siteId: this.getId(), + database: this.getDb(), + config: { cachingStrategy: CoreDatabaseCachingStrategy.Eager }, + primaryKeyColumns: ['component', 'id'], + })); + this.setInfo(otherData.info); + this.calculateOfflineDisabled(); + + this.db = CoreDB.getDB('Site-' + this.id); + } + + /** + * Get site ID. + * + * @returns Site ID. + */ + getId(): string { + return this.id; + } + + /** + * Get site DB. + * + * @returns Site DB. + */ + getDb(): SQLiteDB { + return this.db; + } + + /** + * Check if user logged out from the site and needs to authenticate again. + * + * @returns Whether is logged out. + */ + isLoggedOut(): boolean { + return !!this.loggedOut; + } + + /** + * Get OAuth ID. + * + * @returns OAuth ID. + */ + getOAuthId(): number | undefined { + return this.oauthId; + } + + /** + * Set site config. + * + * @param config Config. + */ + setConfig(config: CoreSiteConfig): void { + if (config) { + config.tool_mobile_disabledfeatures = CoreTextUtils.treatDisabledFeatures(config.tool_mobile_disabledfeatures); + } + + this.config = config; + this.calculateOfflineDisabled(); + } + + /** + * Set site logged out. + * + * @param loggedOut True if logged out and needs to authenticate again, false otherwise. + */ + setLoggedOut(loggedOut: boolean): void { + this.loggedOut = !!loggedOut; + } + + /** + * Set OAuth ID. + * + * @param oauthId OAuth ID. + */ + setOAuthId(oauthId: number | undefined): void { + this.oauthId = oauthId; + } + + /** + * Check if the user authenticated in the site using an OAuth method. + * + * @returns Whether the user authenticated in the site using an OAuth method. + */ + isOAuth(): boolean { + return this.oauthId != null && this.oauthId !== undefined; + } + + /** + * @inheritdoc + */ + protected async getCacheEntryById(id: string): Promise { + return this.cacheTable.getOneByPrimaryKey({ id }); + } + + /** + * @inheritdoc + */ + protected async getCacheEntriesByKey(key: string): Promise { + return this.cacheTable.getMany({ key }); + } + + /** + * @inheritdoc + */ + protected async storeCacheEntry(entry: CoreSiteWSCacheRecord): Promise { + await this.cacheTable.insert(entry); + } + + /** + * @inheritdoc + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + protected async deleteFromCache(method: string, data: any, preSets: CoreSiteWSPreSets, allCacheKey?: boolean): Promise { + if (allCacheKey) { + await this.cacheTable.delete({ key: preSets.cacheKey }); + } else { + await this.cacheTable.deleteByPrimaryKey({ id: this.getCacheId(method, data) }); + } + } + + /** + * Gets the size of cached data for a specific component or component instance. + * + * @param component Component name + * @param componentId Optional component id (if not included, returns sum for whole component) + * @returns Promise resolved when we have calculated the size + */ + async getComponentCacheSize(component: string, componentId?: number): Promise { + const params: Array = [component]; + let extraClause = ''; + if (componentId !== undefined && componentId !== null) { + params.push(componentId); + extraClause = ' AND componentId = ?'; + } + + return this.cacheTable.reduce( + { + sql: 'SUM(length(data))', + js: (size, record) => size + record.data.length, + jsInitialValue: 0, + }, + { + sql: 'WHERE component = ?' + extraClause, + sqlParams: params, + js: record => record.component === component && (params.length === 1 || record.componentId === componentId), + }, + ); + } + + /** + * Deletes WS cache entries for all methods relating to a specific component (and + * optionally component id). + * + * @param component Component name. + * @param componentId Component id. + * @returns Promise resolved when the entries are deleted. + */ + async deleteComponentFromCache(component: string, componentId?: number): Promise { + if (!component) { + return; + } + + const params = { component }; + + if (componentId) { + params['componentId'] = componentId; + } + + await this.cacheTable.delete(params); + } + + /* + * Uploads a file using Cordova File API. + * + * @param filePath File path. + * @param options File upload options. + * @param onProgress Function to call on progress. + * @returns Promise resolved when uploaded. + */ + uploadFile( + filePath: string, + options: CoreWSFileUploadOptions, + onProgress?: (event: ProgressEvent) => void, + ): Promise { + if (!options.fileArea) { + options.fileArea = 'draft'; + } + + return CoreWS.uploadFile(filePath, options, { + siteUrl: this.siteUrl, + wsToken: this.token || '', + }, onProgress); + } + + /** + * Invalidates all caches related to the site. + */ + async invalidateCaches(): Promise { + await Promise.all([ + CoreFilepool.invalidateAllFiles(this.getId()), + this.invalidateWsCache(), + ]); + } + + /** + * @inheritdoc + */ + async invalidateWsCache(): Promise { + this.logger.debug('Invalidate all the cache for site: ' + this.id); + + try { + await this.cacheTable.update({ expirationTime: 0 }); + } finally { + CoreEvents.trigger(CoreEvents.WS_CACHE_INVALIDATED, {}, this.getId()); + } + } + + /** + * @inheritdoc + */ + async invalidateWsCacheForKey(key: string): Promise { + if (!key) { + return; + } + + this.logger.debug('Invalidate cache for key: ' + key); + + await this.cacheTable.update({ expirationTime: 0 }, { key }); + } + + /** + * @inheritdoc + */ + async invalidateWsCacheForKeyStartingWith(key: string): Promise { + if (!key) { + return; + } + + this.logger.debug('Invalidate cache for key starting with: ' + key); + + await this.cacheTable.updateWhere({ expirationTime: 0 }, { + sql: 'key LIKE ?', + sqlParams: [key + '%'], + js: record => !!record.key?.startsWith(key), + }); + } + + /** + * Check if tokenpluginfile can be used, and fix the URL afterwards. + * + * @param url The url to be fixed. + * @returns Promise resolved with the fixed URL. + */ + checkAndFixPluginfileURL(url: string): Promise { + return this.checkTokenPluginFile(url).then(() => this.fixPluginfileURL(url)); + } + + /** + * Generic function for adding the wstoken to Moodle urls and for pointing to the correct script. + * Uses CoreUtilsProvider.fixPluginfileURL, passing site's token. + * + * @param url The url to be fixed. + * @returns Fixed URL. + */ + fixPluginfileURL(url: string): string { + const accessKey = this.tokenPluginFileWorks || this.tokenPluginFileWorks === undefined ? + this.infos && this.infos.userprivateaccesskey : undefined; + + return CoreUrlUtils.fixPluginfileURL(url, this.token || '', this.siteUrl, accessKey); + } + + /** + * Deletes site's DB. + * + * @returns Promise to be resolved when the DB is deleted. + */ + async deleteDB(): Promise { + await CoreDB.deleteDB('Site-' + this.id); + } + + /** + * Deletes site's folder. + * + * @returns Promise to be resolved when the DB is deleted. + */ + async deleteFolder(): Promise { + if (!CoreFile.isAvailable() || !this.id) { + return; + } + + const siteFolder = CoreFile.getSiteFolder(this.id); + + // Ignore any errors, removeDir fails if folder doesn't exists. + await CoreUtils.ignoreErrors(CoreFile.removeDir(siteFolder)); + } + + /** + * Get space usage of the site. + * + * @returns Promise resolved with the site space usage (size). + */ + getSpaceUsage(): Promise { + if (CoreFile.isAvailable() && this.id) { + const siteFolderPath = CoreFile.getSiteFolder(this.id); + + return CoreFile.getDirectorySize(siteFolderPath).catch(() => 0); + } else { + return Promise.resolve(0); + } + } + + /** + * Gets an approximation of the cache table usage of the site. + * + * Currently this is just the total length of the data fields in the cache table. + * + * @returns Promise resolved with the total size of all data in the cache table (bytes) + */ + async getCacheUsage(): Promise { + return this.cacheTable.reduce({ + sql: 'SUM(length(data))', + js: (size, record) => size + record.data.length, + jsInitialValue: 0, + }); + } + + /** + * Gets a total of the file and cache usage. + * + * @returns Promise with the total of getSpaceUsage and getCacheUsage + */ + async getTotalUsage(): Promise { + const space = await this.getSpaceUsage(); + const cache = await this.getCacheUsage(); + + return space + cache; + } + + /** + * Check if GET method is supported for AJAX calls. + * + * @returns Whether it's supported. + */ + protected isAjaxGetSupported(): boolean { + return !!this.getInfo() && this.isVersionGreaterEqualThan('3.8'); + } + + /** + * Open a URL in browser using auto-login in the Moodle site if available. + * + * @param url The URL to open. + * @param alertMessage If defined, an alert will be shown before opening the browser. + * @param options Other options. + * @returns Promise resolved when done, rejected otherwise. + */ + async openInBrowserWithAutoLogin( + url: string, + alertMessage?: string, + options: CoreUtilsOpenInBrowserOptions = {}, + ): Promise { + await this.openWithAutoLogin(false, url, options, alertMessage); + } + + /** + * Open a URL in browser using auto-login in the Moodle site if available and the URL belongs to the site. + * + * @param url The URL to open. + * @param alertMessage If defined, an alert will be shown before opening the browser. + * @param options Other options. + * @returns Promise resolved when done, rejected otherwise. + * @deprecated since 4.1. Use openInBrowserWithAutoLogin instead, now it always checks that URL belongs to same site. + */ + async openInBrowserWithAutoLoginIfSameSite( + url: string, + alertMessage?: string, + options: CoreUtilsOpenInBrowserOptions = {}, + ): Promise { + return this.openInBrowserWithAutoLogin(url, alertMessage, options); + } + + /** + * Open a URL in inappbrowser using auto-login in the Moodle site if available. + * + * @param url The URL to open. + * @param options Override default options passed to InAppBrowser. + * @param alertMessage If defined, an alert will be shown before opening the inappbrowser. + * @returns Promise resolved when done. + */ + async openInAppWithAutoLogin(url: string, options?: InAppBrowserOptions, alertMessage?: string): Promise { + const iabInstance = await this.openWithAutoLogin(true, url, options, alertMessage); + + return iabInstance; + } + + /** + * Open a URL in inappbrowser using auto-login in the Moodle site if available and the URL belongs to the site. + * + * @param url The URL to open. + * @param options Override default options passed to inappbrowser. + * @param alertMessage If defined, an alert will be shown before opening the inappbrowser. + * @returns Promise resolved when done. + * @deprecated since 4.1. Use openInAppWithAutoLogin instead, now it always checks that URL belongs to same site. + */ + async openInAppWithAutoLoginIfSameSite( + url: string, + options?: InAppBrowserOptions, + alertMessage?: string, + ): Promise { + return this.openInAppWithAutoLogin(url, options, alertMessage); + } + + /** + * Open a URL in browser or InAppBrowser using auto-login in the Moodle site if available. + * + * @param inApp True to open it in InAppBrowser, false to open in browser. + * @param url The URL to open. + * @param options Override default options passed to $cordovaInAppBrowser#open. + * @param alertMessage If defined, an alert will be shown before opening the browser/inappbrowser. + * @returns Promise resolved when done. Resolve param is returned only if inApp=true. + */ + async openWithAutoLogin( + inApp: boolean, + url: string, + options: InAppBrowserOptions & CoreUtilsOpenInBrowserOptions = {}, + alertMessage?: string, + ): Promise { + // Get the URL to open. + const autoLoginUrl = await this.getAutoLoginUrl(url); + + if (alertMessage) { + // Show an alert first. + const alert = await CoreDomUtils.showAlert( + Translate.instant('core.notice'), + alertMessage, + undefined, + 3000, + ); + + await alert.onDidDismiss(); + options.showBrowserWarning = false; // A warning already shown, no need to show another. + } + + options.originalUrl = url; + + // Open the URL. + if (inApp) { + return CoreUtils.openInApp(autoLoginUrl, options); + } else { + return CoreUtils.openInBrowser(autoLoginUrl, options); + } + } + + /** + * Open a URL in browser or InAppBrowser using auto-login in the Moodle site if available and the URL belongs to the site. + * + * @param inApp True to open it in InAppBrowser, false to open in browser. + * @param url The URL to open. + * @param options Override default options passed to inappbrowser. + * @param alertMessage If defined, an alert will be shown before opening the browser/inappbrowser. + * @returns Promise resolved when done. Resolve param is returned only if inApp=true. + * @deprecated since 4.1. Use openWithAutoLogin instead, now it always checks that URL belongs to same site. + */ + async openWithAutoLoginIfSameSite( + inApp: boolean, + url: string, + options: InAppBrowserOptions & CoreUtilsOpenInBrowserOptions = {}, + alertMessage?: string, + ): Promise { + return this.openWithAutoLogin(inApp, url, options, alertMessage); + } + + /** + * Get the config of this site. + * It is recommended to use getStoredConfig instead since it's faster and doesn't use network. + * + * @param name Name of the setting to get. If not set or false, all settings will be returned. + * @param ignoreCache True if it should ignore cached data. + * @returns Promise resolved with site config. + */ + getConfig(name?: undefined, ignoreCache?: boolean): Promise; + getConfig(name: string, ignoreCache?: boolean): Promise; + getConfig(name?: string, ignoreCache?: boolean): Promise { + return firstValueFrom( + this.getConfigObservable( name, ignoreCache ? CoreSitesReadingStrategy.ONLY_NETWORK : undefined), + ); + } + + /** + * Get the config of this site. + * It is recommended to use getStoredConfig instead since it's faster and doesn't use network. + * + * @param name Name of the setting to get. If not set or false, all settings will be returned. + * @param readingStrategy Reading strategy. + * @returns Observable returning site config. + */ + getConfigObservable(name?: undefined, readingStrategy?: CoreSitesReadingStrategy): WSObservable; + getConfigObservable(name: string, readingStrategy?: CoreSitesReadingStrategy): WSObservable; + getConfigObservable(name?: string, readingStrategy?: CoreSitesReadingStrategy): WSObservable { + const preSets: CoreSiteWSPreSets = { + cacheKey: this.getConfigCacheKey(), + ...CoreSites.getReadingStrategyPreSets(readingStrategy), + }; + + return this.readObservable('tool_mobile_get_config', {}, preSets).pipe(map(config => { + if (name) { + // Return the requested setting. + for (const x in config.settings) { + if (config.settings[x].name == name) { + return String(config.settings[x].value); + } + } + + throw new CoreError('Site config not found: ' + name); + } else { + // Return all settings in the same array. + const settings: CoreSiteConfig = {}; + config.settings.forEach((setting) => { + settings[setting.name] = String(setting.value); + }); + + return settings; + } + })); + } + + /** + * Invalidates config WS call. + * + * @returns Promise resolved when the data is invalidated. + */ + async invalidateConfig(): Promise { + await this.invalidateWsCacheForKey(this.getConfigCacheKey()); + } + + /** + * Get cache key for getConfig WS calls. + * + * @returns Cache key. + */ + protected getConfigCacheKey(): string { + return 'tool_mobile_get_config'; + } + + /** + * Get the stored config of this site. + * + * @param name Name of the setting to get. If not set, all settings will be returned. + * @returns Site config or a specific setting. + */ + getStoredConfig(): CoreSiteConfig | undefined; + getStoredConfig(name: string): string | undefined; + getStoredConfig(name?: string): string | CoreSiteConfig | undefined { + if (!this.config) { + return; + } + + if (name) { + return this.config[name]; + } else { + return this.config; + } + } + + /** + * @inheritdoc + */ + protected getDisabledFeatures(): string | undefined { + return this.config ? this.getStoredConfig('tool_mobile_disabledfeatures') : super.getDisabledFeatures(); + } + + /** + * @inheritdoc + */ + protected triggerSiteEvent( + eventName: Event, + data?: CoreEventData, + ): void { + CoreEvents.trigger(eventName, data, this.id); + } + + /** + * Calculate if offline is disabled in the site. + */ + calculateOfflineDisabled(): void { + this.offlineDisabled = this.isFeatureDisabled('NoDelegate_CoreOffline'); + } + + /** + * Get whether offline is disabled in the site. + * + * @returns Whether it's disabled. + */ + isOfflineDisabled(): boolean { + return this.offlineDisabled; + } + + /** + * Given a URL, convert it to a URL that will auto-login if supported. + * + * @param url The URL to convert. + * @param showModal Whether to show a loading modal. + * @returns Promise resolved with the converted URL. + */ + async getAutoLoginUrl(url: string, showModal: boolean = true): Promise { + if (!this.privateToken) { + // No private token, don't change the URL. + return url; + } + + if (!this.containsUrl(url)) { + // URL doesn't belong to the site, don't auto login. + return url; + } + + if (this.lastAutoLogin > 0) { + const timeBetweenRequests = await CoreUtils.ignoreErrors( + this.getConfig('tool_mobile_autologinmintimebetweenreq'), + CoreConstants.SECONDS_MINUTE * 6, + ); + + if (CoreTimeUtils.timestamp() - this.lastAutoLogin < Number(timeBetweenRequests)) { + // Not enough time has passed since last auto login. + return url; + } + } + + const userId = this.getUserId(); + const params = { + privatetoken: this.privateToken, + }; + let modal: CoreIonLoadingElement | undefined; + + if (showModal) { + modal = await CoreDomUtils.showModalLoading(); + } + + try { + // Use write to not use cache. + const data = await this.write('tool_mobile_get_autologin_key', params); + + if (!data.autologinurl || !data.key) { + // Not valid data, return the same URL. + return url; + } + + this.lastAutoLogin = CoreTimeUtils.timestamp(); + + return data.autologinurl + '?userid=' + userId + '&key=' + data.key + '&urltogo=' + encodeURIComponent(url); + } catch (error) { + // Couldn't get autologin key, return the same URL. + return url; + } finally { + modal?.dismiss(); + } + } + + /** + * Deletes a site setting. + * + * @param name The config name. + * @returns Promise resolved when done. + */ + async deleteSiteConfig(name: string): Promise { + await this.configTable.deleteByPrimaryKey({ name }); + } + + /** + * Get a site setting on local device. + * + * @param name The config name. + * @param defaultValue Default value to use if the entry is not found. + * @returns Resolves upon success along with the config data. Reject on failure. + */ + async getLocalSiteConfig(name: string, defaultValue?: T): Promise { + try { + const entry = await this.configTable.getOneByPrimaryKey({ name }); + + return entry.value; + } catch (error) { + if (defaultValue !== undefined) { + return defaultValue; + } + + throw error; + } + } + + /** + * Set a site setting on local device. + * + * @param name The config name. + * @param value The config value. Can only store number or strings. + * @returns Promise resolved when done. + */ + async setLocalSiteConfig(name: string, value: number | string): Promise { + await this.configTable.insert({ name, value }); + } + + /* + * Check if tokenpluginfile script works in the site. + * + * @param url URL to check. + * @returns Promise resolved with boolean: whether it works or not. + */ + checkTokenPluginFile(url: string): Promise { + if (!CoreUrlUtils.canUseTokenPluginFile(url, this.siteUrl, this.infos && this.infos.userprivateaccesskey)) { + // Cannot use tokenpluginfile. + return Promise.resolve(false); + } else if (this.tokenPluginFileWorks !== undefined) { + // Already checked. + return Promise.resolve(this.tokenPluginFileWorks); + } else if (this.tokenPluginFileWorksPromise) { + // Check ongoing, use the same promise. + return this.tokenPluginFileWorksPromise; + } else if (!CoreNetwork.isOnline()) { + // Not online, cannot check it. Assume it's working, but don't save the result. + return Promise.resolve(true); + } + + url = this.fixPluginfileURL(url); + + this.tokenPluginFileWorksPromise = CoreWS.urlWorks(url).then((result) => { + this.tokenPluginFileWorks = result; + + return result; + }); + + return this.tokenPluginFileWorksPromise; + } + + /** + * Deletes last viewed records based on some conditions. + * + * @param conditions Conditions. + * @returns Promise resolved when done. + */ + async deleteLastViewed(conditions?: Partial): Promise { + await this.lastViewedTable.delete(conditions); + } + + /** + * Get a last viewed record for a component+id. + * + * @param component The component. + * @param id ID. + * @returns Resolves with last viewed record, undefined if not found. + */ + async getLastViewed(component: string, id: number): Promise { + try { + return await this.lastViewedTable.getOneByPrimaryKey({ component, id }); + } catch { + // Not found. + } + } + + /** + * Get several last viewed for a certain component. + * + * @param component The component. + * @param ids IDs. If not provided or empty, return all last viewed for a component. + * @returns Resolves with last viewed records, undefined if error. + */ + async getComponentLastViewed(component: string, ids: number[] = []): Promise { + try { + if (!ids.length) { + return await this.lastViewedTable.getMany({ component }); + } + + const whereAndParams = SQLiteDB.getInOrEqual(ids); + + whereAndParams.sql = 'id ' + whereAndParams.sql + ' AND component = ?'; + whereAndParams.params.push(component); + + return await this.lastViewedTable.getManyWhere({ + sql: whereAndParams.sql, + sqlParams: whereAndParams.params, + js: (record) => record.component === component && ids.includes(record.id), + }); + } catch { + // Not found. + } + } + + /** + * Store a last viewed record. + * + * @param component The component. + * @param id ID. + * @param value Last viewed item value. + * @param options Options. + * @returns Promise resolved when done. + */ + async storeLastViewed( + component: string, + id: number, + value: string | number, + options: CoreSiteStoreLastViewedOptions = {}, + ): Promise { + await this.lastViewedTable.insert({ + component, + id, + value: String(value), + data: options.data, + timeaccess: options.timeaccess ?? Date.now(), + }); + } + +} + +/** + * Optional data to create a site. + */ +export type CoreSiteOptionalData = CoreAuthenticatedSiteOptionalData & { + info?: CoreSiteInfo; + config?: CoreSiteConfig; + loggedOut?: boolean; +}; + +/** + * Result of WS tool_mobile_get_config. + */ +export type CoreSiteConfigResponse = { + settings: { // Settings. + name: string; // The name of the setting. + value: string | number; // The value of the setting. + }[]; + warnings?: CoreWSExternalWarning[]; +}; + +/** + * Site config indexed by name. + */ +export type CoreSiteConfig = Record & { + supportavailability?: string; // String representation of CoreSiteConfigSupportAvailability. + searchbanner?: string; // Search banner text. + searchbannerenable?: string; // Whether search banner is enabled. +}; + +/** + * Result of WS tool_mobile_get_autologin_key. + */ +export type CoreSiteAutologinKeyResult = { + key: string; // Auto-login key for a single usage with time expiration. + autologinurl: string; // Auto-login URL. + warnings?: CoreWSExternalWarning[]; +}; + +/** + * Options for storeLastViewed. + */ +export type CoreSiteStoreLastViewedOptions = { + data?: string; // Other data. + timeaccess?: number; // Accessed time. If not set, current time. +}; diff --git a/src/core/classes/sites/unauthenticated-site.ts b/src/core/classes/sites/unauthenticated-site.ts new file mode 100644 index 00000000000..fe4134fbd99 --- /dev/null +++ b/src/core/classes/sites/unauthenticated-site.ts @@ -0,0 +1,483 @@ +// (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 { CoreConstants } from '@/core/constants'; +import { CoreError } from '@classes/errors/error'; +import { CoreLoginHelper } from '@features/login/services/login-helper'; +import { CoreSitesReadingStrategy } from '@services/sites'; +import { CoreTextUtils } from '@services/utils/text'; +import { CoreUrlUtils } from '@services/utils/url'; +import { CoreWS, CoreWSAjaxPreSets, CoreWSExternalWarning } from '@services/ws'; +import { CorePath } from '@singletons/path'; + +/** + * Class that represents a Moodle site where the user still hasn't authenticated. + */ +export class CoreUnauthenticatedSite { + + siteUrl: string; + + protected publicConfig?: CoreSitePublicConfigResponse; + + /** + * Create a site. + * + * @param siteUrl Site URL. + * @param publicConfig Site public config. + */ + constructor(siteUrl: string, publicConfig?: CoreSitePublicConfigResponse) { + this.siteUrl = CoreUrlUtils.removeUrlParams(siteUrl); // Make sure the URL doesn't have params. + if (publicConfig) { + this.setPublicConfig(publicConfig); + } + } + + /** + * Get site URL. + * + * @returns Site URL. + */ + getURL(): string { + return this.siteUrl; + } + + /** + * Set site URL. + * + * @param url Site URL. + */ + setURL(url: string): void { + this.siteUrl = url; + } + + /** + * Get site info. + * + * @returns Site info. + */ + getInfo(): CoreSiteInfo | undefined { + // Cannot retrieve info for unauthenticated sites. + return undefined; + } + + /** + * Check if the site has info with the given key and it doesn't contain an empty value. + * + * @param key Info key. + * @returns Whether the key is filled within site info. + */ + hasInfo(key: string): boolean { + const info = this.getInfo()?.[key] ?? null; + + return info === false || info === 0 || !!info; + } + + /** + * Get site name. + * + * @returns Site name. + */ + async getSiteName(): Promise { + if (this.isDemoModeSite()) { + return CoreConstants.CONFIG.appname; + } + + const siteName = this.getInfo()?.sitename || this.publicConfig?.sitename; + if (siteName) { + return siteName; + } + + // Fallback. + const isSingleFixedSite = await CoreLoginHelper.isSingleFixedSite(); + + if (isSingleFixedSite) { + const sites = await CoreLoginHelper.getAvailableSites(); + + return sites[0].name; + } + + return ''; + } + + /** + * Check whether the app should use the local logo instead of the remote one. + * + * @returns Whether local logo is forced. + */ + forcesLocalLogo(): boolean { + return CoreConstants.CONFIG.forceLoginLogo || this.isDemoModeSite(); + } + + /** + * Get logo URL from a site public config. + * + * @param config Site public config. + * @returns Logo URL. + */ + getLogoUrl(config?: CoreSitePublicConfigResponse): string | undefined { + config = config ?? this.publicConfig; + if (!config || this.forcesLocalLogo()) { + return 'assets/img/login_logo.png'; + } + + return config.logourl || config.compactlogourl || 'assets/img/login_logo.png'; + } + + /** + * Returns a url to link an specific page on the site. + * + * @param path Path of the url to go to. + * @param params Object with the params to add. + * @param anchor Anchor text if needed. + * @returns URL with params. + */ + createSiteUrl(path: string, params?: Record, anchor?: string): string { + return CoreUrlUtils.addParamsToUrl(CorePath.concatenatePaths(this.siteUrl, path), params, anchor); + } + + /** + * Check if a URL belongs to this site. + * + * @param url URL to check. + * @returns Whether the URL belongs to this site. + */ + containsUrl(url?: string): boolean { + if (!url) { + return false; + } + + const siteUrl = CoreTextUtils.addEndingSlash(CoreUrlUtils.removeProtocolAndWWW(this.siteUrl)); + url = CoreTextUtils.addEndingSlash(CoreUrlUtils.removeProtocolAndWWW(url)); + + return url.indexOf(siteUrl) == 0; + } + + /** + * Get the public config of this site. + * + * @param options Options. + * @returns Promise resolved with public config. Rejected with an object if error, see CoreWSProvider.callAjax. + */ + async getPublicConfig(options: { readingStrategy?: CoreSitesReadingStrategy } = {}): Promise { + const ignoreCache = options.readingStrategy === CoreSitesReadingStrategy.ONLY_NETWORK || + options.readingStrategy === CoreSitesReadingStrategy.PREFER_NETWORK; + if (!ignoreCache && this.publicConfig) { + return this.publicConfig; + }; + + if (options.readingStrategy === CoreSitesReadingStrategy.ONLY_CACHE) { + throw new CoreError('Cache not available to read public config'); + } + + try { + const config = await this.requestPublicConfig(); + + this.setPublicConfig(config); + + return config; + } catch (error) { + if (options.readingStrategy === CoreSitesReadingStrategy.ONLY_NETWORK || !this.publicConfig) { + throw error; + } + + return this.publicConfig; + } + } + + /** + * Set public config. + * + * @param publicConfig Public config. + */ + setPublicConfig(publicConfig: CoreSitePublicConfigResponse): void { + publicConfig.tool_mobile_disabledfeatures = + CoreTextUtils.treatDisabledFeatures(publicConfig.tool_mobile_disabledfeatures ?? ''); + this.publicConfig = publicConfig; + } + + /** + * Perform a request to the server to get the public config of this site. + * + * @returns Promise resolved with public config. + */ + protected async requestPublicConfig(): Promise { + const preSets: CoreWSAjaxPreSets = { + siteUrl: this.siteUrl, + }; + + let config: CoreSitePublicConfigResponse; + + try { + config = await CoreWS.callAjax('tool_mobile_get_public_config', {}, preSets); + } catch (error) { + if (!error || error.errorcode !== 'codingerror' || (this.getInfo() && !this.isAjaxGetSupported())) { + throw error; + } + + // This error probably means that there is a redirect in the site. Try to use a GET request. + preSets.noLogin = true; + preSets.useGet = true; + + try { + config = await CoreWS.callAjax('tool_mobile_get_public_config', {}, preSets); + } catch (error2) { + if (this.isAjaxGetSupported()) { + // GET is supported, return the second error. + throw error2; + } else { + // GET not supported or we don't know if it's supported. Return first error. + throw error; + } + } + } + + // Use the wwwroot returned by the server. + if (config.httpswwwroot) { + this.siteUrl = CoreUrlUtils.removeUrlParams(config.httpswwwroot); // Make sure the URL doesn't have params. + } + + return config; + } + + /** + * Check if GET method is supported for AJAX calls. + * + * @returns Whether it's supported. + * @since Moodle 3.8 + */ + protected isAjaxGetSupported(): boolean { + // We don't know if it's supported, assume it's not. + return false; + } + + /** + * Check if a URL to a file belongs to the site and uses the pluginfileurl or tokenpluginfileurl endpoints. + * + * @param url File URL to check. + * @returns Whether it's a site file URL. + */ + isSitePluginFileUrl(url: string): boolean { + const isPluginFileUrl = CoreUrlUtils.isPluginFileUrl(url) || CoreUrlUtils.isTokenPluginFileUrl(url); + if (!isPluginFileUrl) { + return false; + } + + return this.containsUrl(url); + } + + /** + * Check if a URL to a file belongs to the site and is a theme image file. + * + * @param url File URL to check. + * @returns Whether it's a site theme image URL. + */ + isSiteThemeImageUrl(url: string): boolean { + if (!CoreUrlUtils.isThemeImageUrl(url)) { + return false; + } + + return this.containsUrl(url); + } + + /** + * Check if the site is a demo mode site. + * + * @returns Whether the site is a demo mode site. + */ + isDemoModeSite(): boolean { + const demoSiteData = CoreLoginHelper.getDemoModeSiteInfo(); + + return this.containsUrl(demoSiteData?.url); + } + + /** + * Check whether informative links should be displayed for this site. + * + * @returns Whether informative links should be displayed. + */ + shouldDisplayInformativeLinks(): boolean { + return !CoreConstants.CONFIG.hideInformativeLinks && !this.isDemoModeSite(); + } + + /** + * Check if a certain feature is disabled in the site. + * + * @param name Name of the feature to check. + * @returns Whether it's disabled. + */ + isFeatureDisabled(name: string): boolean { + const disabledFeatures = this.getDisabledFeatures(); + if (!disabledFeatures) { + return false; + } + + const regEx = new RegExp('(,|^)' + CoreTextUtils.escapeForRegex(name) + '(,|$)', 'g'); + + return !!disabledFeatures.match(regEx); + } + + /** + * Get disabled features string. + * + * @returns Disabled features. + */ + protected getDisabledFeatures(): string | undefined { + return this.publicConfig?.tool_mobile_disabledfeatures; + } + +} + +/** + * Result of WS core_webservice_get_site_info. + */ +export type CoreSiteInfoResponse = { + sitename: string; // Site name. + username: string; // Username. + firstname: string; // First name. + lastname: string; // Last name. + fullname: string; // User full name. + lang: string; // Current language. + userid: number; // User id. + siteurl: string; // Site url. + userpictureurl: string; // The user profile picture. + functions: { + name: string; // Function name. + version: string; // The version number of the component to which the function belongs. + }[]; + downloadfiles?: number; // 1 if users are allowed to download files, 0 if not. + uploadfiles?: number; // 1 if users are allowed to upload files, 0 if not. + release?: string; // Moodle release number. + version?: string; // Moodle version number. + mobilecssurl?: string; // Mobile custom CSS theme. + advancedfeatures?: { // Advanced features availability. + name: string; // Feature name. + value: number; // Feature value. Usually 1 means enabled. + }[]; + usercanmanageownfiles?: boolean; // True if the user can manage his own files. + userquota?: number; // User quota (bytes). 0 means user can ignore the quota. + usermaxuploadfilesize?: number; // User max upload file size (bytes). -1 means the user can ignore the upload file size. + userhomepage?: CoreSiteInfoUserHomepage; // The default home page for the user. + userprivateaccesskey?: string; // Private user access key for fetching files. + siteid?: number; // Site course ID. + sitecalendartype?: string; // Calendar type set in the site. + usercalendartype?: string; // Calendar typed used by the user. + userissiteadmin?: boolean; // Whether the user is a site admin or not. + theme?: string; // Current theme for the user. +}; + +/** + * Site info, including some calculated data. + */ +export type CoreSiteInfo = CoreSiteInfoResponse & { + functionsByName?: { + [name: string]: { + name: string; // Function name. + version: string; // The version number of the component to which the function belongs. + }; + }; +}; + +/** + * Enum constants that define default user home page. + */ +export enum CoreSiteInfoUserHomepage { + HOMEPAGE_SITE = 0, // Site home. + HOMEPAGE_MY = 1, // Dashboard. + HOMEPAGE_MYCOURSES = 3, // My courses. +} + +/** + * Possible values for 'supportavailability' config. + */ +export const enum CoreSiteConfigSupportAvailability { + Disabled = 0, + Authenticated = 1, + Anyone = 2, +} + +/** + * Result of WS tool_mobile_get_public_config. + */ +export type CoreSitePublicConfigResponse = { + wwwroot: string; // Site URL. + httpswwwroot: string; // Site https URL (if httpslogin is enabled). + sitename: string; // Site name. + guestlogin: number; // Whether guest login is enabled. + rememberusername: number; // Values: 0 for No, 1 for Yes, 2 for optional. + authloginviaemail: number; // Whether log in via email is enabled. + registerauth: string; // Authentication method for user registration. + forgottenpasswordurl: string; // Forgotten password URL. + authinstructions: string; // Authentication instructions. + authnoneenabled: number; // Whether auth none is enabled. + enablewebservices: number; // Whether Web Services are enabled. + enablemobilewebservice: number; // Whether the Mobile service is enabled. + maintenanceenabled: number; // Whether site maintenance is enabled. + maintenancemessage: string; // Maintenance message. + logourl?: string; // The site logo URL. + compactlogourl?: string; // The site compact logo URL. + typeoflogin: TypeOfLogin; // The type of login. 1 for app, 2 for browser, 3 for embedded. + launchurl?: string; // SSO login launch URL. + mobilecssurl?: string; // Mobile custom CSS theme. + // eslint-disable-next-line @typescript-eslint/naming-convention + tool_mobile_disabledfeatures?: string; // Disabled features in the app. + identityproviders?: CoreSiteIdentityProvider[]; // Identity providers. + country?: string; // Default site country. + agedigitalconsentverification?: boolean; // Whether age digital consent verification is enabled. + supportname?: string; // Site support contact name (only if age verification is enabled). + supportemail?: string; // Site support contact email (only if age verification is enabled). + supportavailability?: CoreSiteConfigSupportAvailability; + supportpage?: string; // Site support contact url. + autolang?: number; // Whether to detect default language from browser setting. + lang?: string; // Default language for the site. + langmenu?: number; // Whether the language menu should be displayed. + langlist?: string; // Languages on language menu. + locale?: string; // Sitewide locale. + // eslint-disable-next-line @typescript-eslint/naming-convention + tool_mobile_minimumversion?: string; // Minimum required version to access. + // eslint-disable-next-line @typescript-eslint/naming-convention + tool_mobile_iosappid?: string; // IOS app's unique identifier. + // eslint-disable-next-line @typescript-eslint/naming-convention + tool_mobile_androidappid?: string; // Android app's unique identifier. + // eslint-disable-next-line @typescript-eslint/naming-convention + tool_mobile_setuplink?: string; // App download page. + tool_mobile_qrcodetype?: CoreSiteQRCodeType; // eslint-disable-line @typescript-eslint/naming-convention + warnings?: CoreWSExternalWarning[]; +}; + +/** + * QR Code type enumeration. + */ +export enum CoreSiteQRCodeType { + QR_CODE_DISABLED = 0, // QR code disabled value + QR_CODE_URL = 1, // QR code type URL value + QR_CODE_LOGIN = 2, // QR code type login value +} + +/** + * Identity provider. + */ +export type CoreSiteIdentityProvider = { + name: string; // The identity provider name. + iconurl: string; // The icon URL for the provider. + url: string; // The URL of the provider. +}; + +/** + * The type of login. 1 for app, 2 for browser, 3 for embedded. + */ +export enum TypeOfLogin { + APP = 1, + BROWSER = 2, // SSO in browser window is required. + EMBEDDED = 3, // SSO in embedded browser is required. +} diff --git a/src/core/components/sites-list/sites-list.ts b/src/core/components/sites-list/sites-list.ts index b92dd59cab7..812cade37dc 100644 --- a/src/core/components/sites-list/sites-list.ts +++ b/src/core/components/sites-list/sites-list.ts @@ -14,8 +14,9 @@ import { Component, ContentChild, Input, Output, TemplateRef, EventEmitter } from '@angular/core'; -import { CoreSiteBasicInfo, CoreSites } from '@services/sites'; +import { CoreSiteBasicInfo } from '@services/sites'; import { CoreAccountsList } from '@features/login/services/login-helper'; +import { CoreSitesFactory } from '@services/sites-factory'; /** * Component to display a list of sites (accounts). @@ -84,7 +85,7 @@ export class CoreSitesListComponent { * @returns Whether to display URL. */ displaySiteUrl(site: CoreSiteBasicInfo): boolean { - return CoreSites.shouldDisplayInformativeLinks(site.siteUrl); + return CoreSitesFactory.makeSite(site.id, site.siteUrl, '', { info: site.info }).shouldDisplayInformativeLinks(); } } diff --git a/src/core/components/user-avatar/user-avatar.ts b/src/core/components/user-avatar/user-avatar.ts index 6c3e137e5d2..6b8778014b6 100644 --- a/src/core/components/user-avatar/user-avatar.ts +++ b/src/core/components/user-avatar/user-avatar.ts @@ -22,7 +22,7 @@ import { CoreNavigator } from '@services/navigator'; import { CoreNetwork } from '@services/network'; import { CoreUserHelper } from '@features/user/services/user-helper'; import { CoreUrlUtils } from '@services/utils/url'; -import { CoreSiteInfo } from '@classes/site'; +import { CoreSiteInfo } from '@classes/sites/unauthenticated-site'; /** * Component to display a "user avatar". diff --git a/src/core/directives/external-content.ts b/src/core/directives/external-content.ts index d1a561b68ee..e8c239884d1 100644 --- a/src/core/directives/external-content.ts +++ b/src/core/directives/external-content.ts @@ -30,7 +30,7 @@ import { CoreUrlUtils } from '@services/utils/url'; import { CoreUtils } from '@services/utils/utils'; import { CoreLogger } from '@singletons/logger'; import { CoreError } from '@classes/errors/error'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreConstants } from '../constants'; import { CoreNetwork } from '@services/network'; diff --git a/src/core/directives/format-text.ts b/src/core/directives/format-text.ts index 2046dbc943a..bc6a16d6206 100644 --- a/src/core/directives/format-text.ts +++ b/src/core/directives/format-text.ts @@ -34,7 +34,7 @@ import { CoreDomUtils } from '@services/utils/dom'; import { CoreIframeUtils, CoreIframeUtilsProvider } from '@services/utils/iframe'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUtils } from '@services/utils/utils'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { NgZone, Translate } from '@singletons'; import { CoreExternalContentDirective } from './external-content'; import { CoreLinkDirective } from './link'; diff --git a/src/core/directives/tests/format-text.test.ts b/src/core/directives/tests/format-text.test.ts index 843e7674250..34c08c18b89 100644 --- a/src/core/directives/tests/format-text.test.ts +++ b/src/core/directives/tests/format-text.test.ts @@ -21,7 +21,7 @@ import { CoreFilepool } from '@services/filepool'; import { CoreFilter } from '@features/filter/services/filter'; import { CoreFilterHelper } from '@features/filter/services/filter-helper'; import { CoreFormatTextDirective } from '@directives/format-text'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreSites } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; diff --git a/src/core/features/autologout/services/autologout.ts b/src/core/features/autologout/services/autologout.ts index 4d721cacf80..49ed2c3f807 100644 --- a/src/core/features/autologout/services/autologout.ts +++ b/src/core/features/autologout/services/autologout.ts @@ -13,7 +13,7 @@ // limitations under the License. import { Injectable } from '@angular/core'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CorePlatform } from '@services/platform'; import { CoreSites } from '@services/sites'; import { CoreStorage } from '@services/storage'; diff --git a/src/core/features/block/services/block-delegate.ts b/src/core/features/block/services/block-delegate.ts index 8a579bdff0f..2f224c275ba 100644 --- a/src/core/features/block/services/block-delegate.ts +++ b/src/core/features/block/services/block-delegate.ts @@ -15,7 +15,7 @@ import { Injectable, Type } from '@angular/core'; import { CoreSites } from '@services/sites'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { Subject } from 'rxjs'; import { CoreCourseBlock } from '@features/course/services/course'; import { Params } from '@angular/router'; diff --git a/src/core/features/comments/services/comments.ts b/src/core/features/comments/services/comments.ts index a183e9ed07f..288dd72935c 100644 --- a/src/core/features/comments/services/comments.ts +++ b/src/core/features/comments/services/comments.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreNetwork } from '@services/network'; import { CoreSites } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; @@ -23,6 +23,7 @@ import { makeSingleton } from '@singletons'; import { CoreEvents } from '@singletons/events'; import { CoreCommentsOffline } from './comments-offline'; import { CoreCommentsSyncAutoSyncData, CoreCommentsSyncProvider } from './comments-sync'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmComments:'; diff --git a/src/core/features/contentlinks/components/choose-site-modal/choose-site-modal.ts b/src/core/features/contentlinks/components/choose-site-modal/choose-site-modal.ts index 1bcbe6325f1..193b1996b4b 100644 --- a/src/core/features/contentlinks/components/choose-site-modal/choose-site-modal.ts +++ b/src/core/features/contentlinks/components/choose-site-modal/choose-site-modal.ts @@ -20,6 +20,7 @@ import { CoreContentLinksAction } from '../../services/contentlinks-delegate'; import { CoreContentLinksHelper } from '../../services/contentlinks-helper'; import { CoreError } from '@classes/errors/error'; import { CoreNavigator } from '@services/navigator'; +import { CoreSitesFactory } from '@services/sites-factory'; /** * Page to display the list of sites to choose one to perform a content link action. @@ -73,7 +74,7 @@ export class CoreContentLinksChooseSiteModalComponent implements OnInit { this.sites = await CoreSites.getSites(siteIds); // All sites have the same URL, use the first one. - this.displaySiteUrl = CoreSites.shouldDisplayInformativeLinks(this.sites[0].siteUrl); + this.displaySiteUrl = CoreSitesFactory.makeUnauthenticatedSite(this.sites[0].siteUrl).shouldDisplayInformativeLinks(); } catch (error) { CoreDomUtils.showErrorModalDefault(error, 'core.contentlinks.errornosites', true); this.closeModal(); diff --git a/src/core/features/contentlinks/services/contentlinks-helper.ts b/src/core/features/contentlinks/services/contentlinks-helper.ts index 84291fe3808..cb2b0db6fe4 100644 --- a/src/core/features/contentlinks/services/contentlinks-helper.ts +++ b/src/core/features/contentlinks/services/contentlinks-helper.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreContentLinksDelegate, CoreContentLinksAction } from './contentlinks-delegate'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton, Translate } from '@singletons'; import { CoreNavigator } from '@services/navigator'; import { CoreContentLinksChooseSiteModalComponent } from '../components/choose-site-modal/choose-site-modal'; diff --git a/src/core/features/course/components/module-summary/module-summary.ts b/src/core/features/course/components/module-summary/module-summary.ts index 8500ecd47b3..8c908987ed9 100644 --- a/src/core/features/course/components/module-summary/module-summary.ts +++ b/src/core/features/course/components/module-summary/module-summary.ts @@ -101,7 +101,7 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { } this.displayOptions = Object.assign({ - displayOpenInBrowser: CoreSites.shouldDisplayInformativeLinks(), + displayOpenInBrowser: !!CoreSites.getCurrentSite()?.shouldDisplayInformativeLinks(), displayDescription: true, displayRefresh: true, displayPrefetch: true, diff --git a/src/core/features/course/pages/course-summary/course-summary.page.ts b/src/core/features/course/pages/course-summary/course-summary.page.ts index 73512e8224e..c1943250dae 100644 --- a/src/core/features/course/pages/course-summary/course-summary.page.ts +++ b/src/core/features/course/pages/course-summary/course-summary.page.ts @@ -138,7 +138,7 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy { const currentSiteUrl = CoreSites.getRequiredCurrentSite().getURL(); this.enrolUrl = CorePath.concatenatePaths(currentSiteUrl, 'enrol/index.php?id=' + this.courseId); this.courseUrl = CorePath.concatenatePaths(currentSiteUrl, 'course/view.php?id=' + this.courseId); - this.displayOpenInBrowser = CoreSites.shouldDisplayInformativeLinks(); + this.displayOpenInBrowser = CoreSites.getRequiredCurrentSite().shouldDisplayInformativeLinks(); await this.getCourse(); } diff --git a/src/core/features/course/pages/module-preview/module-preview.ts b/src/core/features/course/pages/module-preview/module-preview.ts index c5192b9d6b3..bbaf90c66a7 100644 --- a/src/core/features/course/pages/module-preview/module-preview.ts +++ b/src/core/features/course/pages/module-preview/module-preview.ts @@ -63,7 +63,7 @@ export class CoreCourseModulePreviewPage implements OnInit { return; } - this.displayOpenInBrowser = CoreSites.shouldDisplayInformativeLinks(); + this.displayOpenInBrowser = !!CoreSites.getCurrentSite()?.shouldDisplayInformativeLinks(); this.debouncedUpdateModule = CoreUtils.debounce(() => { this.doRefresh(); }, 10000); diff --git a/src/core/features/course/services/course-helper.ts b/src/core/features/course/services/course-helper.ts index 7a0126609ca..b6de863d447 100644 --- a/src/core/features/course/services/course-helper.ts +++ b/src/core/features/course/services/course-helper.ts @@ -58,7 +58,7 @@ import { import { CoreFileSizeSum } from '@services/plugin-file-delegate'; import { CoreFileHelper } from '@services/file-helper'; import { CoreNetwork } from '@services/network'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreFile } from '@services/file'; import { CoreUrlUtils } from '@services/utils/url'; import { CoreTextUtils } from '@services/utils/text'; diff --git a/src/core/features/course/services/course.ts b/src/core/features/course/services/course.ts index 2380f13c705..aba3a28c85d 100644 --- a/src/core/features/course/services/course.ts +++ b/src/core/features/course/services/course.ts @@ -21,7 +21,7 @@ import { CoreLogger } from '@singletons/logger'; import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites'; import { CoreTimeUtils } from '@services/utils/time'; import { CoreUtils } from '@services/utils/utils'; -import { CoreSiteWSPreSets, CoreSite, WSObservable } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreConstants } from '@/core/constants'; import { makeSingleton, Translate } from '@singletons'; import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; @@ -55,6 +55,7 @@ import { SQLiteDB } from '@classes/sqlitedb'; import { CorePlatform } from '@services/platform'; import { asyncObservable, firstValueFrom } from '@/core/utils/rxjs'; import { map } from 'rxjs/operators'; +import { CoreSiteWSPreSets, WSObservable } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmCourse:'; diff --git a/src/core/features/course/services/module-delegate.ts b/src/core/features/course/services/module-delegate.ts index 69474390803..1d0f9170f3a 100644 --- a/src/core/features/course/services/module-delegate.ts +++ b/src/core/features/course/services/module-delegate.ts @@ -15,7 +15,7 @@ import { Injectable, Type } from '@angular/core'; import { SafeUrl } from '@angular/platform-browser'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseModuleDefaultHandler } from './handlers/default-module'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; import { CoreCourseAnyCourseData } from '@features/courses/services/courses'; diff --git a/src/core/features/course/services/module-prefetch-delegate.ts b/src/core/features/course/services/module-prefetch-delegate.ts index 39c18d65112..845e2c99fd7 100644 --- a/src/core/features/course/services/module-prefetch-delegate.ts +++ b/src/core/features/course/services/module-prefetch-delegate.ts @@ -24,7 +24,7 @@ import { CoreTimeUtils } from '@services/utils/time'; import { CoreUtils } from '@services/utils/utils'; import { CoreCourse, CoreCourseAnyModuleData, CoreCourseModuleContentFile } from './course'; import { CoreCache } from '@classes/cache'; -import { CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { CoreConstants } from '@/core/constants'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; import { makeSingleton } from '@singletons'; diff --git a/src/core/features/courses/services/courses-helper.ts b/src/core/features/courses/services/courses-helper.ts index 682397e0162..a6464390a4e 100644 --- a/src/core/features/courses/services/courses-helper.ts +++ b/src/core/features/courses/services/courses-helper.ts @@ -29,7 +29,7 @@ import moment from 'moment-timezone'; import { of } from 'rxjs'; import { firstValueFrom, zipIncludingComplete } from '@/core/utils/rxjs'; import { catchError, map } from 'rxjs/operators'; -import { chainRequests, WSObservable } from '@classes/site'; +import { chainRequests, WSObservable } from '@classes/sites/authenticated-site'; // Id for a course item representing all courses (for example, for course filters). export const ALL_COURSES_ID = -1; diff --git a/src/core/features/courses/services/courses.ts b/src/core/features/courses/services/courses.ts index f9a8be0ae10..57b4b8a5fe5 100644 --- a/src/core/features/courses/services/courses.ts +++ b/src/core/features/courses/services/courses.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites'; -import { CoreSite, CoreSiteWSPreSets, WSObservable } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; import { CoreWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; import { CoreEvents } from '@singletons/events'; @@ -25,6 +25,7 @@ import { map } from 'rxjs/operators'; import { AddonEnrolGuest, AddonEnrolGuestInfo } from '@addons/enrol/guest/services/guest'; import { AddonEnrolSelf } from '@addons/enrol/self/services/self'; import { CoreEnrol, CoreEnrolEnrolmentInfo, CoreEnrolEnrolmentMethod } from '@features/enrol/services/enrol'; +import { CoreSiteWSPreSets, WSObservable } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'mmCourses:'; diff --git a/src/core/features/courses/services/dashboard.ts b/src/core/features/courses/services/dashboard.ts index 194d32dc807..c207ef908cd 100644 --- a/src/core/features/courses/services/dashboard.ts +++ b/src/core/features/courses/services/dashboard.ts @@ -14,13 +14,14 @@ import { Injectable } from '@angular/core'; import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites'; -import { CoreSite, CoreSiteWSPreSets, WSObservable } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseBlock } from '@features/course/services/course'; import { CoreStatusWithWarningsWSResponse } from '@services/ws'; import { makeSingleton } from '@singletons'; import { CoreError } from '@classes/errors/error'; import { map } from 'rxjs/operators'; import { asyncObservable, firstValueFrom } from '@/core/utils/rxjs'; +import { CoreSiteWSPreSets, WSObservable } from '@classes/sites/authenticated-site'; const ROOT_CACHE_KEY = 'CoreCoursesDashboard:'; diff --git a/src/core/features/courses/services/handlers/my-courses-mainmenu.ts b/src/core/features/courses/services/handlers/my-courses-mainmenu.ts index 619327dc738..110d8f1e70a 100644 --- a/src/core/features/courses/services/handlers/my-courses-mainmenu.ts +++ b/src/core/features/courses/services/handlers/my-courses-mainmenu.ts @@ -13,7 +13,7 @@ // limitations under the License. import { Injectable } from '@angular/core'; -import { CoreSiteInfoUserHomepage } from '@classes/site'; +import { CoreSiteInfoUserHomepage } from '@classes/sites/unauthenticated-site'; import { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@features/mainmenu/services/mainmenu-delegate'; import { CoreSiteHomeHomeHandler } from '@features/sitehome/services/handlers/sitehome-home'; import { CoreSites } from '@services/sites'; diff --git a/src/core/features/enrol/services/enrol.ts b/src/core/features/enrol/services/enrol.ts index 63117019f3a..c0a47825858 100644 --- a/src/core/features/enrol/services/enrol.ts +++ b/src/core/features/enrol/services/enrol.ts @@ -14,7 +14,7 @@ import { Injectable } from '@angular/core'; import { makeSingleton } from '@singletons'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreSites } from '@services/sites'; import { CoreUtils } from '@services/utils/utils'; import { CoreEnrolAction, CoreEnrolDelegate } from './enrol-delegate'; diff --git a/src/core/features/fileuploader/services/fileuploader.ts b/src/core/features/fileuploader/services/fileuploader.ts index c64a654b6a9..b9565d276cf 100644 --- a/src/core/features/fileuploader/services/fileuploader.ts +++ b/src/core/features/fileuploader/services/fileuploader.ts @@ -28,7 +28,7 @@ import { CoreWSFile, CoreWSFileUploadOptions, CoreWSUploadFileResult } from '@se import { makeSingleton, Translate, MediaCapture, Camera } from '@singletons'; import { CoreLogger } from '@singletons/logger'; import { CoreError } from '@classes/errors/error'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreFileEntry, CoreFileHelper } from '@services/file-helper'; import { CorePath } from '@singletons/path'; import { CorePlatform } from '@services/platform'; diff --git a/src/core/features/filter/services/filter-delegate.ts b/src/core/features/filter/services/filter-delegate.ts index 88eafb41bfd..07031aae76e 100644 --- a/src/core/features/filter/services/filter-delegate.ts +++ b/src/core/features/filter/services/filter-delegate.ts @@ -18,7 +18,7 @@ import { CoreSites } from '@services/sites'; import { CoreFilterFilter, CoreFilterFormatTextOptions } from './filter'; import { CoreFilterDefaultHandler } from './handlers/default-filter'; import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { makeSingleton } from '@singletons'; /** diff --git a/src/core/features/filter/services/filter-helper.ts b/src/core/features/filter/services/filter-helper.ts index 627518c592f..e5d6cb3088b 100644 --- a/src/core/features/filter/services/filter-helper.ts +++ b/src/core/features/filter/services/filter-helper.ts @@ -29,7 +29,7 @@ import { CoreCourses } from '@features/courses/services/courses'; import { makeSingleton } from '@singletons'; import { CoreEvents, CoreEventSiteData } from '@singletons/events'; import { CoreLogger } from '@singletons/logger'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreCourseHelper } from '@features/course/services/course-helper'; import { firstValueFrom } from '@/core/utils/rxjs'; diff --git a/src/core/features/filter/services/filter.ts b/src/core/features/filter/services/filter.ts index 76ad93ff4dc..f82862f84cf 100644 --- a/src/core/features/filter/services/filter.ts +++ b/src/core/features/filter/services/filter.ts @@ -16,13 +16,14 @@ import { Injectable } from '@angular/core'; import { CoreNetwork } from '@services/network'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreWSExternalWarning } from '@services/ws'; import { CoreTextUtils } from '@services/utils/text'; import { CoreFilterDelegate } from './filter-delegate'; import { makeSingleton } from '@singletons'; import { CoreEvents, CoreEventSiteData } from '@singletons/events'; import { CoreLogger } from '@singletons/logger'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; /** * Service to provide filter functionalities. diff --git a/src/core/features/filter/services/handlers/default-filter.ts b/src/core/features/filter/services/handlers/default-filter.ts index 625b5bd9bea..e94161ba679 100644 --- a/src/core/features/filter/services/handlers/default-filter.ts +++ b/src/core/features/filter/services/handlers/default-filter.ts @@ -16,7 +16,7 @@ import { Injectable, ViewContainerRef } from '@angular/core'; import { CoreFilterHandler } from '../filter-delegate'; import { CoreFilterFilter, CoreFilterFormatTextOptions } from '../filter'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; /** * Default handler used when the module doesn't have a specific implementation. diff --git a/src/core/features/grades/services/grades.ts b/src/core/features/grades/services/grades.ts index 1308c2d9455..789fe0df2d5 100644 --- a/src/core/features/grades/services/grades.ts +++ b/src/core/features/grades/services/grades.ts @@ -18,7 +18,7 @@ import { CoreSites } from '@services/sites'; import { makeSingleton } from '@singletons'; import { CoreLogger } from '@singletons/logger'; import { CoreWSExternalWarning } from '@services/ws'; -import { CoreSiteWSPreSets } from '@classes/site'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { CoreError } from '@classes/errors/error'; import { SafeNumber } from '@/core/utils/types'; diff --git a/src/core/features/h5p/components/h5p-iframe/h5p-iframe.ts b/src/core/features/h5p/components/h5p-iframe/h5p-iframe.ts index 080140489c3..e4faf397d0c 100644 --- a/src/core/features/h5p/components/h5p-iframe/h5p-iframe.ts +++ b/src/core/features/h5p/components/h5p-iframe/h5p-iframe.ts @@ -25,7 +25,7 @@ import { CoreDomUtils } from '@services/utils/dom'; import { CoreUrlUtils } from '@services/utils/url'; import { CoreH5P } from '@features/h5p/services/h5p'; import { CoreConstants } from '@/core/constants'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreLogger } from '@singletons/logger'; import { CoreH5PCore, CoreH5PDisplayOptions } from '../../classes/core'; import { CoreH5PHelper } from '../../classes/helper'; diff --git a/src/core/features/h5p/components/h5p-player/h5p-player.ts b/src/core/features/h5p/components/h5p-player/h5p-player.ts index 87b85e40a21..1b158ca877d 100644 --- a/src/core/features/h5p/components/h5p-player/h5p-player.ts +++ b/src/core/features/h5p/components/h5p-player/h5p-player.ts @@ -21,7 +21,7 @@ import { CoreDomUtils } from '@services/utils/dom'; import { CoreUrlUtils } from '@services/utils/url'; import { CorePluginFileDelegate } from '@services/plugin-file-delegate'; import { CoreConstants } from '@/core/constants'; -import { CoreSite } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreEvents, CoreEventObserver } from '@singletons/events'; import { CoreLogger } from '@singletons/logger'; import { CoreH5P } from '@features/h5p/services/h5p'; diff --git a/src/core/features/h5p/services/h5p.ts b/src/core/features/h5p/services/h5p.ts index 0d0fe9c7476..81586e55afa 100644 --- a/src/core/features/h5p/services/h5p.ts +++ b/src/core/features/h5p/services/h5p.ts @@ -18,7 +18,7 @@ import { CoreSites } from '@services/sites'; import { CoreWSExternalWarning, CoreWSExternalFile, CoreWSFile } from '@services/ws'; import { CoreUrlUtils } from '@services/utils/url'; import { CoreQueueRunner } from '@classes/queue-runner'; -import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; +import { CoreSite } from '@classes/sites/site'; import { CoreH5PCore } from '../classes/core'; import { CoreH5PFramework } from '../classes/framework'; @@ -29,6 +29,7 @@ import { CoreH5PValidator } from '../classes/validator'; import { makeSingleton } from '@singletons'; import { CoreError } from '@classes/errors/error'; import { CorePath } from '@singletons/path'; +import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; /** * Service to provide H5P functionalities. diff --git a/src/core/features/login/components/login-methods/login-methods.ts b/src/core/features/login/components/login-methods/login-methods.ts index a934c1bc086..ce0df2c195b 100644 --- a/src/core/features/login/components/login-methods/login-methods.ts +++ b/src/core/features/login/components/login-methods/login-methods.ts @@ -13,10 +13,11 @@ // limitations under the License. import { Component, Input, OnInit } from '@angular/core'; -import { CoreSiteIdentityProvider, CoreSitePublicConfigResponse } from '@classes/site'; +import { CoreSiteIdentityProvider, CoreSitePublicConfigResponse } from '@classes/sites/unauthenticated-site'; import { CoreLoginHelper, CoreLoginMethod } from '@features/login/services/login-helper'; import { CoreRedirectPayload } from '@services/navigator'; import { CoreSites } from '@services/sites'; +import { CoreSitesFactory } from '@services/sites-factory'; import { CoreDomUtils } from '@services/utils/dom'; @Component({ @@ -53,11 +54,11 @@ export class CoreLoginMethodsComponent implements OnInit { if (this.siteConfig) { this.isBrowserSSO = CoreLoginHelper.isSSOLoginNeeded(this.siteConfig.typeoflogin); + // Identity providers won't be shown if login on browser. if (!this.isBrowserSSO) { - // Identity providers won't be shown if login on browser. - const disabledFeatures = CoreLoginHelper.getDisabledFeatures(this.siteConfig); - - this.identityProviders = CoreLoginHelper.getValidIdentityProviders(this.siteConfig, disabledFeatures); + this.identityProviders = await CoreLoginHelper.getValidIdentityProvidersForSite( + CoreSitesFactory.makeUnauthenticatedSite(this.siteUrl, this.siteConfig), + ); } if (this.reconnect) { diff --git a/src/core/features/login/components/site-help/site-help.ts b/src/core/features/login/components/site-help/site-help.ts index 51629ee3b60..ba1b6101dce 100644 --- a/src/core/features/login/components/site-help/site-help.ts +++ b/src/core/features/login/components/site-help/site-help.ts @@ -16,7 +16,7 @@ import { AfterViewInit, Component, ElementRef, HostBinding, OnDestroy } from '@a import { CoreUtils } from '@services/utils/utils'; import { ModalController, Translate } from '@singletons'; -import { CoreLoginHelperProvider, GET_STARTED_URL } from '@features/login/services/login-helper'; +import { FAQ_QRCODE_IMAGE_HTML, FAQ_URL_IMAGE_HTML, GET_STARTED_URL } from '@features/login/constants'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreCancellablePromise } from '@classes/cancellable-promise'; @@ -39,8 +39,8 @@ export class CoreLoginSiteHelpComponent implements AfterViewInit, OnDestroy { constructor(protected el: ElementRef) { const getStartedTitle = Translate.instant('core.login.faqsetupsitelinktitle'); const canScanQR = CoreUtils.canScanQR(); - const urlImageHtml = CoreLoginHelperProvider.FAQ_URL_IMAGE_HTML; - const qrCodeImageHtml = CoreLoginHelperProvider.FAQ_QRCODE_IMAGE_HTML; + const urlImageHtml = FAQ_URL_IMAGE_HTML; + const qrCodeImageHtml = FAQ_QRCODE_IMAGE_HTML; const setupLinkHtml = `${GET_STARTED_URL}`; const questions: Array = [ { diff --git a/src/core/features/login/components/site-onboarding/site-onboarding.ts b/src/core/features/login/components/site-onboarding/site-onboarding.ts index b8073697550..2b5896b604f 100644 --- a/src/core/features/login/components/site-onboarding/site-onboarding.ts +++ b/src/core/features/login/components/site-onboarding/site-onboarding.ts @@ -16,7 +16,7 @@ import { Component } from '@angular/core'; import { CoreConfig } from '@services/config'; import { CoreUtils } from '@services/utils/utils'; -import { CoreLoginHelperProvider, GET_STARTED_URL } from '@features/login/services/login-helper'; +import { GET_STARTED_URL, ONBOARDING_DONE } from '@features/login/constants'; import { ModalController } from '@singletons'; /** @@ -88,7 +88,7 @@ export class CoreLoginSiteOnboardingComponent { * Saves the onboarding has finished. */ protected saveOnboardingDone(): void { - CoreConfig.set(CoreLoginHelperProvider.ONBOARDING_DONE, 1); + CoreConfig.set(ONBOARDING_DONE, 1); } } diff --git a/src/core/features/login/constants.ts b/src/core/features/login/constants.ts new file mode 100644 index 00000000000..0da8f8fe348 --- /dev/null +++ b/src/core/features/login/constants.ts @@ -0,0 +1,23 @@ +// (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. + +export const GET_STARTED_URL = 'https://moodle.com'; +export const ONBOARDING_DONE = 'onboarding_done'; +export const FAQ_QRCODE_INFO_DONE = 'qrcode_info_done'; +export const FAQ_URL_IMAGE_HTML = ''; +export const FAQ_QRCODE_IMAGE_HTML = ''; +export const EMAIL_SIGNUP_FEATURE_NAME = 'CoreLoginEmailSignup'; +export const FORGOTTEN_PASSWORD_FEATURE_NAME = 'NoDelegate_ForgottenPassword'; +export const IDENTITY_PROVIDERS_FEATURE_NAME = 'NoDelegate_IdentityProviders'; +export const IDENTITY_PROVIDER_FEATURE_NAME_PREFIX = 'NoDelegate_IdentityProvider_'; diff --git a/src/core/features/login/pages/credentials/credentials.html b/src/core/features/login/pages/credentials/credentials.html index 300cb545fb1..d2cbebcc897 100644 --- a/src/core/features/login/pages/credentials/credentials.html +++ b/src/core/features/login/pages/credentials/credentials.html @@ -20,19 +20,17 @@

{{ 'core.login.login' | translate }}

- +