forked from EVOgeek/Vmeda.Online
		
	
						commit
						3d33629f73
					
				@ -433,6 +433,22 @@
 | 
			
		||||
  "addon.mod_assign_submission_file.pluginname": "assignsubmission_file",
 | 
			
		||||
  "addon.mod_assign_submission_onlinetext.pluginname": "assignsubmission_onlinetext",
 | 
			
		||||
  "addon.mod_assign_submission_onlinetext.wordlimitexceeded": "assignsubmission_onlinetext",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.end_session_confirm": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.end_session_confirm_title": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.mod_form_field_closingtime": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.mod_form_field_openingtime": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.userlimitreached": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_conference_action_end": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_conference_action_join": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_error_unable_join_student": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_groups_selection_warning": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_message_conference_in_progress": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_message_conference_room_ready": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_message_moderator": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_message_moderators": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_message_session_started_at": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_message_viewer": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_bigbluebuttonbn.view_message_viewers": "bigbluebuttonbn",
 | 
			
		||||
  "addon.mod_book.errorchapter": "book",
 | 
			
		||||
  "addon.mod_book.modulenameplural": "book",
 | 
			
		||||
  "addon.mod_book.navnexttitle": "book",
 | 
			
		||||
 | 
			
		||||
@ -55,6 +55,7 @@ export class AddonModAssignSubmissionsSource extends CoreItemsManagerSource<Addo
 | 
			
		||||
        separateGroups: false,
 | 
			
		||||
        visibleGroups: false,
 | 
			
		||||
        defaultGroupId: 0,
 | 
			
		||||
        canAccessAllGroups: false,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    protected submissionsData: { canviewsubmissions: boolean; submissions?: AddonModAssignSubmission[] } = {
 | 
			
		||||
 | 
			
		||||
@ -71,6 +71,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
 | 
			
		||||
        separateGroups: false,
 | 
			
		||||
        visibleGroups: false,
 | 
			
		||||
        defaultGroupId: 0,
 | 
			
		||||
        canAccessAllGroups: false,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Status.
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,38 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { RouterModule, Routes } from '@angular/router';
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { AddonModBBBComponentsModule } from './components/components.module';
 | 
			
		||||
import { AddonModBBBIndexPage } from './pages/index/index';
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
        path: ':courseId/:cmId',
 | 
			
		||||
        component: AddonModBBBIndexPage,
 | 
			
		||||
    },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
        RouterModule.forChild(routes),
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        AddonModBBBComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonModBBBIndexPage,
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBBBLazyModule {}
 | 
			
		||||
							
								
								
									
										54
									
								
								src/addons/mod/bigbluebuttonbn/bigbluebuttonbn.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/addons/mod/bigbluebuttonbn/bigbluebuttonbn.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
			
		||||
// (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 { APP_INITIALIZER, NgModule, Type } from '@angular/core';
 | 
			
		||||
import { Routes } from '@angular/router';
 | 
			
		||||
import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate';
 | 
			
		||||
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
 | 
			
		||||
import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module';
 | 
			
		||||
import { AddonModBBBComponentsModule } from './components/components.module';
 | 
			
		||||
import { AddonModBBBService } from './services/bigbluebuttonbn';
 | 
			
		||||
import { AddonModBBBIndexLinkHandler } from './services/handlers/index-link';
 | 
			
		||||
import { AddonModBBBListLinkHandler } from './services/handlers/list-link';
 | 
			
		||||
import { AddonModBBBModuleHandler, ADDON_MOD_BBB_MAIN_MENU_PAGE_NAME } from './services/handlers/module';
 | 
			
		||||
 | 
			
		||||
export const ADDON_MOD_BBB_SERVICES: Type<unknown>[] = [
 | 
			
		||||
    AddonModBBBService,
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const routes: Routes = [
 | 
			
		||||
    {
 | 
			
		||||
        path: ADDON_MOD_BBB_MAIN_MENU_PAGE_NAME,
 | 
			
		||||
        loadChildren: () => import('./bigbluebuttonbn-lazy.module').then(m => m.AddonModBBBLazyModule),
 | 
			
		||||
    },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreMainMenuTabRoutingModule.forChild(routes),
 | 
			
		||||
        AddonModBBBComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
        {
 | 
			
		||||
            provide: APP_INITIALIZER,
 | 
			
		||||
            multi: true,
 | 
			
		||||
            useValue: () => {
 | 
			
		||||
                CoreCourseModuleDelegate.registerHandler(AddonModBBBModuleHandler.instance);
 | 
			
		||||
                CoreContentLinksDelegate.registerHandler(AddonModBBBIndexLinkHandler.instance);
 | 
			
		||||
                CoreContentLinksDelegate.registerHandler(AddonModBBBListLinkHandler.instance);
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBBBModule {}
 | 
			
		||||
@ -0,0 +1,34 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
import { AddonModBBBIndexComponent } from './index/index';
 | 
			
		||||
import { CoreSharedModule } from '@/core/shared.module';
 | 
			
		||||
import { CoreCourseComponentsModule } from '@features/course/components/components.module';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonModBBBIndexComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreSharedModule,
 | 
			
		||||
        CoreCourseComponentsModule,
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [
 | 
			
		||||
        AddonModBBBIndexComponent,
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBBBComponentsModule {}
 | 
			
		||||
							
								
								
									
										130
									
								
								src/addons/mod/bigbluebuttonbn/components/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								src/addons/mod/bigbluebuttonbn/components/index/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,130 @@
 | 
			
		||||
<!-- Buttons to add to the header. -->
 | 
			
		||||
<core-navbar-buttons slot="end">
 | 
			
		||||
    <core-context-menu>
 | 
			
		||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl"
 | 
			
		||||
            iconAction="fas-external-link-alt">
 | 
			
		||||
        </core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate"
 | 
			
		||||
            (action)="expandDescription()" iconAction="fas-arrow-right">
 | 
			
		||||
        </core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper"
 | 
			
		||||
            (action)="gotoBlog()">
 | 
			
		||||
        </core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="loaded && isOnline" [priority]="700" [content]="'core.refresh' | translate"
 | 
			
		||||
            (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false">
 | 
			
		||||
        </core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)"
 | 
			
		||||
            [iconAction]="prefetchStatusIcon" [closeOnClick]="false">
 | 
			
		||||
        </core-context-menu-item>
 | 
			
		||||
    </core-context-menu>
 | 
			
		||||
</core-navbar-buttons>
 | 
			
		||||
 | 
			
		||||
<!-- Content. -->
 | 
			
		||||
<core-loading [hideUntil]="loaded" class="safe-area-page">
 | 
			
		||||
 | 
			
		||||
    <!-- Activity info. -->
 | 
			
		||||
    <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description"
 | 
			
		||||
        [component]="component" [componentId]="componentId" [courseId]="courseId">
 | 
			
		||||
    </core-course-module-info>
 | 
			
		||||
 | 
			
		||||
    <ng-container *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)">
 | 
			
		||||
        <ion-card class="core-info-card" *ngIf="groupInfo.groups && groupInfo.groups.length > 1">
 | 
			
		||||
            <ion-item>
 | 
			
		||||
                <ion-icon name="fas-question-circle" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                <ion-label>{{ 'addon.mod_bigbluebuttonbn.view_groups_selection_warning' | translate }}</ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
        </ion-card>
 | 
			
		||||
 | 
			
		||||
        <ion-item class="ion-text-wrap">
 | 
			
		||||
            <ion-label id="addon-bigbluebuttonbn-groupslabel">
 | 
			
		||||
                <ng-container *ngIf="groupInfo.separateGroups">{{'core.groupsseparate' | translate }}</ng-container>
 | 
			
		||||
                <ng-container *ngIf="groupInfo.visibleGroups">{{'core.groupsvisible' | translate }}</ng-container>
 | 
			
		||||
            </ion-label>
 | 
			
		||||
            <ion-select [(ngModel)]="groupId" (ionChange)="groupChanged()" aria-labelledby="addon-bigbluebuttonbn-groupslabel"
 | 
			
		||||
                interface="action-sheet" [interfaceOptions]="{header: 'core.group' | translate}">
 | 
			
		||||
                <ion-select-option *ngFor="let groupOpt of groupInfo.groups" [value]="groupOpt.id">
 | 
			
		||||
                    {{groupOpt.name}}
 | 
			
		||||
                </ion-select-option>
 | 
			
		||||
            </ion-select>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
 | 
			
		||||
    <ng-container *ngIf="meetingInfo">
 | 
			
		||||
        <ion-item class="ion-text-wrap" *ngIf="meetingInfo.openingtime">
 | 
			
		||||
            <ion-label>
 | 
			
		||||
                <h3>{{ 'addon.mod_bigbluebuttonbn.mod_form_field_openingtime' | translate }}</h3>
 | 
			
		||||
            </ion-label>
 | 
			
		||||
            <p slot="end">{{ meetingInfo.openingtime * 1000 | coreFormatDate }}</p>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
        <ion-item class="ion-text-wrap" *ngIf="meetingInfo.closingtime">
 | 
			
		||||
            <ion-label>
 | 
			
		||||
                <h3>{{ 'addon.mod_bigbluebuttonbn.mod_form_field_closingtime' | translate }}</h3>
 | 
			
		||||
            </ion-label>
 | 
			
		||||
            <p slot="end">{{ meetingInfo.closingtime * 1000 | coreFormatDate }}</p>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
 | 
			
		||||
        <ion-item class="ion-text-wrap" *ngIf="meetingInfo.canjoin && !meetingInfo.statusrunning">
 | 
			
		||||
            <ion-label>
 | 
			
		||||
                <p>{{ 'addon.mod_bigbluebuttonbn.view_message_conference_room_ready' | translate }}</p>
 | 
			
		||||
            </ion-label>
 | 
			
		||||
        </ion-item>
 | 
			
		||||
 | 
			
		||||
        <ng-container *ngIf="meetingInfo.statusrunning">
 | 
			
		||||
            <ion-item class="ion-text-wrap">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <p>{{ 'addon.mod_bigbluebuttonbn.view_message_conference_in_progress' | translate }}</p>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <ion-item class="ion-text-wrap" *ngIf="meetingInfo.startedat">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <h3>{{ 'addon.mod_bigbluebuttonbn.view_message_session_started_at' | translate }}</h3>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
                <p slot="end">{{ meetingInfo.startedat * 1000 | coreFormatDate: "strftimetime" }}</p>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <ion-item class="ion-text-wrap">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <h3 *ngIf="meetingInfo.moderatorplural">
 | 
			
		||||
                        {{ 'addon.mod_bigbluebuttonbn.view_message_moderators' | translate }}
 | 
			
		||||
                    </h3>
 | 
			
		||||
                    <h3 *ngIf="!meetingInfo.moderatorplural">
 | 
			
		||||
                        {{ 'addon.mod_bigbluebuttonbn.view_message_moderator' | translate }}
 | 
			
		||||
                    </h3>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
                <p slot="end">{{ meetingInfo.moderatorcount }}</p>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
 | 
			
		||||
            <ion-item class="ion-text-wrap">
 | 
			
		||||
                <ion-label>
 | 
			
		||||
                    <h3 *ngIf="meetingInfo.participantplural">
 | 
			
		||||
                        {{ 'addon.mod_bigbluebuttonbn.view_message_viewers' | translate }}
 | 
			
		||||
                    </h3>
 | 
			
		||||
                    <h3 *ngIf="!meetingInfo.participantplural">
 | 
			
		||||
                        {{ 'addon.mod_bigbluebuttonbn.view_message_viewer' | translate }}
 | 
			
		||||
                    </h3>
 | 
			
		||||
                </ion-label>
 | 
			
		||||
                <p slot="end">{{ meetingInfo.participantcount }}</p>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
        </ng-container>
 | 
			
		||||
 | 
			
		||||
        <ion-button *ngIf="meetingInfo.canjoin" class="ion-margin" expand="block" (click)="joinRoom()">
 | 
			
		||||
            {{ 'addon.mod_bigbluebuttonbn.view_conference_action_join' | translate }}
 | 
			
		||||
        </ion-button>
 | 
			
		||||
 | 
			
		||||
        <ion-button *ngIf="meetingInfo.statusrunning && meetingInfo.ismoderator" color="light" class="ion-margin" expand="block"
 | 
			
		||||
            (click)="endMeeting()">
 | 
			
		||||
            {{ 'addon.mod_bigbluebuttonbn.view_conference_action_end' | translate }}
 | 
			
		||||
        </ion-button>
 | 
			
		||||
 | 
			
		||||
        <ion-card *ngIf="!meetingInfo.canjoin" class="core-warning-card">
 | 
			
		||||
            <ion-item class="ion-text-wrap">
 | 
			
		||||
                <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
                <ion-label>{{ meetingInfo.statusmessage }}</ion-label>
 | 
			
		||||
            </ion-item>
 | 
			
		||||
        </ion-card>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
</core-loading>
 | 
			
		||||
 | 
			
		||||
<core-course-module-navigation [hidden]="!loaded" [courseId]="courseId" [currentModuleId]="module.id">
 | 
			
		||||
</core-course-module-navigation>
 | 
			
		||||
@ -0,0 +1,7 @@
 | 
			
		||||
@import "~theme/globals";
 | 
			
		||||
 | 
			
		||||
:host {
 | 
			
		||||
    ion-item > p[slot="end"] {
 | 
			
		||||
        font-size: 14px;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								src/addons/mod/bigbluebuttonbn/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								src/addons/mod/bigbluebuttonbn/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,220 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Component, OnInit, Optional } from '@angular/core';
 | 
			
		||||
import { CoreCourseModuleMainActivityComponent } from '@features/course/classes/main-activity-component';
 | 
			
		||||
import { CoreCourseContentsPage } from '@features/course/pages/contents/contents';
 | 
			
		||||
import { CoreCourse } from '@features/course/services/course';
 | 
			
		||||
import { IonContent } from '@ionic/angular';
 | 
			
		||||
import { CoreGroupInfo, CoreGroups } from '@services/groups';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { Translate } from '@singletons';
 | 
			
		||||
import { AddonModBBB, AddonModBBBData, AddonModBBBMeetingInfoWSResponse, AddonModBBBService } from '../../services/bigbluebuttonbn';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that displays a Big Blue Button activity.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'addon-mod-bbb-index',
 | 
			
		||||
    templateUrl: 'index.html',
 | 
			
		||||
    styleUrls: ['index.scss'],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityComponent implements OnInit {
 | 
			
		||||
 | 
			
		||||
    component = AddonModBBBService.COMPONENT;
 | 
			
		||||
    moduleName = 'bigbluebuttonbn';
 | 
			
		||||
    bbb?: AddonModBBBData;
 | 
			
		||||
    groupInfo?: CoreGroupInfo;
 | 
			
		||||
    groupId = 0;
 | 
			
		||||
    meetingInfo?: AddonModBBBMeetingInfoWSResponse;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        protected content?: IonContent,
 | 
			
		||||
        @Optional() courseContentsPage?: CoreCourseContentsPage,
 | 
			
		||||
    ) {
 | 
			
		||||
        super('AddonModBBBIndexComponent', content, courseContentsPage);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async ngOnInit(): Promise<void> {
 | 
			
		||||
        super.ngOnInit();
 | 
			
		||||
 | 
			
		||||
        await this.loadContent();
 | 
			
		||||
 | 
			
		||||
        if (!this.bbb) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await AddonModBBB.logView(this.bbb.id, this.bbb.name);
 | 
			
		||||
 | 
			
		||||
            CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata);
 | 
			
		||||
        } catch {
 | 
			
		||||
            // Ignore errors.
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    protected async fetchContent(refresh: boolean = false): Promise<void> {
 | 
			
		||||
        try {
 | 
			
		||||
            this.bbb = await AddonModBBB.getBBB(this.courseId, this.module.id);
 | 
			
		||||
 | 
			
		||||
            this.description = this.bbb.intro;
 | 
			
		||||
            this.dataRetrieved.emit(this.bbb);
 | 
			
		||||
 | 
			
		||||
            this.groupInfo = await CoreGroups.getActivityGroupInfo(this.module.id, false);
 | 
			
		||||
 | 
			
		||||
            this.groupId = CoreGroups.validateGroupId(this.groupId, this.groupInfo);
 | 
			
		||||
 | 
			
		||||
            await this.fetchMeetingInfo();
 | 
			
		||||
        } finally {
 | 
			
		||||
            this.fillContextMenu(refresh);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get meeting info.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async fetchMeetingInfo(): Promise<void> {
 | 
			
		||||
        if (!this.bbb) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.meetingInfo = await AddonModBBB.getMeetingInfo(this.bbb.id, this.groupId);
 | 
			
		||||
 | 
			
		||||
        if (this.meetingInfo.statusrunning && this.meetingInfo.userlimit > 0) {
 | 
			
		||||
            const count = (this.meetingInfo.participantcount || 0) + (this.meetingInfo.moderatorcount || 0);
 | 
			
		||||
            if (count === this.meetingInfo.userlimit) {
 | 
			
		||||
                this.meetingInfo.statusmessage = Translate.instant('addon.mod_bigbluebuttonbn.userlimitreached');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update meeting info.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async updateMeetingInfo(): Promise<void> {
 | 
			
		||||
        if (!this.bbb) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.loaded = false;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await AddonModBBB.invalidateAllGroupsMeetingInfo(this.bbb.id);
 | 
			
		||||
 | 
			
		||||
            await this.fetchMeetingInfo();
 | 
			
		||||
        } finally {
 | 
			
		||||
            this.loaded = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    protected async invalidateContent(): Promise<void> {
 | 
			
		||||
        const promises: Promise<void>[] = [];
 | 
			
		||||
 | 
			
		||||
        promises.push(AddonModBBB.invalidateBBBs(this.courseId));
 | 
			
		||||
        promises.push(CoreGroups.invalidateActivityGroupInfo(this.module.id));
 | 
			
		||||
 | 
			
		||||
        if (this.bbb) {
 | 
			
		||||
            promises.push(AddonModBBB.invalidateAllGroupsMeetingInfo(this.bbb.id));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        await Promise.all(promises);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Group changed, reload some data.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async groupChanged(): Promise<void> {
 | 
			
		||||
        this.loaded = false;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await this.fetchMeetingInfo();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.showErrorModal(error);
 | 
			
		||||
        } finally {
 | 
			
		||||
            this.loaded = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Join the room.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async joinRoom(): Promise<void> {
 | 
			
		||||
        const modal = await CoreDomUtils.showModalLoading();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            const joinUrl = await AddonModBBB.getJoinUrl(this.module.id, this.groupId);
 | 
			
		||||
 | 
			
		||||
            CoreUtils.openInBrowser(joinUrl);
 | 
			
		||||
 | 
			
		||||
            this.updateMeetingInfo();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.showErrorModal(error);
 | 
			
		||||
        } finally {
 | 
			
		||||
            modal.dismiss();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * End the meeting.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async endMeeting(): Promise<void> {
 | 
			
		||||
        if (!this.bbb) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await CoreDomUtils.showConfirm(
 | 
			
		||||
                Translate.instant('addon.mod_bigbluebuttonbn.end_session_confirm'),
 | 
			
		||||
                Translate.instant('addon.mod_bigbluebuttonbn.end_session_confirm_title'),
 | 
			
		||||
                Translate.instant('core.yes'),
 | 
			
		||||
            );
 | 
			
		||||
        } catch {
 | 
			
		||||
            // User canceled.
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const modal = await CoreDomUtils.showModalLoading();
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            await AddonModBBB.endMeeting(this.bbb.id, this.groupId);
 | 
			
		||||
 | 
			
		||||
            this.updateMeetingInfo();
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            CoreDomUtils.showErrorModal(error);
 | 
			
		||||
        } finally {
 | 
			
		||||
            modal.dismiss();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								src/addons/mod/bigbluebuttonbn/lang.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/addons/mod/bigbluebuttonbn/lang.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
{
 | 
			
		||||
    "end_session_confirm": "Are you sure you want to end the virtual classroom session?",
 | 
			
		||||
    "end_session_confirm_title": "Really end session?",
 | 
			
		||||
    "mod_form_field_closingtime": "Join closed",
 | 
			
		||||
    "mod_form_field_openingtime": "Join open",
 | 
			
		||||
    "userlimitreached": "The number of users allowed in a meeting has been reached.",
 | 
			
		||||
    "view_conference_action_end": "End session",
 | 
			
		||||
    "view_conference_action_join": "Join session",
 | 
			
		||||
    "view_error_unable_join_student": "Unable to connect to the BigBlueButton server. Please contact your Teacher or the Administrator.",
 | 
			
		||||
    "view_groups_selection_warning": "There is a conference room for each group and you have access to more than one. Be sure to select the correct one.",
 | 
			
		||||
    "view_message_conference_in_progress": "This conference is in progress.",
 | 
			
		||||
    "view_message_conference_room_ready": "This conference room is ready. You can join the session now.",
 | 
			
		||||
    "view_message_moderator": "moderator",
 | 
			
		||||
    "view_message_moderators": "moderators",
 | 
			
		||||
    "view_message_session_started_at": "This session started at",
 | 
			
		||||
    "view_message_viewer": "viewer",
 | 
			
		||||
    "view_message_viewers": "viewers"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								src/addons/mod/bigbluebuttonbn/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/addons/mod/bigbluebuttonbn/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
<ion-header collapsible>
 | 
			
		||||
    <ion-toolbar>
 | 
			
		||||
        <ion-buttons slot="start">
 | 
			
		||||
            <ion-back-button [text]="'core.back' | translate"></ion-back-button>
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
        <ion-title>
 | 
			
		||||
            <h1>
 | 
			
		||||
                <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId">
 | 
			
		||||
                </core-format-text>
 | 
			
		||||
            </h1>
 | 
			
		||||
        </ion-title>
 | 
			
		||||
        <ion-buttons slot="end">
 | 
			
		||||
            <!-- The buttons defined by the component will be added in here. -->
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
    </ion-toolbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <ion-refresher slot="fixed" [disabled]="!activityComponent?.loaded" (ionRefresh)="activityComponent?.doRefresh($event.target)">
 | 
			
		||||
        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
			
		||||
    </ion-refresher>
 | 
			
		||||
 | 
			
		||||
    <addon-mod-bbb-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"></addon-mod-bbb-index>
 | 
			
		||||
</ion-content>
 | 
			
		||||
							
								
								
									
										30
									
								
								src/addons/mod/bigbluebuttonbn/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/addons/mod/bigbluebuttonbn/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
// (C) Copyright 2015 Moodle Pty Ltd.
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Component, ViewChild } from '@angular/core';
 | 
			
		||||
import { CoreCourseModuleMainActivityPage } from '@features/course/classes/main-activity-page';
 | 
			
		||||
import { AddonModBBBIndexComponent } from '../../components/index/index';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that displays a Big Blue Button activity.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'page-addon-mod-bbb-index',
 | 
			
		||||
    templateUrl: 'index.html',
 | 
			
		||||
})
 | 
			
		||||
export class AddonModBBBIndexPage extends CoreCourseModuleMainActivityPage<AddonModBBBIndexComponent> {
 | 
			
		||||
 | 
			
		||||
    @ViewChild(AddonModBBBIndexComponent) activityComponent?: AddonModBBBIndexComponent;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										382
									
								
								src/addons/mod/bigbluebuttonbn/services/bigbluebuttonbn.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								src/addons/mod/bigbluebuttonbn/services/bigbluebuttonbn.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,382 @@
 | 
			
		||||
// (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 { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreError } from '@classes/errors/error';
 | 
			
		||||
import { CoreWSError } from '@classes/errors/wserror';
 | 
			
		||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
 | 
			
		||||
import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
 | 
			
		||||
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
 | 
			
		||||
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
 | 
			
		||||
import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
 | 
			
		||||
import { makeSingleton, Translate } from '@singletons';
 | 
			
		||||
 | 
			
		||||
const ROOT_CACHE_KEY = 'AddonModBBB:';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Service that provides some features for Big Blue Button activity.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonModBBBService {
 | 
			
		||||
 | 
			
		||||
    static readonly COMPONENT = 'mmaModBigBlueButtonBN';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * End a meeting.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id BBB ID.
 | 
			
		||||
     * @param groupId Group ID, 0 means that the function will determine the user group.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    async endMeeting(
 | 
			
		||||
        id: number,
 | 
			
		||||
        groupId: number = 0,
 | 
			
		||||
        siteId?: string,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const site = await CoreSites.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        const params: AddonModBBBEndMeetingWSParams = {
 | 
			
		||||
            bigbluebuttonbnid: id,
 | 
			
		||||
            groupid: groupId,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        await site.write('mod_bigbluebuttonbn_end_meeting', params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a BBB activity.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @param cmId Course module ID.
 | 
			
		||||
     * @param options Other options.
 | 
			
		||||
     * @return Promise resolved when the activity is retrieved.
 | 
			
		||||
     */
 | 
			
		||||
    async getBBB(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModBBBData> {
 | 
			
		||||
        const site = await CoreSites.getSite(options.siteId);
 | 
			
		||||
 | 
			
		||||
        const params: AddonModBBBGetBigBlueButtonBNsByCoursesWSParams = {
 | 
			
		||||
            courseids: [courseId],
 | 
			
		||||
        };
 | 
			
		||||
        const preSets: CoreSiteWSPreSets = {
 | 
			
		||||
            cacheKey: this.getBBBsCacheKey(courseId),
 | 
			
		||||
            updateFrequency: CoreSite.FREQUENCY_RARELY,
 | 
			
		||||
            component: AddonModBBBService.COMPONENT,
 | 
			
		||||
            ...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const response = await site.read<AddonModBBBGetBigBlueButtonBNsByCoursesWSResponse>(
 | 
			
		||||
            'mod_bigbluebuttonbn_get_bigbluebuttonbns_by_courses',
 | 
			
		||||
            params,
 | 
			
		||||
            preSets,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        const bbb = response.bigbluebuttonbns.find((bbb) => bbb.coursemodule == cmId);
 | 
			
		||||
        if (bbb) {
 | 
			
		||||
            return bbb;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        throw new CoreError(Translate.instant('core.course.modulenotfound'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get cache key for get BBB WS call.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @return Cache key.
 | 
			
		||||
     */
 | 
			
		||||
    protected getBBBsCacheKey(courseId: number): string {
 | 
			
		||||
        return ROOT_CACHE_KEY + 'bbb:' + courseId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get join URL for a BBB activity.
 | 
			
		||||
     *
 | 
			
		||||
     * @param cmId Course module ID.
 | 
			
		||||
     * @param groupId Group ID, 0 means that the function will determine the user group.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved with the list of messages.
 | 
			
		||||
     */
 | 
			
		||||
    async getJoinUrl(
 | 
			
		||||
        cmId: number,
 | 
			
		||||
        groupId: number = 0,
 | 
			
		||||
        siteId?: string,
 | 
			
		||||
    ): Promise<string> {
 | 
			
		||||
        const site = await CoreSites.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        const params: AddonModBBBGetJoinUrlWSParams = {
 | 
			
		||||
            cmid: cmId,
 | 
			
		||||
            groupid: groupId,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Don't use cache.
 | 
			
		||||
        const response = await site.write<AddonModBBBGetJoinUrlWSResponse>(
 | 
			
		||||
            'mod_bigbluebuttonbn_get_join_url',
 | 
			
		||||
            params,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (response.warnings?.length) {
 | 
			
		||||
            throw new CoreWSError(response.warnings[0]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!response.join_url) {
 | 
			
		||||
            // Shouldn't happen, if there are no warning the app should always receive the URL.
 | 
			
		||||
            throw new CoreError(
 | 
			
		||||
                Translate.instant('addon.mod_bigbluebuttonbn.view_error_unable_join_studentview_error_unable_join_student'),
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return response.join_url;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get meeting info for a BBB activity.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id BBB ID.
 | 
			
		||||
     * @param groupId Group ID, 0 means that the function will determine the user group.
 | 
			
		||||
     * @param options Other options.
 | 
			
		||||
     * @return Promise resolved with the list of messages.
 | 
			
		||||
     */
 | 
			
		||||
    async getMeetingInfo(
 | 
			
		||||
        id: number,
 | 
			
		||||
        groupId: number = 0,
 | 
			
		||||
        options: CoreCourseCommonModWSOptions = {},
 | 
			
		||||
    ): Promise<AddonModBBBMeetingInfoWSResponse> {
 | 
			
		||||
        const site = await CoreSites.getSite(options.siteId);
 | 
			
		||||
 | 
			
		||||
        const params: AddonModBBBMeetingInfoWSParams = {
 | 
			
		||||
            bigbluebuttonbnid: id,
 | 
			
		||||
            groupid: groupId,
 | 
			
		||||
        };
 | 
			
		||||
        const preSets: CoreSiteWSPreSets = {
 | 
			
		||||
            cacheKey: this.getMeetingInfoCacheKey(id, groupId),
 | 
			
		||||
            component: AddonModBBBService.COMPONENT,
 | 
			
		||||
            componentId: options.cmId,
 | 
			
		||||
            ...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return await site.read<AddonModBBBMeetingInfoWSResponse>(
 | 
			
		||||
            'mod_bigbluebuttonbn_meeting_info',
 | 
			
		||||
            params,
 | 
			
		||||
            preSets,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get cache key for meeting info WS call.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id BBB ID.
 | 
			
		||||
     * @param groupId Group ID, 0 means that the function will determine the user group.
 | 
			
		||||
     * @return Cache key.
 | 
			
		||||
     */
 | 
			
		||||
    protected getMeetingInfoCacheKey(id: number, groupId: number = 0): string {
 | 
			
		||||
        return this.getMeetingInfoCacheKeyPrefix(id) + groupId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get cache key prefix for meeting info WS call.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id BBB ID.
 | 
			
		||||
     * @return Cache key prefix.
 | 
			
		||||
     */
 | 
			
		||||
    protected getMeetingInfoCacheKeyPrefix(id: number): string {
 | 
			
		||||
        return ROOT_CACHE_KEY + 'meetingInfo:' + id + ':';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Report a BBB as being viewed.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id BBB instance ID.
 | 
			
		||||
     * @param name Name of the BBB.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when the WS call is successful.
 | 
			
		||||
     */
 | 
			
		||||
    async logView(id: number, name?: string, siteId?: string): Promise<void> {
 | 
			
		||||
        const params: AddonModBBBViewBigBlueButtonBNWSParams = {
 | 
			
		||||
            bigbluebuttonbnid: id,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        await CoreCourseLogHelper.logSingle(
 | 
			
		||||
            'mod_bigbluebuttonbn_view_bigbluebuttonbn',
 | 
			
		||||
            params,
 | 
			
		||||
            AddonModBBBService.COMPONENT,
 | 
			
		||||
            id,
 | 
			
		||||
            name,
 | 
			
		||||
            'bigbluebuttonbn',
 | 
			
		||||
            {},
 | 
			
		||||
            siteId,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidate BBBs.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    async invalidateBBBs(courseId: number, siteId?: string): Promise<void> {
 | 
			
		||||
        const site = await CoreSites.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        await site.invalidateWsCacheForKey(this.getBBBsCacheKey(courseId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidate meeting info for a certain group.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id BBB ID.
 | 
			
		||||
     * @param groupId Group ID, 0 means that the function will determine the user group.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    async invalidateMeetingInfo(id: number, groupId: number = 0, siteId?: string): Promise<void> {
 | 
			
		||||
        const site = await CoreSites.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        await site.invalidateWsCacheForKey(this.getMeetingInfoCacheKey(id, groupId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidate meeting info for all groups.
 | 
			
		||||
     *
 | 
			
		||||
     * @param id BBB ID.
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    async invalidateAllGroupsMeetingInfo(id: number, siteId?: string): Promise<void> {
 | 
			
		||||
        const site = await CoreSites.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        await site.invalidateWsCacheForKeyStartingWith(this.getMeetingInfoCacheKeyPrefix(id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns whether or not the BBB plugin is enabled for a certain site.
 | 
			
		||||
     *
 | 
			
		||||
     * @param siteId Site ID. If not defined, current site.
 | 
			
		||||
     * @return Promise resolved with true if enabled, resolved with false or rejected otherwise.
 | 
			
		||||
     * @since 4.0, but the WebServices were backported to the plugin so it can be supported in older versions.
 | 
			
		||||
     */
 | 
			
		||||
    async isPluginEnabled(siteId?: string): Promise<boolean> {
 | 
			
		||||
        const site = await CoreSites.getSite(siteId);
 | 
			
		||||
 | 
			
		||||
        return site.wsAvailable('mod_bigbluebuttonbn_meeting_info');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const AddonModBBB = makeSingleton(AddonModBBBService);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of mod_bigbluebuttonbn_get_bigbluebuttonbns_by_courses WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBBBGetBigBlueButtonBNsByCoursesWSParams = {
 | 
			
		||||
    courseids?: number[]; // Array of course ids.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Data returned by mod_bigbluebuttonbn_get_bigbluebuttonbns_by_courses WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBBBGetBigBlueButtonBNsByCoursesWSResponse = {
 | 
			
		||||
    bigbluebuttonbns: AddonModBBBData[];
 | 
			
		||||
    warnings?: CoreWSExternalWarning[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * BBB data returned by mod_bigbluebuttonbn_get_bigbluebuttonbns_by_courses.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBBBData = {
 | 
			
		||||
    id: number; // Module id.
 | 
			
		||||
    coursemodule: number; // Course module id.
 | 
			
		||||
    course: number; // Course id.
 | 
			
		||||
    name: string; // Name.
 | 
			
		||||
    intro: string; // Description.
 | 
			
		||||
    meetingid: string; // Meeting id.
 | 
			
		||||
    introformat?: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
 | 
			
		||||
    introfiles: CoreWSExternalFile[];
 | 
			
		||||
    timemodified: number; // Last time the instance was modified.
 | 
			
		||||
    section: number; // Course section id.
 | 
			
		||||
    visible: number; // Module visibility.
 | 
			
		||||
    groupmode: number; // Group mode.
 | 
			
		||||
    groupingid: number; // Grouping id.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of mod_bigbluebuttonbn_meeting_info WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBBBMeetingInfoWSParams = {
 | 
			
		||||
    bigbluebuttonbnid: number; // Bigbluebuttonbn instance id.
 | 
			
		||||
    groupid?: number; // Bigbluebuttonbn group id.
 | 
			
		||||
    updatecache?: boolean; // Update cache ?.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Data returned by mod_bigbluebuttonbn_meeting_info WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBBBMeetingInfoWSResponse = {
 | 
			
		||||
    cmid: number; // CM id.
 | 
			
		||||
    userlimit: number; // User limit.
 | 
			
		||||
    bigbluebuttonbnid: string; // Bigbluebuttonbn instance id.
 | 
			
		||||
    meetingid: string; // Meeting id.
 | 
			
		||||
    openingtime?: number; // Opening time.
 | 
			
		||||
    closingtime?: number; // Closing time.
 | 
			
		||||
    statusrunning?: boolean; // Status running.
 | 
			
		||||
    statusclosed?: boolean; // Status closed.
 | 
			
		||||
    statusopen?: boolean; // Status open.
 | 
			
		||||
    statusmessage?: string; // Status message.
 | 
			
		||||
    startedat?: number; // Started at.
 | 
			
		||||
    moderatorcount?: number; // Moderator count.
 | 
			
		||||
    participantcount?: number; // Participant count.
 | 
			
		||||
    moderatorplural?: boolean; // Several moderators ?.
 | 
			
		||||
    participantplural?: boolean; // Several participants ?.
 | 
			
		||||
    canjoin: boolean; // Can join.
 | 
			
		||||
    ismoderator: boolean; // Is moderator.
 | 
			
		||||
    presentations: {
 | 
			
		||||
        url: string; // Presentation URL.
 | 
			
		||||
        iconname: string; // Icon name.
 | 
			
		||||
        icondesc: string; // Icon text.
 | 
			
		||||
        name: string; // Presentation name.
 | 
			
		||||
    }[];
 | 
			
		||||
    joinurl: string; // Join URL.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of mod_bigbluebuttonbn_get_join_url WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBBBGetJoinUrlWSParams = {
 | 
			
		||||
    cmid: number; // Course module id.
 | 
			
		||||
    groupid?: number; // Bigbluebuttonbn group id.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Data returned by mod_bigbluebuttonbn_get_join_url WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBBBGetJoinUrlWSResponse = {
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/naming-convention
 | 
			
		||||
    join_url?: string; // Can join session.
 | 
			
		||||
    warnings?: CoreWSExternalWarning[];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of mod_bigbluebuttonbn_view_bigbluebuttonbn WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBBBViewBigBlueButtonBNWSParams = {
 | 
			
		||||
    bigbluebuttonbnid: number; // Bigbluebuttonbn instance id.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Params of mod_bigbluebuttonbn_end_meeting WS.
 | 
			
		||||
 */
 | 
			
		||||
export type AddonModBBBEndMeetingWSParams = {
 | 
			
		||||
    bigbluebuttonbnid: number; // Bigbluebuttonbn instance id.
 | 
			
		||||
    groupid?: number; // Bigbluebuttonbn group id.
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,33 @@
 | 
			
		||||
// (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 { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/classes/module-index-handler';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to treat links to Big Blue Button activity.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonModBBBIndexLinkHandlerService extends CoreContentLinksModuleIndexHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonModBBBIndexLinkHandlerService';
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super('AddonModBBB', 'bigbluebuttonbn', 'bn');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const AddonModBBBIndexLinkHandler = makeSingleton(AddonModBBBIndexLinkHandlerService);
 | 
			
		||||
@ -0,0 +1,33 @@
 | 
			
		||||
// (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 { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to treat links to Big Blue Button list page.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonModBBBListLinkHandlerService extends CoreContentLinksModuleListHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonModBBBListLinkHandler';
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super('AddonModBBB', 'bigbluebuttonbn');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const AddonModBBBListLinkHandler = makeSingleton(AddonModBBBListLinkHandlerService);
 | 
			
		||||
							
								
								
									
										104
									
								
								src/addons/mod/bigbluebuttonbn/services/handlers/module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/addons/mod/bigbluebuttonbn/services/handlers/module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,104 @@
 | 
			
		||||
// (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 { Injectable, Type } from '@angular/core';
 | 
			
		||||
import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler';
 | 
			
		||||
import { CoreCourseModule } from '@features/course/services/course-helper';
 | 
			
		||||
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate';
 | 
			
		||||
import { CoreSitePluginsModuleHandler } from '@features/siteplugins/classes/handlers/module-handler';
 | 
			
		||||
import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { AddonModBBBIndexComponent } from '../../components/index';
 | 
			
		||||
import { AddonModBBB } from '../bigbluebuttonbn';
 | 
			
		||||
 | 
			
		||||
export const ADDON_MOD_BBB_MAIN_MENU_PAGE_NAME = 'mod_bigbluebuttonbn';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support Big Blue Button activities.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonModBBBModuleHandlerService extends CoreModuleHandlerBase implements CoreCourseModuleHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonModBBB';
 | 
			
		||||
    modName = 'bigbluebuttonbn';
 | 
			
		||||
    protected pageName = ADDON_MOD_BBB_MAIN_MENU_PAGE_NAME;
 | 
			
		||||
    protected sitePluginHandler?: CoreSitePluginsModuleHandler;
 | 
			
		||||
 | 
			
		||||
    supportedFeatures = {
 | 
			
		||||
        [CoreConstants.FEATURE_GROUPS]: true,
 | 
			
		||||
        [CoreConstants.FEATURE_GROUPINGS]: true,
 | 
			
		||||
        [CoreConstants.FEATURE_MOD_INTRO]: true,
 | 
			
		||||
        [CoreConstants.FEATURE_COMPLETION_TRACKS_VIEWS]: true,
 | 
			
		||||
        [CoreConstants.FEATURE_GRADE_HAS_GRADE]: false,
 | 
			
		||||
        [CoreConstants.FEATURE_GRADE_OUTCOMES]: true,
 | 
			
		||||
        [CoreConstants.FEATURE_BACKUP_MOODLE2]: true,
 | 
			
		||||
        [CoreConstants.FEATURE_SHOW_DESCRIPTION]: true,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabled(): Promise<boolean> {
 | 
			
		||||
        const enabled = await AddonModBBB.isPluginEnabled();
 | 
			
		||||
 | 
			
		||||
        if (enabled) {
 | 
			
		||||
            delete this.sitePluginHandler;
 | 
			
		||||
            this.name = 'AddonModBBB';
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Native support not available in this site. Check if it's supported by site plugin.
 | 
			
		||||
        this.sitePluginHandler = CoreSitePlugins.getModuleHandlerInstance(this.modName);
 | 
			
		||||
        // Change the handler name to be able to retrieve the plugin data in component.
 | 
			
		||||
        this.name = this.sitePluginHandler?.name || this.name;
 | 
			
		||||
 | 
			
		||||
        return !!this.sitePluginHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async getData(
 | 
			
		||||
        module: CoreCourseModule,
 | 
			
		||||
        courseId: number,
 | 
			
		||||
        sectionId?: number,
 | 
			
		||||
        forCoursePage?: boolean,
 | 
			
		||||
    ): Promise<CoreCourseModuleHandlerData> {
 | 
			
		||||
        if (this.sitePluginHandler) {
 | 
			
		||||
            return this.sitePluginHandler.getData(module, courseId, sectionId, forCoursePage);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const data = await super.getData(module, courseId, sectionId, forCoursePage);
 | 
			
		||||
 | 
			
		||||
        data.showDownloadButton = false;
 | 
			
		||||
 | 
			
		||||
        return data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async getMainComponent(): Promise<Type<unknown>> {
 | 
			
		||||
        if (this.sitePluginHandler) {
 | 
			
		||||
            return this.sitePluginHandler.getMainComponent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return AddonModBBBIndexComponent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const AddonModBBBModuleHandler = makeSingleton(AddonModBBBModuleHandlerService);
 | 
			
		||||
@ -15,6 +15,7 @@
 | 
			
		||||
import { NgModule } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { AddonModAssignModule } from './assign/assign.module';
 | 
			
		||||
import { AddonModBBBModule } from './bigbluebuttonbn/bigbluebuttonbn.module';
 | 
			
		||||
import { AddonModBookModule } from './book/book.module';
 | 
			
		||||
import { AddonModChatModule } from './chat/chat.module';
 | 
			
		||||
import { AddonModChoiceModule } from './choice/choice.module';
 | 
			
		||||
@ -40,6 +41,7 @@ import { AddonModWorkshopModule } from './workshop/workshop.module';
 | 
			
		||||
@NgModule({
 | 
			
		||||
    imports: [
 | 
			
		||||
        AddonModAssignModule,
 | 
			
		||||
        AddonModBBBModule,
 | 
			
		||||
        AddonModBookModule,
 | 
			
		||||
        AddonModChatModule,
 | 
			
		||||
        AddonModChoiceModule,
 | 
			
		||||
 | 
			
		||||
@ -82,6 +82,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity
 | 
			
		||||
        separateGroups: false,
 | 
			
		||||
        visibleGroups: false,
 | 
			
		||||
        defaultGroupId: 0,
 | 
			
		||||
        canAccessAllGroups: false,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    canSubmit = false;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										55
									
								
								src/assets/img/mod/bigbluebuttonbn.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/assets/img/mod/bigbluebuttonbn.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 | 
			
		||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 | 
			
		||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
			
		||||
	 width="24px" height="24px" viewBox="0 0 30 30" enable-background="new 0 0 30 30" xml:space="preserve" preserveAspectRatio="xMinYMid meet">
 | 
			
		||||
		<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-58.9473" y1="84.1865" x2="58.9479" y2="-84.1852">
 | 
			
		||||
			<stop  offset="0" style="stop-color:#283274"/>
 | 
			
		||||
			<stop  offset="0.7088" style="stop-color:#293275"/>
 | 
			
		||||
			<stop  offset="0.967" style="stop-color:#273F87"/>
 | 
			
		||||
		</linearGradient>
 | 
			
		||||
<symbol  id="New_Symbol" viewBox="-107.423 -107.423 214.847 214.846">
 | 
			
		||||
	<g>
 | 
			
		||||
		<path fill="url(#SVGID_1_)" stroke="#5D6AA4" stroke-width="9.3191" d="M102.765,0c0-56.755-46.009-102.764-102.765-102.764
 | 
			
		||||
			c-56.754,0-102.764,46.009-102.764,102.764S-56.754,102.764,0,102.764C56.756,102.764,102.765,56.755,102.765,0z"/>
 | 
			
		||||
		
 | 
			
		||||
			<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="-75.0186" y1="112.8037" x2="-15.8528" y2="28.3063" gradientTransform="matrix(1 0 0 1 18.4946 -31.9512)">
 | 
			
		||||
			<stop  offset="0" style="stop-color:#BEC7E5"/>
 | 
			
		||||
			<stop  offset="0.0956" style="stop-color:#B5BEDE"/>
 | 
			
		||||
			<stop  offset="0.2524" style="stop-color:#9CA5CC"/>
 | 
			
		||||
			<stop  offset="0.4508" style="stop-color:#747DAE"/>
 | 
			
		||||
			<stop  offset="0.6809" style="stop-color:#3D4684"/>
 | 
			
		||||
			<stop  offset="0.7582" style="stop-color:#293275"/>
 | 
			
		||||
		</linearGradient>
 | 
			
		||||
		<path fill="url(#SVGID_2_)" d="M0.282,98.502C26.323,98.31,54.293,87.893,74.49,63.84C73.631,43.207,36.703,22.057,5.886-1.229
 | 
			
		||||
			c-25.857-19.538-65.427-37.86-92.487-45.059c-25.73,49.263-7.016,96.619,25.25,123.238C-46.256,90.16-23.508,98.679,0.282,98.502z
 | 
			
		||||
			"/>
 | 
			
		||||
	</g>
 | 
			
		||||
	<g>
 | 
			
		||||
		<g>
 | 
			
		||||
			<path d="M55.602-25.561c0-8.678-3.055-16.072-9.16-22.179c-6.11-6.109-13.501-9.16-22.179-9.16h-37.367
 | 
			
		||||
				c-8.679,0-16.073,3.051-22.179,9.16c-6.11,6.106-9.162,13.501-9.162,22.179v93.779c6.656,0,12.336-3.254,17.046-9.764
 | 
			
		||||
				c4.708-6.509,7.062-14.344,7.062-23.505v-60.511c0-4.821,2.411-7.231,7.232-7.231h37.367c4.821,0,7.231,2.41,7.231,7.231V3.128
 | 
			
		||||
				c0,4.66-2.41,7.07-7.231,7.232H17.03c-9.323,0.324-17.2,2.757-23.626,7.304c-6.43,4.543-9.643,10.145-9.643,16.805h40.501
 | 
			
		||||
				c8.678,0,16.068-3.056,22.179-9.161c6.105-6.11,9.16-13.5,9.16-22.18V-25.561z"/>
 | 
			
		||||
		</g>
 | 
			
		||||
	</g>
 | 
			
		||||
	<g opacity="0.46">
 | 
			
		||||
		<g>
 | 
			
		||||
			<path fill="#FFFFFF" d="M55.602-25.561c0-8.678-3.055-16.072-9.16-22.179c-6.11-6.109-13.501-9.16-22.179-9.16h-37.367
 | 
			
		||||
				c-8.679,0-16.073,3.051-22.179,9.16c-6.11,6.106-9.162,13.501-9.162,22.179v93.779c6.656,0,12.336-3.254,17.046-9.764
 | 
			
		||||
				c4.708-6.509,7.062-14.344,7.062-23.505v-60.511c0-4.821,2.411-7.231,7.232-7.231h37.367c4.821,0,7.231,2.41,7.231,7.231V3.128
 | 
			
		||||
				c0,4.66-2.41,7.07-7.231,7.232H17.03c-9.323,0.324-17.2,2.757-23.626,7.304c-6.43,4.543-9.643,10.145-9.643,16.805h40.501
 | 
			
		||||
				c8.678,0,16.068-3.056,22.179-9.161c6.105-6.11,9.16-13.5,9.16-22.18V-25.561z"/>
 | 
			
		||||
		</g>
 | 
			
		||||
	</g>
 | 
			
		||||
	<g>
 | 
			
		||||
		<path fill="#FFFFFF" d="M53.829-26.788c0-8.678-3.055-16.072-9.16-22.179c-6.11-6.109-13.501-9.16-22.18-9.16h-37.367
 | 
			
		||||
			c-8.679,0-16.073,3.051-22.179,9.16c-6.109,6.106-9.16,13.501-9.16,22.179v93.779c6.655,0,12.336-3.255,17.045-9.764
 | 
			
		||||
			c4.708-6.509,7.062-14.345,7.062-23.505v-60.511c0-4.821,2.41-7.231,7.232-7.231h37.367c4.821,0,7.232,2.41,7.232,7.231V1.901
 | 
			
		||||
			c0,4.66-2.411,7.07-7.232,7.232h-7.232C5.935,9.457-1.942,11.89-8.368,16.438c-6.43,4.542-9.644,10.144-9.644,16.803h40.501
 | 
			
		||||
			c8.679,0,16.069-3.055,22.18-9.16c6.105-6.109,9.16-13.5,9.16-22.179V-26.788z"/>
 | 
			
		||||
	</g>
 | 
			
		||||
</symbol>
 | 
			
		||||
<use xlink:href="#New_Symbol"  width="214.847" height="214.846" x="-107.423" y="-107.423" transform="matrix(0.1376 0 0 -0.1376 14.9995 15)" overflow="visible"/>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 3.7 KiB  | 
@ -87,7 +87,7 @@ export class CoreCourseProvider {
 | 
			
		||||
    readonly CORE_MODULES = [
 | 
			
		||||
        'assign', 'assignment', 'book', 'chat', 'choice', 'data', 'database', 'date', 'external-tool',
 | 
			
		||||
        'feedback', 'file', 'folder', 'forum', 'glossary', 'ims', 'imscp', 'label', 'lesson', 'lti', 'page', 'quiz',
 | 
			
		||||
        'resource', 'scorm', 'survey', 'url', 'wiki', 'workshop', 'h5pactivity',
 | 
			
		||||
        'resource', 'scorm', 'survey', 'url', 'wiki', 'workshop', 'h5pactivity', 'bigbluebuttonbn',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    protected logger: CoreLogger;
 | 
			
		||||
 | 
			
		||||
@ -161,7 +161,11 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
 | 
			
		||||
     * Expand the description.
 | 
			
		||||
     */
 | 
			
		||||
    expandDescription(): void {
 | 
			
		||||
        CoreTextUtils.viewText(Translate.instant('core.description'), this.description!, {
 | 
			
		||||
        if (!this.description) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CoreTextUtils.viewText(Translate.instant('core.description'), this.description, {
 | 
			
		||||
            component: this.component,
 | 
			
		||||
            componentId: this.module.id,
 | 
			
		||||
            filter: true,
 | 
			
		||||
 | 
			
		||||
@ -205,7 +205,7 @@ export class CoreSitePluginsHelperProvider {
 | 
			
		||||
            undefined,
 | 
			
		||||
            undefined,
 | 
			
		||||
            undefined,
 | 
			
		||||
            handlerSchema.styles!.version,
 | 
			
		||||
            handlerSchema.styles?.version,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // File is downloaded, get the contents.
 | 
			
		||||
@ -378,8 +378,9 @@ export class CoreSitePluginsHelperProvider {
 | 
			
		||||
 | 
			
		||||
        if (plugin.parsedHandlers) {
 | 
			
		||||
            // Register all the handlers.
 | 
			
		||||
            await CoreUtils.allPromises(Object.keys(plugin.parsedHandlers).map(async (name) => {
 | 
			
		||||
                await this.registerHandler(plugin, name, plugin.parsedHandlers![name]);
 | 
			
		||||
            const parsedHandlers = plugin.parsedHandlers;
 | 
			
		||||
            await CoreUtils.allPromises(Object.keys(parsedHandlers).map(async (name) => {
 | 
			
		||||
                await this.registerHandler(plugin, name, parsedHandlers[name]);
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -891,6 +892,7 @@ export class CoreSitePluginsHelperProvider {
 | 
			
		||||
 | 
			
		||||
        const moduleHandler = new CoreSitePluginsModuleHandler(uniqueName, modName, plugin, handlerSchema, initResult);
 | 
			
		||||
        CoreCourseModuleDelegate.registerHandler(moduleHandler);
 | 
			
		||||
        CoreSitePlugins.setModuleHandlerInstance(modName, moduleHandler);
 | 
			
		||||
 | 
			
		||||
        if (handlerSchema.offlinefunctions && Object.keys(handlerSchema.offlinefunctions).length) {
 | 
			
		||||
            // Register the prefetch handler.
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@ import { CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreLogger } from '@singletons/logger';
 | 
			
		||||
import { CoreSitePluginsModuleHandler } from '../classes/handlers/module-handler';
 | 
			
		||||
 | 
			
		||||
const ROOT_CACHE_KEY = 'CoreSitePlugins:';
 | 
			
		||||
 | 
			
		||||
@ -44,6 +45,8 @@ export class CoreSitePluginsProvider {
 | 
			
		||||
    protected sitePlugins: {[name: string]: CoreSitePluginsHandler} = {}; // Site plugins registered.
 | 
			
		||||
    protected sitePluginPromises: {[name: string]: Promise<void>} = {}; // Promises of loading plugins.
 | 
			
		||||
    protected fetchPluginsDeferred: PromiseDefer<void>;
 | 
			
		||||
    protected moduleHandlerInstances: Record<string, CoreSitePluginsModuleHandler> = {};
 | 
			
		||||
 | 
			
		||||
    hasSitePluginsLoaded = false;
 | 
			
		||||
    sitePluginsFinishedLoading = false;
 | 
			
		||||
 | 
			
		||||
@ -262,7 +265,7 @@ export class CoreSitePluginsProvider {
 | 
			
		||||
        switch (paramName) {
 | 
			
		||||
            case 'courseids':
 | 
			
		||||
                // The WS needs the list of course IDs. Create the list.
 | 
			
		||||
                return [courseId!];
 | 
			
		||||
                return [courseId || 0];
 | 
			
		||||
 | 
			
		||||
            case component + 'id':
 | 
			
		||||
                // The WS needs the instance id.
 | 
			
		||||
@ -540,10 +543,13 @@ export class CoreSitePluginsProvider {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const siteInstance = site;
 | 
			
		||||
        const offlineFunctions = handlerSchema.offlinefunctions;
 | 
			
		||||
 | 
			
		||||
        await Promise.all(Object.keys(handlerSchema.offlinefunctions).map(async(method) => {
 | 
			
		||||
            if (site!.wsAvailable(method)) {
 | 
			
		||||
            if (siteInstance.wsAvailable(method)) {
 | 
			
		||||
                // The method is a WS.
 | 
			
		||||
                const paramsList = handlerSchema.offlinefunctions![method];
 | 
			
		||||
                const paramsList = offlineFunctions[method];
 | 
			
		||||
                const cacheKey = this.getCallWSCacheKey(method, args);
 | 
			
		||||
                let params: Record<string, unknown> = {};
 | 
			
		||||
 | 
			
		||||
@ -584,7 +590,7 @@ export class CoreSitePluginsProvider {
 | 
			
		||||
            // Prefetch the files in the content.
 | 
			
		||||
            if (result.files.length) {
 | 
			
		||||
                await CoreFilepool.downloadOrPrefetchFiles(
 | 
			
		||||
                    site!.getId(),
 | 
			
		||||
                    siteInstance.getId(),
 | 
			
		||||
                    result.files,
 | 
			
		||||
                    !!prefetch,
 | 
			
		||||
                    false,
 | 
			
		||||
@ -657,6 +663,26 @@ export class CoreSitePluginsProvider {
 | 
			
		||||
        return this.fetchPluginsDeferred.promise;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a module hander instance, if present.
 | 
			
		||||
     *
 | 
			
		||||
     * @param modName Mod name without "mod_".
 | 
			
		||||
     * @return Handler instance, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getModuleHandlerInstance(modName: string): CoreSitePluginsModuleHandler | undefined {
 | 
			
		||||
        return this.moduleHandlerInstances[modName];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set a module hander instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param modName Mod name.
 | 
			
		||||
     * @param handler Handler instance.
 | 
			
		||||
     */
 | 
			
		||||
    setModuleHandlerInstance(modName: string, handler: CoreSitePluginsModuleHandler): void {
 | 
			
		||||
        this.moduleHandlerInstances[modName] = handler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const CoreSitePlugins = makeSingleton(CoreSitePluginsProvider);
 | 
			
		||||
 | 
			
		||||
@ -151,6 +151,7 @@ export class CoreGroupsProvider {
 | 
			
		||||
        const groupInfo: CoreGroupInfo = {
 | 
			
		||||
            groups: [],
 | 
			
		||||
            defaultGroupId: 0,
 | 
			
		||||
            canAccessAllGroups: false,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        const groupMode = await this.getActivityGroupMode(cmId, siteId, ignoreCache);
 | 
			
		||||
@ -161,6 +162,8 @@ export class CoreGroupsProvider {
 | 
			
		||||
        let result: CoreGroupGetActivityAllowedGroupsWSResponse;
 | 
			
		||||
        if (groupInfo.separateGroups || groupInfo.visibleGroups) {
 | 
			
		||||
            result = await this.getActivityAllowedGroups(cmId, userId, siteId, ignoreCache);
 | 
			
		||||
 | 
			
		||||
            groupInfo.canAccessAllGroups = !!result.canaccessallgroups;
 | 
			
		||||
        } else {
 | 
			
		||||
            result = {
 | 
			
		||||
                groups: [],
 | 
			
		||||
@ -471,6 +474,11 @@ export type CoreGroupInfo = {
 | 
			
		||||
     * The group ID to use by default. If all participants is visible, 0 will be used. First group ID otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    defaultGroupId: number;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether the user has the capability to access all groups in the context.
 | 
			
		||||
     */
 | 
			
		||||
    canAccessAllGroups: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user