forked from EVOgeek/Vmeda.Online
		
	MOBILE-1633 core: Rating components and providers
This commit is contained in:
		
							parent
							
								
									4c602c62bf
								
							
						
					
					
						commit
						beaab9d2f6
					
				@ -1590,6 +1590,15 @@
 | 
				
			|||||||
  "core.question.questionno": "question",
 | 
					  "core.question.questionno": "question",
 | 
				
			||||||
  "core.question.requiresgrading": "question",
 | 
					  "core.question.requiresgrading": "question",
 | 
				
			||||||
  "core.quotausage": "moodle",
 | 
					  "core.quotausage": "moodle",
 | 
				
			||||||
 | 
					  "core.rating.aggregateavg": "moodle",
 | 
				
			||||||
 | 
					  "core.rating.aggregatecount": "moodle",
 | 
				
			||||||
 | 
					  "core.rating.aggregatemax": "moodle",
 | 
				
			||||||
 | 
					  "core.rating.aggregatemin": "moodle",
 | 
				
			||||||
 | 
					  "core.rating.aggregatesum": "moodle",
 | 
				
			||||||
 | 
					  "core.rating.norating": "local_moodlemobileapp",
 | 
				
			||||||
 | 
					  "core.rating.noratings": "moodle",
 | 
				
			||||||
 | 
					  "core.rating.rating": "moodle",
 | 
				
			||||||
 | 
					  "core.rating.ratings": "moodle",
 | 
				
			||||||
  "core.redirectingtosite": "local_moodlemobileapp",
 | 
					  "core.redirectingtosite": "local_moodlemobileapp",
 | 
				
			||||||
  "core.refresh": "moodle",
 | 
					  "core.refresh": "moodle",
 | 
				
			||||||
  "core.remove": "moodle",
 | 
					  "core.remove": "moodle",
 | 
				
			||||||
 | 
				
			|||||||
@ -78,6 +78,7 @@ import { CoreCompileModule } from '@core/compile/compile.module';
 | 
				
			|||||||
import { CoreQuestionModule } from '@core/question/question.module';
 | 
					import { CoreQuestionModule } from '@core/question/question.module';
 | 
				
			||||||
import { CoreCommentsModule } from '@core/comments/comments.module';
 | 
					import { CoreCommentsModule } from '@core/comments/comments.module';
 | 
				
			||||||
import { CoreBlockModule } from '@core/block/block.module';
 | 
					import { CoreBlockModule } from '@core/block/block.module';
 | 
				
			||||||
 | 
					import { CoreRatingModule } from '@core/rating/rating.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Addon modules.
 | 
					// Addon modules.
 | 
				
			||||||
import { AddonBadgesModule } from '@addon/badges/badges.module';
 | 
					import { AddonBadgesModule } from '@addon/badges/badges.module';
 | 
				
			||||||
@ -198,6 +199,7 @@ export const CORE_PROVIDERS: any[] = [
 | 
				
			|||||||
        CoreQuestionModule,
 | 
					        CoreQuestionModule,
 | 
				
			||||||
        CoreCommentsModule,
 | 
					        CoreCommentsModule,
 | 
				
			||||||
        CoreBlockModule,
 | 
					        CoreBlockModule,
 | 
				
			||||||
 | 
					        CoreRatingModule,
 | 
				
			||||||
        AddonBadgesModule,
 | 
					        AddonBadgesModule,
 | 
				
			||||||
        AddonBlogModule,
 | 
					        AddonBlogModule,
 | 
				
			||||||
        AddonCalendarModule,
 | 
					        AddonCalendarModule,
 | 
				
			||||||
 | 
				
			|||||||
@ -1590,6 +1590,15 @@
 | 
				
			|||||||
    "core.question.questionno": "Question {{$a}}",
 | 
					    "core.question.questionno": "Question {{$a}}",
 | 
				
			||||||
    "core.question.requiresgrading": "Requires grading",
 | 
					    "core.question.requiresgrading": "Requires grading",
 | 
				
			||||||
    "core.quotausage": "You have currently used {{$a.used}} of your {{$a.total}} limit.",
 | 
					    "core.quotausage": "You have currently used {{$a.used}} of your {{$a.total}} limit.",
 | 
				
			||||||
 | 
					    "core.rating.aggregateavg": "Average of ratings",
 | 
				
			||||||
 | 
					    "core.rating.aggregatecount": "Count of ratings",
 | 
				
			||||||
 | 
					    "core.rating.aggregatemax": "Maximum rating",
 | 
				
			||||||
 | 
					    "core.rating.aggregatemin": "Minimum rating",
 | 
				
			||||||
 | 
					    "core.rating.aggregatesum": "Sum of ratings",
 | 
				
			||||||
 | 
					    "core.rating.norating": "No rating",
 | 
				
			||||||
 | 
					    "core.rating.noratings": "No ratings submitted",
 | 
				
			||||||
 | 
					    "core.rating.rating": "Rating",
 | 
				
			||||||
 | 
					    "core.rating.ratings": "Ratings",
 | 
				
			||||||
    "core.redirectingtosite": "You will be redirected to the site.",
 | 
					    "core.redirectingtosite": "You will be redirected to the site.",
 | 
				
			||||||
    "core.refresh": "Refresh",
 | 
					    "core.refresh": "Refresh",
 | 
				
			||||||
    "core.remove": "Remove",
 | 
					    "core.remove": "Remove",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										112
									
								
								src/core/rating/components/aggregate/aggregate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/core/rating/components/aggregate/aggregate.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Martin Dougiamas
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Component, Input, OnChanges, SimpleChange } from '@angular/core';
 | 
				
			||||||
 | 
					import { ModalController } from 'ionic-angular';
 | 
				
			||||||
 | 
					import { CoreEventsProvider } from '@providers/events';
 | 
				
			||||||
 | 
					import { CoreRatingProvider, CoreRatingInfo, CoreRatingInfoItem } from '@core/rating/providers/rating';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Component that displays the aggregation of a rating item.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					    selector: 'core-rating-aggregate',
 | 
				
			||||||
 | 
					    templateUrl: 'core-rating-aggregate.html'
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class CoreRatingAggregateComponent implements OnChanges {
 | 
				
			||||||
 | 
					    @Input() ratingInfo: CoreRatingInfo;
 | 
				
			||||||
 | 
					    @Input() contextLevel: string;
 | 
				
			||||||
 | 
					    @Input() instanceId: number;
 | 
				
			||||||
 | 
					    @Input() itemId: number;
 | 
				
			||||||
 | 
					    @Input() aggregateMethod: number;
 | 
				
			||||||
 | 
					    @Input() scaleId: number;
 | 
				
			||||||
 | 
					    @Input() courseId?: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected labelKey: string;
 | 
				
			||||||
 | 
					    protected showCount: boolean;
 | 
				
			||||||
 | 
					    protected item: CoreRatingInfoItem;
 | 
				
			||||||
 | 
					    protected aggregateObserver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(private eventsProvider: CoreEventsProvider, private modalCtrl: ModalController) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Detect changes on input properties.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ngOnChanges(changes: {[name: string]: SimpleChange}): void {
 | 
				
			||||||
 | 
					        this.aggregateObserver && this.aggregateObserver.off();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.item = (this.ratingInfo.ratings || []).find((rating) => rating.itemid == this.itemId);
 | 
				
			||||||
 | 
					        if (!this.item) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (this.aggregateMethod == CoreRatingProvider.AGGREGATE_AVERAGE) {
 | 
				
			||||||
 | 
					            this.labelKey = 'core.rating.aggregateavg';
 | 
				
			||||||
 | 
					        } else if (this.aggregateMethod == CoreRatingProvider.AGGREGATE_COUNT) {
 | 
				
			||||||
 | 
					            this.labelKey = 'core.rating.aggregatecount';
 | 
				
			||||||
 | 
					        } else if (this.aggregateMethod == CoreRatingProvider.AGGREGATE_MAXIMUM) {
 | 
				
			||||||
 | 
					            this.labelKey = 'core.rating.aggregatemax';
 | 
				
			||||||
 | 
					        } else if (this.aggregateMethod == CoreRatingProvider.AGGREGATE_MINIMUM) {
 | 
				
			||||||
 | 
					            this.labelKey = 'core.rating.aggregatemin';
 | 
				
			||||||
 | 
					        } else if (this.aggregateMethod == CoreRatingProvider.AGGREGATE_SUM) {
 | 
				
			||||||
 | 
					            this.labelKey = 'core.rating.aggregatesum';
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            this.labelKey = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.showCount = (this.aggregateMethod != CoreRatingProvider.AGGREGATE_COUNT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Update aggrgate when the user adds or edits a rating.
 | 
				
			||||||
 | 
					        this.aggregateObserver = this.eventsProvider.on(CoreRatingProvider.AGGREGATE_CHANGED_EVENT, (data) => {
 | 
				
			||||||
 | 
					            if (data.contextLevel == this.contextLevel &&
 | 
				
			||||||
 | 
					                    data.instanceId == this.instanceId &&
 | 
				
			||||||
 | 
					                    data.component == this.ratingInfo.component &&
 | 
				
			||||||
 | 
					                    data.ratingArea == this.ratingInfo.ratingarea &&
 | 
				
			||||||
 | 
					                    data.itemId == this.itemId) {
 | 
				
			||||||
 | 
					                this.item.aggregatestr = data.aggregate;
 | 
				
			||||||
 | 
					                this.item.count = data.count;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Open the individual ratings page.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    openRatings(): void {
 | 
				
			||||||
 | 
					        if (!this.ratingInfo.canviewall || !this.item.count) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const params = {
 | 
				
			||||||
 | 
					            contextLevel: this.contextLevel,
 | 
				
			||||||
 | 
					            instanceId: this.instanceId,
 | 
				
			||||||
 | 
					            ratingComponent: this.ratingInfo.component,
 | 
				
			||||||
 | 
					            ratingArea: this.ratingInfo.ratingarea,
 | 
				
			||||||
 | 
					            itemId: this.itemId,
 | 
				
			||||||
 | 
					            scaleId: this.scaleId,
 | 
				
			||||||
 | 
					            courseId: this.courseId
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        const modal = this.modalCtrl.create('CoreRatingRatingsPage', params);
 | 
				
			||||||
 | 
					        modal.present();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Component being destroyed.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ngOnDestroy(): void {
 | 
				
			||||||
 | 
					        this.aggregateObserver && this.aggregateObserver.off();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					<a *ngIf="item && item.canviewaggregate && labelKey" ion-item text-wrap [attr.detail-none]="ratingInfo.canviewall && item.count ? null : true" (click)="openRatings()">
 | 
				
			||||||
 | 
					    {{ labelKey | translate }}{{ 'core.labelsep' | translate }} {{ item.aggregatestr || '-' }}
 | 
				
			||||||
 | 
					    <span *ngIf="showCount && item.count > 0">({{ item.count }})</span>
 | 
				
			||||||
 | 
					</a>
 | 
				
			||||||
							
								
								
									
										39
									
								
								src/core/rating/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/core/rating/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Martin Dougiamas
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { CommonModule } from '@angular/common';
 | 
				
			||||||
 | 
					import { IonicModule } from 'ionic-angular';
 | 
				
			||||||
 | 
					import { TranslateModule } from '@ngx-translate/core';
 | 
				
			||||||
 | 
					import { CoreRatingAggregateComponent } from './aggregate/aggregate';
 | 
				
			||||||
 | 
					import { CoreRatingRateComponent } from './rate/rate';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					    declarations: [
 | 
				
			||||||
 | 
					        CoreRatingAggregateComponent,
 | 
				
			||||||
 | 
					        CoreRatingRateComponent
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    imports: [
 | 
				
			||||||
 | 
					        CommonModule,
 | 
				
			||||||
 | 
					        IonicModule,
 | 
				
			||||||
 | 
					        TranslateModule.forChild()
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    providers: [
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    exports: [
 | 
				
			||||||
 | 
					        CoreRatingAggregateComponent,
 | 
				
			||||||
 | 
					        CoreRatingRateComponent
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class CoreRatingComponentsModule {}
 | 
				
			||||||
							
								
								
									
										6
									
								
								src/core/rating/components/rate/core-rating-rate.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/core/rating/components/rate/core-rating-rate.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					<ion-item text-wrap *ngIf="item && (item.canrate || item.rating != null)">
 | 
				
			||||||
 | 
					    <ion-label>{{ 'core.rating.rating' | translate }}</ion-label>
 | 
				
			||||||
 | 
					    <ion-select text-start [(ngModel)]="rating" (ngModelChange)="userRatingChanged()" interface="action-sheet" [disabled]="!item.canrate">
 | 
				
			||||||
 | 
					        <ion-option *ngFor="let scaleItem of scale.items" [value]="scaleItem.value">{{ scaleItem.name }}</ion-option>
 | 
				
			||||||
 | 
					    </ion-select>
 | 
				
			||||||
 | 
					</ion-item>
 | 
				
			||||||
							
								
								
									
										106
									
								
								src/core/rating/components/rate/rate.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/core/rating/components/rate/rate.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,106 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Martin Dougiamas
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Component, Input, OnChanges, SimpleChange } from '@angular/core';
 | 
				
			||||||
 | 
					import { TranslateService } from '@ngx-translate/core';
 | 
				
			||||||
 | 
					import { CoreRatingProvider, CoreRatingInfo, CoreRatingInfoItem, CoreRatingScale } from '@core/rating/providers/rating';
 | 
				
			||||||
 | 
					import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
				
			||||||
 | 
					import { CoreRatingOfflineProvider } from '@core/rating/providers/offline';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Component that displays the user rating select.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					    selector: 'core-rating-rate',
 | 
				
			||||||
 | 
					    templateUrl: 'core-rating-rate.html'
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class CoreRatingRateComponent implements OnChanges {
 | 
				
			||||||
 | 
					    @Input() ratingInfo: CoreRatingInfo;
 | 
				
			||||||
 | 
					    @Input() contextLevel: string; // Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					    @Input() instanceId: number; // Context instance id.
 | 
				
			||||||
 | 
					    @Input() itemId: number; // Item id. Example: forum post id.
 | 
				
			||||||
 | 
					    @Input() itemSetId: number; // Item set id. Example: forum discussion id.
 | 
				
			||||||
 | 
					    @Input() courseId: number;
 | 
				
			||||||
 | 
					    @Input() aggregateMethod: number;
 | 
				
			||||||
 | 
					    @Input() scaleId: number;
 | 
				
			||||||
 | 
					    @Input() userId: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    item: CoreRatingInfoItem;
 | 
				
			||||||
 | 
					    scale: CoreRatingScale;
 | 
				
			||||||
 | 
					    rating: number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(private domUtils: CoreDomUtilsProvider, private translate: TranslateService,
 | 
				
			||||||
 | 
					            private ratingProvider: CoreRatingProvider, private ratingOffline: CoreRatingOfflineProvider) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Detect changes on input properties.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ngOnChanges(changes: {[name: string]: SimpleChange}): void {
 | 
				
			||||||
 | 
					        this.item = (this.ratingInfo.ratings || []).find((rating) => rating.itemid == this.itemId);
 | 
				
			||||||
 | 
					        this.scale = (this.ratingInfo.scales || []).find((scale) => scale.id == this.scaleId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this.item || !this.scale || !this.ratingProvider.isAddRatingWSAvailable()) {
 | 
				
			||||||
 | 
					            this.item = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Set numeric scale items.
 | 
				
			||||||
 | 
					        if (!this.scale.items) {
 | 
				
			||||||
 | 
					            this.scale.items = [];
 | 
				
			||||||
 | 
					            if (this.scale.isnumeric) {
 | 
				
			||||||
 | 
					                for (let n = 0; n <= this.scale.max; n++) {
 | 
				
			||||||
 | 
					                    this.scale.items.push({name: String(n), value: n});
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add "No rating" item to the scale.
 | 
				
			||||||
 | 
					        if (!this.scale.items[0] || this.scale.items[0].value != CoreRatingProvider.UNSET_RATING) {
 | 
				
			||||||
 | 
					            this.scale.items.unshift({
 | 
				
			||||||
 | 
					                name: this.translate.instant('core.rating.norating'),
 | 
				
			||||||
 | 
					                value: CoreRatingProvider.UNSET_RATING
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.ratingOffline.getRating(this.contextLevel, this.instanceId, this.ratingInfo.component, this.ratingInfo.ratingarea,
 | 
				
			||||||
 | 
					                this.itemId).then((rating) => {
 | 
				
			||||||
 | 
					            this.rating = rating.rating;
 | 
				
			||||||
 | 
					        }).catch(() => {
 | 
				
			||||||
 | 
					            if (this.item && this.item.rating != null) {
 | 
				
			||||||
 | 
					                this.rating = this.item.rating;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.rating = CoreRatingProvider.UNSET_RATING;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Send or save the user rating when changed.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected userRatingChanged(): void {
 | 
				
			||||||
 | 
					        const modal = this.domUtils.showModalLoading('core.sending', true);
 | 
				
			||||||
 | 
					        this.ratingProvider.addRating(this.ratingInfo.component, this.ratingInfo.ratingarea, this.contextLevel, this.instanceId,
 | 
				
			||||||
 | 
					                this.itemId, this.itemSetId, this.courseId, this.scaleId, this.rating, this.userId, this.aggregateMethod)
 | 
				
			||||||
 | 
					                .then((response) => {
 | 
				
			||||||
 | 
					            if (response == null) {
 | 
				
			||||||
 | 
					                this.domUtils.showToast('core.datastoredoffline', true, 3000);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }).catch((error) => {
 | 
				
			||||||
 | 
					            this.domUtils.showErrorModal(error);
 | 
				
			||||||
 | 
					        }).finally(() => {
 | 
				
			||||||
 | 
					            modal.dismiss();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/core/rating/lang/en.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/core/rating/lang/en.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "aggregateavg": "Average of ratings",
 | 
				
			||||||
 | 
					    "aggregatecount": "Count of ratings",
 | 
				
			||||||
 | 
					    "aggregatemax": "Maximum rating",
 | 
				
			||||||
 | 
					    "aggregatemin": "Minimum rating",
 | 
				
			||||||
 | 
					    "aggregatesum": "Sum of ratings",
 | 
				
			||||||
 | 
					    "norating": "No rating",
 | 
				
			||||||
 | 
					    "noratings": "No ratings submitted",
 | 
				
			||||||
 | 
					    "rating": "Rating",
 | 
				
			||||||
 | 
					    "ratings": "Ratings"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/core/rating/pages/ratings/ratings.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/core/rating/pages/ratings/ratings.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					<ion-header>
 | 
				
			||||||
 | 
					    <ion-navbar core-back-button>
 | 
				
			||||||
 | 
					        <ion-title>{{ 'core.rating.ratings' | translate }}</ion-title>
 | 
				
			||||||
 | 
					        <ion-buttons end>
 | 
				
			||||||
 | 
					            <button ion-button icon-only (click)="closeModal()" [attr.aria-label]="'core.close' | translate">
 | 
				
			||||||
 | 
					                <ion-icon name="close"></ion-icon>
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					        </ion-buttons>
 | 
				
			||||||
 | 
					    </ion-navbar>
 | 
				
			||||||
 | 
					</ion-header>
 | 
				
			||||||
 | 
					<ion-content>
 | 
				
			||||||
 | 
					    <ion-refresher [enabled]="loaded" (ionRefresh)="refreshRatings($event)">
 | 
				
			||||||
 | 
					        <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content>
 | 
				
			||||||
 | 
					    </ion-refresher>
 | 
				
			||||||
 | 
					    <core-loading [hideUntil]="loaded">
 | 
				
			||||||
 | 
					        <ion-list *ngIf="ratings.length > 0">
 | 
				
			||||||
 | 
					            <ion-item text-wrap *ngFor="let rating of ratings">
 | 
				
			||||||
 | 
					                <ion-avatar core-user-avatar [user]="rating" [courseId]="courseId" item-start></ion-avatar>
 | 
				
			||||||
 | 
					                <ion-note item-end padding-left *ngIf="rating.timemodified">
 | 
				
			||||||
 | 
					                    {{ rating.timemodified | coreDateDayOrTime }}
 | 
				
			||||||
 | 
					                </ion-note>
 | 
				
			||||||
 | 
					                <h2><core-format-text [text]="rating.userfullname"></core-format-text></h2>
 | 
				
			||||||
 | 
					                <p>{{ rating.rating }}</p>
 | 
				
			||||||
 | 
					            </ion-item>
 | 
				
			||||||
 | 
					        </ion-list>
 | 
				
			||||||
 | 
					        <core-empty-box *ngIf="ratings.length == 0" icon="stats" [message]="'core.rating.noratings' | translate"></core-empty-box>
 | 
				
			||||||
 | 
					    </core-loading>
 | 
				
			||||||
 | 
					</ion-content>
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/core/rating/pages/ratings/ratings.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/core/rating/pages/ratings/ratings.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Martin Dougiamas
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { IonicPageModule } from 'ionic-angular';
 | 
				
			||||||
 | 
					import { TranslateModule } from '@ngx-translate/core';
 | 
				
			||||||
 | 
					import { CoreRatingRatingsPage } from './ratings';
 | 
				
			||||||
 | 
					import { CoreComponentsModule } from '@components/components.module';
 | 
				
			||||||
 | 
					import { CoreDirectivesModule } from '@directives/directives.module';
 | 
				
			||||||
 | 
					import { CorePipesModule } from '@pipes/pipes.module';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					    declarations: [
 | 
				
			||||||
 | 
					        CoreRatingRatingsPage
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    imports: [
 | 
				
			||||||
 | 
					        CoreComponentsModule,
 | 
				
			||||||
 | 
					        CoreDirectivesModule,
 | 
				
			||||||
 | 
					        CorePipesModule,
 | 
				
			||||||
 | 
					        IonicPageModule.forChild(CoreRatingRatingsPage),
 | 
				
			||||||
 | 
					        TranslateModule.forChild()
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class CoreRatingRatingsPageModule {}
 | 
				
			||||||
							
								
								
									
										95
									
								
								src/core/rating/pages/ratings/ratings.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/core/rating/pages/ratings/ratings.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Martin Dougiamas
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Component } from '@angular/core';
 | 
				
			||||||
 | 
					import { IonicPage, NavParams, ViewController } from 'ionic-angular';
 | 
				
			||||||
 | 
					import { CoreDomUtilsProvider } from '@providers/utils/dom';
 | 
				
			||||||
 | 
					import { CoreRatingProvider, CoreRatingItemRating } from '@core/rating/providers/rating';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Page that displays individual ratings
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@IonicPage({ segment: 'core-rating-ratings' })
 | 
				
			||||||
 | 
					@Component({
 | 
				
			||||||
 | 
					    selector: 'page-core-rating-ratings',
 | 
				
			||||||
 | 
					    templateUrl: 'ratings.html',
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class CoreRatingRatingsPage {
 | 
				
			||||||
 | 
					    contextLevel: string;
 | 
				
			||||||
 | 
					    instanceId: number;
 | 
				
			||||||
 | 
					    component: string;
 | 
				
			||||||
 | 
					    ratingArea: string;
 | 
				
			||||||
 | 
					    aggregateMethod: number;
 | 
				
			||||||
 | 
					    itemId: number;
 | 
				
			||||||
 | 
					    scaleId: number;
 | 
				
			||||||
 | 
					    courseId: number;
 | 
				
			||||||
 | 
					    loaded = false;
 | 
				
			||||||
 | 
					    ratings: CoreRatingItemRating[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(navParams: NavParams, private viewCtrl: ViewController, private domUtils: CoreDomUtilsProvider,
 | 
				
			||||||
 | 
					            private ratingProvider: CoreRatingProvider) {
 | 
				
			||||||
 | 
					        this.contextLevel = navParams.get('contextLevel');
 | 
				
			||||||
 | 
					        this.instanceId = navParams.get('instanceId');
 | 
				
			||||||
 | 
					        this.component = navParams.get('ratingComponent');
 | 
				
			||||||
 | 
					        this.ratingArea = navParams.get('ratingArea');
 | 
				
			||||||
 | 
					        this.aggregateMethod = navParams.get('aggregateMethod');
 | 
				
			||||||
 | 
					        this.itemId = navParams.get('itemId');
 | 
				
			||||||
 | 
					        this.scaleId = navParams.get('scaleId');
 | 
				
			||||||
 | 
					        this.courseId = navParams.get('courseId');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * View loaded.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    ionViewDidLoad(): void {
 | 
				
			||||||
 | 
					        this.fetchData().finally(() => {
 | 
				
			||||||
 | 
					            this.loaded = true;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Fetch all the data required for the view.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fetchData(): Promise<any> {
 | 
				
			||||||
 | 
					        return this.ratingProvider.getItemRatings(this.contextLevel, this.instanceId, this.component, this.ratingArea, this.itemId,
 | 
				
			||||||
 | 
					                this.scaleId, undefined, this.courseId).then((ratings) => {
 | 
				
			||||||
 | 
					            this.ratings = ratings;
 | 
				
			||||||
 | 
					        }).catch((error) => {
 | 
				
			||||||
 | 
					            this.domUtils.showErrorModal(error);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Refresh data.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {any} refresher Refresher.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    refreshRatings(refresher: any): void {
 | 
				
			||||||
 | 
					        this.ratingProvider.invalidateRatingItems(this.contextLevel, this.instanceId, this.component, this.ratingArea, this.itemId,
 | 
				
			||||||
 | 
					                this.scaleId).finally(() => {
 | 
				
			||||||
 | 
					            return this.fetchData().finally(() => {
 | 
				
			||||||
 | 
					                refresher.complete();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Close modal.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    closeModal(): void {
 | 
				
			||||||
 | 
					        this.viewCtrl.dismiss();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										305
									
								
								src/core/rating/providers/offline.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								src/core/rating/providers/offline.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,305 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Martin Dougiamas
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
 | 
				
			||||||
 | 
					import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Structure of offline ratings.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface CoreRatingOfflineRating {
 | 
				
			||||||
 | 
					    component: string;
 | 
				
			||||||
 | 
					    ratingarea: string;
 | 
				
			||||||
 | 
					    contextlevel: string;
 | 
				
			||||||
 | 
					    instanceid: number;
 | 
				
			||||||
 | 
					    itemid: number;
 | 
				
			||||||
 | 
					    itemsetid: number;
 | 
				
			||||||
 | 
					    courseid: number;
 | 
				
			||||||
 | 
					    scaleid: number;
 | 
				
			||||||
 | 
					    rating: number;
 | 
				
			||||||
 | 
					    rateduserid: number;
 | 
				
			||||||
 | 
					    aggregation: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Structure of item sets.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface CoreRatingItemSet {
 | 
				
			||||||
 | 
					    component: string;
 | 
				
			||||||
 | 
					    ratingArea: string;
 | 
				
			||||||
 | 
					    contextLevel: string;
 | 
				
			||||||
 | 
					    instanceId: number;
 | 
				
			||||||
 | 
					    itemSetId: number;
 | 
				
			||||||
 | 
					    courseId: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Service to handle offline data for rating.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable()
 | 
				
			||||||
 | 
					export class CoreRatingOfflineProvider {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Variables for database.
 | 
				
			||||||
 | 
					    static RATINGS_TABLE = 'rating_ratings';
 | 
				
			||||||
 | 
					    protected siteSchema: CoreSiteSchema = {
 | 
				
			||||||
 | 
					        name: 'CoreCourseOfflineProvider',
 | 
				
			||||||
 | 
					        version: 1,
 | 
				
			||||||
 | 
					        tables: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                name: CoreRatingOfflineProvider.RATINGS_TABLE,
 | 
				
			||||||
 | 
					                columns: [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'component',
 | 
				
			||||||
 | 
					                        type: 'TEXT'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'ratingarea',
 | 
				
			||||||
 | 
					                        type: 'TEXT'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'contextlevel',
 | 
				
			||||||
 | 
					                        type: 'INTEGER',
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'instanceid',
 | 
				
			||||||
 | 
					                        type: 'INTEGER'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'itemid',
 | 
				
			||||||
 | 
					                        type: 'INTEGER'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'itemsetid',
 | 
				
			||||||
 | 
					                        type: 'INTEGER'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'courseid',
 | 
				
			||||||
 | 
					                        type: 'INTEGER'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'scaleid',
 | 
				
			||||||
 | 
					                        type: 'INTEGER'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'rating',
 | 
				
			||||||
 | 
					                        type: 'INTEGER'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'rateduserid',
 | 
				
			||||||
 | 
					                        type: 'INTEGER'
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        name: 'aggregation',
 | 
				
			||||||
 | 
					                        type: 'INTEGER'
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                primaryKeys: ['component', 'ratingarea', 'contextlevel', 'instanceid', 'itemid']
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider) {
 | 
				
			||||||
 | 
					        this.sitesProvider.registerSiteSchema(this.siteSchema);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get an offline rating.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {numnber} instanceId Context instance id.
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {number} itemId Item id. Example: forum post id.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<CoreRatingOfflineRating>} Promise resolved with the saved rating, rejected if not found.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getRating(contextLevel: string, instanceId: number, component: string, ratingArea: string, itemId: number,  siteId?: string):
 | 
				
			||||||
 | 
					            Promise<CoreRatingOfflineRating> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const conditions = {
 | 
				
			||||||
 | 
					                contextlevel: contextLevel,
 | 
				
			||||||
 | 
					                instanceid: instanceId,
 | 
				
			||||||
 | 
					                component: component,
 | 
				
			||||||
 | 
					                ratingarea: ratingArea,
 | 
				
			||||||
 | 
					                itemid: itemId
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return site.getDb().getRecord(CoreRatingOfflineProvider.RATINGS_TABLE, conditions);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add an offline rating.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {numnber} instanceId Context instance id.
 | 
				
			||||||
 | 
					     * @param {number} itemId Item id. Example: forum post id.
 | 
				
			||||||
 | 
					     * @param {number} itemSetId Item set id. Example: forum discussion id.
 | 
				
			||||||
 | 
					     * @param {number} courseId Course id.
 | 
				
			||||||
 | 
					     * @param {number} scaleId Scale id.
 | 
				
			||||||
 | 
					     * @param {number} rating Rating value. Use CoreRatingProvider.UNSET_RATING to delete rating.
 | 
				
			||||||
 | 
					     * @param {number} ratedUserId Rated user id.
 | 
				
			||||||
 | 
					     * @param {number} aggregateMethod Aggregate method.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Promise resolved when the rating is saved.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    addRating(component: string, ratingArea: string, contextLevel: string, instanceId: number, itemId: number, itemSetId: number,
 | 
				
			||||||
 | 
					            courseId: number, scaleId: number, rating: number, ratedUserId: number, aggregateMethod: number, siteId?: string):
 | 
				
			||||||
 | 
					            Promise<any> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const data: CoreRatingOfflineRating = {
 | 
				
			||||||
 | 
					                component: component,
 | 
				
			||||||
 | 
					                ratingarea: ratingArea,
 | 
				
			||||||
 | 
					                contextlevel: contextLevel,
 | 
				
			||||||
 | 
					                instanceid: instanceId,
 | 
				
			||||||
 | 
					                itemid: itemId,
 | 
				
			||||||
 | 
					                itemsetid: itemSetId,
 | 
				
			||||||
 | 
					                courseid: courseId,
 | 
				
			||||||
 | 
					                scaleid: scaleId,
 | 
				
			||||||
 | 
					                rating: rating,
 | 
				
			||||||
 | 
					                rateduserid: ratedUserId,
 | 
				
			||||||
 | 
					                aggregation: aggregateMethod
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return site.getDb().insertRecord(CoreRatingOfflineProvider.RATINGS_TABLE, data);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Delete offline rating.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} itemId Item id. Example: forum post id.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Promise resolved when the rating is saved.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    deleteRating(component: string, ratingArea: string, contextLevel: string, instanceId: number, itemId: number, siteId?: string):
 | 
				
			||||||
 | 
					            Promise<any> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const conditions = {
 | 
				
			||||||
 | 
					                component: component,
 | 
				
			||||||
 | 
					                ratingarea: ratingArea,
 | 
				
			||||||
 | 
					                contextlevel: contextLevel,
 | 
				
			||||||
 | 
					                instanceid: instanceId,
 | 
				
			||||||
 | 
					                itemid: itemId
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return site.getDb().deleteRecords(CoreRatingOfflineProvider.RATINGS_TABLE, conditions);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the list of item sets in a component or instance.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating Area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} [contextLevel] Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {numnber} [instanceId] Context instance id.
 | 
				
			||||||
 | 
					     * @param {number} [itemSetId] Item set id.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<CoreRatingItemSet[]>} Promise resolved with the list of item set ids.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getItemSets(component: string, ratingArea: string, contextLevel?: string, instanceId?: number, itemSetId?: number,
 | 
				
			||||||
 | 
					            siteId?: string): Promise<CoreRatingItemSet[]> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const fields = 'DISTINCT contextlevel, instanceid, itemsetid, courseid';
 | 
				
			||||||
 | 
					            const conditions: any = {
 | 
				
			||||||
 | 
					                component,
 | 
				
			||||||
 | 
					                ratingarea: ratingArea
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            if (contextLevel != null && instanceId != null) {
 | 
				
			||||||
 | 
					                conditions.contextlevel = contextLevel;
 | 
				
			||||||
 | 
					                conditions.instanceId = instanceId;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (itemSetId != null) {
 | 
				
			||||||
 | 
					                conditions.itemSetId = itemSetId;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return site.getDb().getRecords(CoreRatingOfflineProvider.RATINGS_TABLE, conditions, undefined, fields)
 | 
				
			||||||
 | 
					                    .then((records: any[]) => {
 | 
				
			||||||
 | 
					                return records.map((record) => {
 | 
				
			||||||
 | 
					                    return {
 | 
				
			||||||
 | 
					                        component,
 | 
				
			||||||
 | 
					                        ratingArea,
 | 
				
			||||||
 | 
					                        contextLevel: record.contextlevel,
 | 
				
			||||||
 | 
					                        instanceId: record.instanceid,
 | 
				
			||||||
 | 
					                        itemSetId: record.itemsetid,
 | 
				
			||||||
 | 
					                        courseId: record.courseid
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get offline ratings of an item set.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating Area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} itemId Item id. Example: forum post id.
 | 
				
			||||||
 | 
					     * @param {number} itemSetId Item set id. Example: forum discussion id.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<CoreRatingOfflineRating[]>} Promise resolved with the list of ratings.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getRatings(component: string, ratingArea: string, contextLevel: string, instanceId: number, itemSetId: number, siteId?: string):
 | 
				
			||||||
 | 
					            Promise<CoreRatingOfflineRating[]> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const conditions = {
 | 
				
			||||||
 | 
					                component,
 | 
				
			||||||
 | 
					                ratingarea: ratingArea,
 | 
				
			||||||
 | 
					                contextlevel: contextLevel,
 | 
				
			||||||
 | 
					                instanceid: instanceId,
 | 
				
			||||||
 | 
					                itemsetid: itemSetId
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return site.getDb().getRecords(CoreRatingOfflineProvider.RATINGS_TABLE, conditions);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Return whether a component, instance or item set has offline ratings.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating Area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} [contextLevel] Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} [instanceId] Context instance id.
 | 
				
			||||||
 | 
					     * @param {number} [itemSetId] Item set id. Example: forum discussion id.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<boolean>} Promise resolved with a boolean.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    hasRatings(component: string, ratingArea: string, contextLevel?: string, instanceId?: number, itemSetId?: number,
 | 
				
			||||||
 | 
					            siteId?: string): Promise<boolean> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const conditions: any = {
 | 
				
			||||||
 | 
					                component,
 | 
				
			||||||
 | 
					                ratingarea: ratingArea
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            if (contextLevel != null && instanceId != null) {
 | 
				
			||||||
 | 
					                conditions.contextlevel = contextLevel;
 | 
				
			||||||
 | 
					                conditions.instanceId = instanceId;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (itemSetId != null) {
 | 
				
			||||||
 | 
					                conditions.itemsetid = itemSetId;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return this.utils.promiseWorks(site.getDb().recordExists(CoreRatingOfflineProvider.RATINGS_TABLE, conditions));
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										352
									
								
								src/core/rating/providers/rating.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										352
									
								
								src/core/rating/providers/rating.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,352 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Martin Dougiamas
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import { CoreSiteWSPreSets } from '@classes/site';
 | 
				
			||||||
 | 
					import { CoreAppProvider } from '@providers/app';
 | 
				
			||||||
 | 
					import { CoreEventsProvider } from '@providers/events';
 | 
				
			||||||
 | 
					import { CoreSitesProvider } from '@providers/sites';
 | 
				
			||||||
 | 
					import { CoreUserProvider } from '@core/user/providers/user';
 | 
				
			||||||
 | 
					import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
				
			||||||
 | 
					import { CoreRatingOfflineProvider } from './offline';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Structure of the rating info returned by web services.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface CoreRatingInfo {
 | 
				
			||||||
 | 
					    contextid: number;
 | 
				
			||||||
 | 
					    component: string;
 | 
				
			||||||
 | 
					    ratingarea: string;
 | 
				
			||||||
 | 
					    canviewall: boolean;
 | 
				
			||||||
 | 
					    canviewany: boolean;
 | 
				
			||||||
 | 
					    scales?: CoreRatingScale[];
 | 
				
			||||||
 | 
					    ratings?: CoreRatingInfoItem[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Structure of scales in the rating info.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface CoreRatingScale {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    courseid?: number;
 | 
				
			||||||
 | 
					    name?: string;
 | 
				
			||||||
 | 
					    max: number;
 | 
				
			||||||
 | 
					    isnumeric: boolean;
 | 
				
			||||||
 | 
					    items?: {value: number, name: string}[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Structure of items in the rating info.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface CoreRatingInfoItem {
 | 
				
			||||||
 | 
					    itemid: number;
 | 
				
			||||||
 | 
					    scaleid?: number;
 | 
				
			||||||
 | 
					    scale?: CoreRatingScale;
 | 
				
			||||||
 | 
					    userid?: number;
 | 
				
			||||||
 | 
					    aggregate?: number;
 | 
				
			||||||
 | 
					    aggregatestr?: string;
 | 
				
			||||||
 | 
					    count?: number;
 | 
				
			||||||
 | 
					    rating?: number;
 | 
				
			||||||
 | 
					    canrate?: boolean;
 | 
				
			||||||
 | 
					    canviewaggregate?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Structure of a rating returned by the item ratings web service.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					export interface CoreRatingItemRating {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					    userid: number;
 | 
				
			||||||
 | 
					    userpictureurl: string;
 | 
				
			||||||
 | 
					    userfullname: string;
 | 
				
			||||||
 | 
					    rating: string;
 | 
				
			||||||
 | 
					    timemodified: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Service to handle ratings.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable()
 | 
				
			||||||
 | 
					export class CoreRatingProvider {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static AGGREGATE_NONE = 0; // No ratings.
 | 
				
			||||||
 | 
					    static AGGREGATE_AVERAGE = 1;
 | 
				
			||||||
 | 
					    static AGGREGATE_COUNT = 2;
 | 
				
			||||||
 | 
					    static AGGREGATE_MAXIMUM = 3;
 | 
				
			||||||
 | 
					    static AGGREGATE_MINIMUM = 4;
 | 
				
			||||||
 | 
					    static AGGREGATE_SUM = 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static UNSET_RATING = -999;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static AGGREGATE_CHANGED_EVENT = 'core_rating_aggregate_changed';
 | 
				
			||||||
 | 
					    static RATING_SAVED_EVENT = 'core_rating_rating_saved';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected ROOT_CACHE_KEY = 'CoreRating:';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(private appProvider: CoreAppProvider,
 | 
				
			||||||
 | 
					            private eventsProvider: CoreEventsProvider,
 | 
				
			||||||
 | 
					            private sitesProvider: CoreSitesProvider,
 | 
				
			||||||
 | 
					            private userProvider: CoreUserProvider,
 | 
				
			||||||
 | 
					            private utils: CoreUtilsProvider,
 | 
				
			||||||
 | 
					            private ratingOffline: CoreRatingOfflineProvider) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns whether the web serivce to add ratings is available.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return {boolean} If WS is abalaible.
 | 
				
			||||||
 | 
					     * @since 3.2
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    isAddRatingWSAvailable(): boolean {
 | 
				
			||||||
 | 
					        return this.sitesProvider.wsAvailableInCurrentSite('core_rating_add_rating');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add a rating to an item.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} instanceId Context instance id.
 | 
				
			||||||
 | 
					     * @param {number} itemId Item id. Example: forum post id.
 | 
				
			||||||
 | 
					     * @param {number} itemSetId Item set id. Example: forum discussion id.
 | 
				
			||||||
 | 
					     * @param {number} courseId Course id.
 | 
				
			||||||
 | 
					     * @param {number} scaleId Scale id.
 | 
				
			||||||
 | 
					     * @param {number} rating Rating value. Use CoreRatingProvider.UNSET_RATING to delete rating.
 | 
				
			||||||
 | 
					     * @param {number} ratedUserId Rated user id.
 | 
				
			||||||
 | 
					     * @param {number} aggregateMethod Aggregate method.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<CoreRatingItemRating|null>} Promise resolved with the aggregated rating or null if stored offline.
 | 
				
			||||||
 | 
					     * @since 3.2
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    addRating(component: string, ratingArea: string, contextLevel: string, instanceId: number, itemId: number, itemSetId: number,
 | 
				
			||||||
 | 
					            courseId: number, scaleId: number, rating: number, ratedUserId: number, aggregateMethod: number, siteId?: string):
 | 
				
			||||||
 | 
					            Promise<CoreRatingItemRating[]> {
 | 
				
			||||||
 | 
					        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Convenience function to store a rating to be synchronized later.
 | 
				
			||||||
 | 
					        const storeOffline = (): Promise<any> => {
 | 
				
			||||||
 | 
					            return this.ratingOffline.addRating(component, ratingArea, contextLevel, instanceId, itemId, itemSetId, courseId,
 | 
				
			||||||
 | 
					                    scaleId, rating, ratedUserId, aggregateMethod, siteId).then(() => {
 | 
				
			||||||
 | 
					                this.eventsProvider.trigger(CoreRatingProvider.RATING_SAVED_EVENT, {
 | 
				
			||||||
 | 
					                    component,
 | 
				
			||||||
 | 
					                    ratingArea,
 | 
				
			||||||
 | 
					                    contextLevel,
 | 
				
			||||||
 | 
					                    instanceId,
 | 
				
			||||||
 | 
					                    itemSetId,
 | 
				
			||||||
 | 
					                    itemId
 | 
				
			||||||
 | 
					                }, siteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return null;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this.appProvider.isOnline()) {
 | 
				
			||||||
 | 
					            // App is offline, store the action.
 | 
				
			||||||
 | 
					            return storeOffline();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.ratingOffline.deleteRating(component, ratingArea, contextLevel, instanceId, itemId, siteId).then(() => {
 | 
				
			||||||
 | 
					            return this.addRatingOnline(component, ratingArea, contextLevel, instanceId, itemId, scaleId, rating, ratedUserId,
 | 
				
			||||||
 | 
					                    aggregateMethod, siteId).catch((error) => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (this.utils.isWebServiceError(error)) {
 | 
				
			||||||
 | 
					                    // The WebService has thrown an error or offline not supported, reject.
 | 
				
			||||||
 | 
					                    return Promise.reject(error);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Couldn't connect to server, store offline.
 | 
				
			||||||
 | 
					                return storeOffline();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add a rating to an item. It will fail if offline or cannot connect.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} instanceId Context instance id.
 | 
				
			||||||
 | 
					     * @param {number} itemId Item id. Example: forum post id.
 | 
				
			||||||
 | 
					     * @param {number} scaleId Scale id.
 | 
				
			||||||
 | 
					     * @param {number} rating Rating value. Use CoreRatingProvider.UNSET_RATING to delete rating.
 | 
				
			||||||
 | 
					     * @param {number} ratedUserId Rated user id.
 | 
				
			||||||
 | 
					     * @param {number} aggregateMethod Aggregate method.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<CoreRatingItemRating>} Promise resolved with the aggregated rating.
 | 
				
			||||||
 | 
					     * @since 3.2
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    addRatingOnline(component: string, ratingArea: string, contextLevel: string, instanceId: number, itemId: number,
 | 
				
			||||||
 | 
					            scaleId: number, rating: number, ratedUserId: number, aggregateMethod: number, siteId?: string):
 | 
				
			||||||
 | 
					            Promise<CoreRatingItemRating> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const params = {
 | 
				
			||||||
 | 
					                contextlevel: contextLevel,
 | 
				
			||||||
 | 
					                instanceid: instanceId,
 | 
				
			||||||
 | 
					                component: component,
 | 
				
			||||||
 | 
					                ratingarea: ratingArea,
 | 
				
			||||||
 | 
					                itemid: itemId,
 | 
				
			||||||
 | 
					                scaleid: scaleId,
 | 
				
			||||||
 | 
					                rating: rating,
 | 
				
			||||||
 | 
					                rateduserid: ratedUserId,
 | 
				
			||||||
 | 
					                aggregation: aggregateMethod
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return site.write('core_rating_add_rating', params).then((response) => {
 | 
				
			||||||
 | 
					                return this.invalidateRatingItems(contextLevel, instanceId, component, ratingArea, itemId, scaleId).then(() => {
 | 
				
			||||||
 | 
					                    this.eventsProvider.trigger(CoreRatingProvider.AGGREGATE_CHANGED_EVENT, {
 | 
				
			||||||
 | 
					                        contextLevel,
 | 
				
			||||||
 | 
					                        instanceId,
 | 
				
			||||||
 | 
					                        component,
 | 
				
			||||||
 | 
					                        ratingArea,
 | 
				
			||||||
 | 
					                        itemId,
 | 
				
			||||||
 | 
					                        aggregate: response.aggregate,
 | 
				
			||||||
 | 
					                        count: response.count
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    return response;
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get item ratings.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} instanceId Context instance id.
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {number} itemId Item id. Example: forum post id.
 | 
				
			||||||
 | 
					     * @param {number} scaleId Scale id.
 | 
				
			||||||
 | 
					     * @param {string} [sort="timemodified"] Sort field.
 | 
				
			||||||
 | 
					     * @param {number} [courseId] Course id. Used for fetching user profiles.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @param {boolean} [ignoreCache=false] True if it should ignore cached data (it will always fail in offline or server down).
 | 
				
			||||||
 | 
					     * @return {Promise<CoreRatingItemRating[]>} Promise resolved with the list of ratings.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getItemRatings(contextLevel: string, instanceId: number, component: string, ratingArea: string, itemId: number,
 | 
				
			||||||
 | 
					            scaleId: number, sort: string = 'timemodified', courseId?: number, siteId?: string, ignoreCache: boolean = false):
 | 
				
			||||||
 | 
					            Promise<CoreRatingItemRating[]> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const params = {
 | 
				
			||||||
 | 
					                contextlevel: contextLevel,
 | 
				
			||||||
 | 
					                instanceid: instanceId,
 | 
				
			||||||
 | 
					                component: component,
 | 
				
			||||||
 | 
					                ratingarea: ratingArea,
 | 
				
			||||||
 | 
					                itemid: itemId,
 | 
				
			||||||
 | 
					                scaleid: scaleId,
 | 
				
			||||||
 | 
					                sort: sort
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            const preSets: CoreSiteWSPreSets = {
 | 
				
			||||||
 | 
					                cacheKey: this.getItemRatingsCacheKey(contextLevel, instanceId, component, ratingArea, itemId, scaleId, sort)
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            if (ignoreCache) {
 | 
				
			||||||
 | 
					                preSets.getFromCache = false;
 | 
				
			||||||
 | 
					                preSets.emergencyCache = false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return site.read('core_rating_get_item_ratings', params, preSets).then((response) => {
 | 
				
			||||||
 | 
					                if (!response || !response.ratings) {
 | 
				
			||||||
 | 
					                    return Promise.reject(null);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // We need to fetch profiles because the returned profile pictures are incorrect.
 | 
				
			||||||
 | 
					                const promises = response.ratings.map((rating: CoreRatingItemRating) => {
 | 
				
			||||||
 | 
					                    return this.userProvider.getProfile(rating.userid, courseId, true, site.id).then((user) => {
 | 
				
			||||||
 | 
					                        rating.userpictureurl = user.profileimageurl;
 | 
				
			||||||
 | 
					                    }).catch(() => {
 | 
				
			||||||
 | 
					                        // Ignore error.
 | 
				
			||||||
 | 
					                        rating.userpictureurl = null;
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                return Promise.all(promises).then(() => {
 | 
				
			||||||
 | 
					                    return response.ratings;
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Invalidate item ratings.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} instanceId Context instance id.
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {number} itemId Item id. Example: forum post id.
 | 
				
			||||||
 | 
					     * @param {number} scaleId Scale id.
 | 
				
			||||||
 | 
					     * @param {string} [sort="timemodified"] Sort field.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Promise resolved when the data is invalidated.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    invalidateRatingItems(contextLevel: string, instanceId: number, component: string, ratingArea: string,
 | 
				
			||||||
 | 
					            itemId: number, scaleId: number, sort: string = 'timemodified', siteId?: string): Promise<any> {
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const key = this.getItemRatingsCacheKey(contextLevel, instanceId, component, ratingArea, itemId, scaleId, sort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return site.invalidateWsCacheForKey(key);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Prefetch individual ratings.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * This function should be called from the prefetch handler of activities with ratings.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} instanceId Instance id.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site id. If not defined, current site.
 | 
				
			||||||
 | 
					     * @param {number} [courseId] Course id. Used for prefetching user profiles.
 | 
				
			||||||
 | 
					     * @param {CoreRatingInfo} [ratingInfo] Rating info returned by web services.
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Promise resolved when done.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    prefetchRatings(contextLevel: string, instanceId: number, scaleId: number, courseId?: number, ratingInfo?: CoreRatingInfo,
 | 
				
			||||||
 | 
					            siteId?: string): Promise<any> {
 | 
				
			||||||
 | 
					        if (!ratingInfo || !ratingInfo.ratings) {
 | 
				
			||||||
 | 
					            return Promise.resolve();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.sitesProvider.getSite(siteId).then((site) => {
 | 
				
			||||||
 | 
					            const promises = ratingInfo.ratings.map((item) => {
 | 
				
			||||||
 | 
					                return this.getItemRatings(contextLevel, instanceId, ratingInfo.component, ratingInfo.ratingarea, item.itemid,
 | 
				
			||||||
 | 
					                        scaleId, undefined, courseId, site.id, true).then((ratings) => {
 | 
				
			||||||
 | 
					                    const userIds = ratings.map((rating: CoreRatingItemRating) => rating.userid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    return this.userProvider.prefetchProfiles(userIds, courseId, site.id);
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return Promise.all(promises);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get cache key for rating items WS calls.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {number} itemId Item id. Example: forum post id.
 | 
				
			||||||
 | 
					     * @param {number} scaleId Scale id.
 | 
				
			||||||
 | 
					     * @param {string} sort Sort field.
 | 
				
			||||||
 | 
					     * @return {string} Cache key.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected getItemRatingsCacheKey(contextLevel: string, instanceId: number, component: string, ratingArea: string,
 | 
				
			||||||
 | 
					            itemId: number, scaleId: number, sort: string): string {
 | 
				
			||||||
 | 
					        return `${this.ROOT_CACHE_KEY}${contextLevel}:${instanceId}:${component}:${ratingArea}:${itemId}:${scaleId}:${sort}`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										196
									
								
								src/core/rating/providers/sync.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								src/core/rating/providers/sync.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,196 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Martin Dougiamas
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
 | 
					import { TranslateService } from '@ngx-translate/core';
 | 
				
			||||||
 | 
					import { CoreSyncBaseProvider } from '@classes/base-sync';
 | 
				
			||||||
 | 
					import { CoreAppProvider } from '@providers/app';
 | 
				
			||||||
 | 
					import { CoreLoggerProvider } from '@providers/logger';
 | 
				
			||||||
 | 
					import { CoreSitesProvider } from '@providers/sites';
 | 
				
			||||||
 | 
					import { CoreSyncProvider } from '@providers/sync';
 | 
				
			||||||
 | 
					import { CoreTextUtilsProvider } from '@providers/utils/text';
 | 
				
			||||||
 | 
					import { CoreTimeUtilsProvider } from '@providers/utils/time';
 | 
				
			||||||
 | 
					import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
				
			||||||
 | 
					import { CoreRatingProvider } from './rating';
 | 
				
			||||||
 | 
					import { CoreRatingOfflineProvider, CoreRatingItemSet } from './offline';
 | 
				
			||||||
 | 
					import { CoreEventsProvider } from '@providers/events';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Service to sync ratings.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Injectable()
 | 
				
			||||||
 | 
					export class CoreRatingSyncProvider extends CoreSyncBaseProvider {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static SYNCED_EVENT = 'core_rating_synced';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(translate: TranslateService,
 | 
				
			||||||
 | 
					            appProvider: CoreAppProvider,
 | 
				
			||||||
 | 
					            private eventsProvider: CoreEventsProvider,
 | 
				
			||||||
 | 
					            loggerProvider: CoreLoggerProvider,
 | 
				
			||||||
 | 
					            sitesProvider: CoreSitesProvider,
 | 
				
			||||||
 | 
					            syncProvider: CoreSyncProvider,
 | 
				
			||||||
 | 
					            textUtils: CoreTextUtilsProvider,
 | 
				
			||||||
 | 
					            timeUtils: CoreTimeUtilsProvider,
 | 
				
			||||||
 | 
					            private utils: CoreUtilsProvider,
 | 
				
			||||||
 | 
					            private ratingProvider: CoreRatingProvider,
 | 
				
			||||||
 | 
					            private ratingOffline: CoreRatingOfflineProvider) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        super('CoreRatingSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate, timeUtils);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Try to synchronize all the ratings of a certain component, instance or item set.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * This function should be called from the sync provider of activities with ratings.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating Area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} [contextLevel] Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {numnber} [instanceId] Context instance id.
 | 
				
			||||||
 | 
					     * @param {number} [itemSetId] Item set id.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Promise resolved if sync is successful, rejected if sync fails.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    syncRatings(component: string, ratingArea: string, contextLevel?: string, instanceId?: number, itemSetId?: number,
 | 
				
			||||||
 | 
					            siteId?: string): Promise<{itemSet: CoreRatingItemSet, updated: boolean, warnings: string[]}[]> {
 | 
				
			||||||
 | 
					        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.ratingOffline.getItemSets(component, ratingArea, contextLevel, instanceId, itemSetId, siteId)
 | 
				
			||||||
 | 
					                .then((itemSets) => {
 | 
				
			||||||
 | 
					            const results = [];
 | 
				
			||||||
 | 
					            const promises = itemSets.map((itemSet) => {
 | 
				
			||||||
 | 
					                return this.syncItemSetIfNeeded(component, ratingArea, itemSet.contextLevel, itemSet.instanceId,
 | 
				
			||||||
 | 
					                        itemSet.itemSetId, siteId).then((result) => {
 | 
				
			||||||
 | 
					                    if (result.updated) {
 | 
				
			||||||
 | 
					                        // Sync successful, send event.
 | 
				
			||||||
 | 
					                        this.eventsProvider.trigger(CoreRatingSyncProvider.SYNCED_EVENT, {
 | 
				
			||||||
 | 
					                            ...itemSet,
 | 
				
			||||||
 | 
					                            warnings: result.warnings
 | 
				
			||||||
 | 
					                        }, siteId);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    results.push({itemSet, ...result});
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return Promise.all(promises).then(() => {
 | 
				
			||||||
 | 
					                return results;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Sync ratings of an item set only if a certain time has passed since the last time.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating Area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} instanceId Context instance id.
 | 
				
			||||||
 | 
					     * @param {number} itemSetId Item set id. Example: forum discussion id.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Promise resolved when ratings are synced or if it doesn't need to be synced.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected syncItemSetIfNeeded(component: string, ratingArea: string,  contextLevel: string, instanceId: number,
 | 
				
			||||||
 | 
					            itemSetId: number, siteId?: string): Promise<{updated: boolean, warnings: string[]}> {
 | 
				
			||||||
 | 
					        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const syncId = this.getItemSetSyncId(component, ratingArea, contextLevel, instanceId, itemSetId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.isSyncNeeded(syncId, siteId).then((needed) => {
 | 
				
			||||||
 | 
					            if (needed) {
 | 
				
			||||||
 | 
					                return this.syncItemSet(component, ratingArea, contextLevel, instanceId, itemSetId, siteId);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Synchronize all offline ratings of an item set.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating Area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} instanceId Context instance id.
 | 
				
			||||||
 | 
					     * @param {number} itemSetId Item set id. Example: forum discussion id.
 | 
				
			||||||
 | 
					     * @param {string} [siteId] Site ID. If not defined, current site.
 | 
				
			||||||
 | 
					     * @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected syncItemSet(component: string, ratingArea: string, contextLevel: string, instanceId: number, itemSetId: number,
 | 
				
			||||||
 | 
					            siteId?: string): Promise<{updated: boolean, warnings: string[]}> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        siteId = siteId || this.sitesProvider.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const syncId = this.getItemSetSyncId(component, ratingArea, contextLevel, instanceId, itemSetId);
 | 
				
			||||||
 | 
					        if (this.isSyncing(syncId, siteId)) {
 | 
				
			||||||
 | 
					            // There's already a sync ongoing for this item set, return the promise.
 | 
				
			||||||
 | 
					            return this.getOngoingSync(syncId, siteId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.logger.debug(`Try to sync ratings of component '${component}' rating area '${ratingArea}'` +
 | 
				
			||||||
 | 
					            ` context level '${contextLevel}' instance ${instanceId} item set ${itemSetId}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let updated = false;
 | 
				
			||||||
 | 
					        const warnings = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this.ratingOffline.getRatings(component, ratingArea, contextLevel, instanceId, itemSetId, siteId).then((ratings) => {
 | 
				
			||||||
 | 
					            if (!ratings.length) {
 | 
				
			||||||
 | 
					                // Nothing to sync.
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            } else if (!this.appProvider.isOnline()) {
 | 
				
			||||||
 | 
					                // Cannot sync in offline.
 | 
				
			||||||
 | 
					                return Promise.reject(null);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const promises = ratings.map((rating) => {
 | 
				
			||||||
 | 
					                return this.ratingProvider.addRatingOnline(component, ratingArea, rating.contextlevel, rating.instanceid,
 | 
				
			||||||
 | 
					                        rating.itemid, rating.scaleid, rating.rating, rating.rateduserid, rating.aggregation, siteId)
 | 
				
			||||||
 | 
					                        .catch((error) => {
 | 
				
			||||||
 | 
					                    if (this.utils.isWebServiceError(error)) {
 | 
				
			||||||
 | 
					                        warnings.push(this.textUtils.getErrorMessageFromError(error));
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        // Couldn't connect to server, reject.
 | 
				
			||||||
 | 
					                        return Promise.reject(error);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }).then(() => {
 | 
				
			||||||
 | 
					                    updated = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    return this.ratingOffline.deleteRating(component, ratingArea, rating.contextlevel, rating.instanceid,
 | 
				
			||||||
 | 
					                            rating.itemid, siteId).finally(() => {
 | 
				
			||||||
 | 
					                        return this.ratingProvider.invalidateRatingItems(rating.contextlevel, rating.instanceid, component,
 | 
				
			||||||
 | 
					                                ratingArea, rating.itemid, rating.scaleid, undefined, siteId);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return Promise.all(promises).then(() => {
 | 
				
			||||||
 | 
					                // All done, return the warnings.
 | 
				
			||||||
 | 
					                return { updated, warnings };
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the sync id of an item set.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param {string} component Component. Example: "mod_forum".
 | 
				
			||||||
 | 
					     * @param {string} ratingArea Rating Area. Example: "post".
 | 
				
			||||||
 | 
					     * @param {string} contextLevel Context level: course, module, user, etc.
 | 
				
			||||||
 | 
					     * @param {number} instanceId Context instance id.
 | 
				
			||||||
 | 
					     * @param {number} itemSetId Item set id. Example: forum discussion id.
 | 
				
			||||||
 | 
					     * @return {string} Sync id.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected getItemSetSyncId(component: string, ratingArea: string, contextLevel: string, instanceId: number, itemSetId: number):
 | 
				
			||||||
 | 
					            string {
 | 
				
			||||||
 | 
					        return `itemSet#${component}#${ratingArea}#${contextLevel}#${instanceId}#${itemSetId}`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								src/core/rating/rating.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/core/rating/rating.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					// (C) Copyright 2015 Martin Dougiamas
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					// you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					// You may obtain a copy of the License at
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					//     http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					// distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					// See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { NgModule } from '@angular/core';
 | 
				
			||||||
 | 
					import { CoreRatingProvider } from './providers/rating';
 | 
				
			||||||
 | 
					import { CoreRatingOfflineProvider } from './providers/offline';
 | 
				
			||||||
 | 
					import { CoreRatingSyncProvider } from './providers/sync';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@NgModule({
 | 
				
			||||||
 | 
					    declarations: [
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    imports: [
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    providers: [
 | 
				
			||||||
 | 
					        CoreRatingProvider,
 | 
				
			||||||
 | 
					        CoreRatingOfflineProvider,
 | 
				
			||||||
 | 
					        CoreRatingSyncProvider
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					export class CoreRatingModule {}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user