394 lines
13 KiB
TypeScript
394 lines
13 KiB
TypeScript
// (C) Copyright 2015 Moodle Pty Ltd.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import { Injectable } from '@angular/core';
|
|
import { CoreError } from '@classes/errors/error';
|
|
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
|
import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
|
|
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
|
|
import { CoreApp } from '@services/app';
|
|
import { CoreFilepool } from '@services/filepool';
|
|
import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites';
|
|
import { CoreUtils } from '@services/utils/utils';
|
|
import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws';
|
|
import { makeSingleton } from '@singletons';
|
|
import { AddonModSurveyOffline } from './survey-offline';
|
|
|
|
const ROOT_CACHE_KEY = 'mmaModSurvey:';
|
|
|
|
/**
|
|
* Service that provides some features for surveys.
|
|
*/
|
|
@Injectable( { providedIn: 'root' })
|
|
export class AddonModSurveyProvider {
|
|
|
|
static readonly COMPONENT = 'mmaModSurvey';
|
|
|
|
/**
|
|
* Get a survey's questions.
|
|
*
|
|
* @param surveyId Survey ID.
|
|
* @param options Other options.
|
|
* @return Promise resolved when the questions are retrieved.
|
|
*/
|
|
async getQuestions(surveyId: number, options: CoreCourseCommonModWSOptions = {}): Promise<AddonModSurveyQuestion[]> {
|
|
const site = await CoreSites.getSite(options.siteId);
|
|
|
|
const params: AddonModSurveyGetQuestionsWSParams = {
|
|
surveyid: surveyId,
|
|
};
|
|
|
|
const preSets: CoreSiteWSPreSets = {
|
|
cacheKey: this.getQuestionsCacheKey(surveyId),
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
component: AddonModSurveyProvider.COMPONENT,
|
|
componentId: options.cmId,
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
|
};
|
|
|
|
const response = await site.read<AddonModSurveyGetQuestionsWSResponse>('mod_survey_get_questions', params, preSets);
|
|
if (response.questions) {
|
|
return response.questions;
|
|
}
|
|
|
|
throw new CoreError('No questions were found.');
|
|
}
|
|
|
|
/**
|
|
* Get cache key for survey questions WS calls.
|
|
*
|
|
* @param surveyId Survey ID.
|
|
* @return Cache key.
|
|
*/
|
|
protected getQuestionsCacheKey(surveyId: number): string {
|
|
return ROOT_CACHE_KEY + 'questions:' + surveyId;
|
|
}
|
|
|
|
/**
|
|
* Get cache key for survey data WS calls.
|
|
*
|
|
* @param courseId Course ID.
|
|
* @return Cache key.
|
|
*/
|
|
protected getSurveyCacheKey(courseId: number): string {
|
|
return ROOT_CACHE_KEY + 'survey:' + courseId;
|
|
}
|
|
|
|
/**
|
|
* Get a survey data.
|
|
*
|
|
* @param courseId Course ID.
|
|
* @param key Name of the property to check.
|
|
* @param value Value to search.
|
|
* @param options Other options.
|
|
* @return Promise resolved when the survey is retrieved.
|
|
*/
|
|
protected async getSurveyDataByKey(
|
|
courseId: number,
|
|
key: string,
|
|
value: number,
|
|
options: CoreSitesCommonWSOptions = {},
|
|
): Promise<AddonModSurveySurvey> {
|
|
const site = await CoreSites.getSite(options.siteId);
|
|
|
|
const params: AddonModSurveyGetSurveysByCoursesWSParams = {
|
|
courseids: [courseId],
|
|
};
|
|
|
|
const preSets: CoreSiteWSPreSets = {
|
|
cacheKey: this.getSurveyCacheKey(courseId),
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
component: AddonModSurveyProvider.COMPONENT,
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
|
};
|
|
|
|
const response =
|
|
await site.read<AddonModSurveyGetSurveysByCoursesWSResponse>('mod_survey_get_surveys_by_courses', params, preSets);
|
|
|
|
const currentSurvey = response.surveys.find((survey) => survey[key] == value);
|
|
if (currentSurvey) {
|
|
return currentSurvey;
|
|
}
|
|
|
|
throw new CoreError('Activity not found.');
|
|
}
|
|
|
|
/**
|
|
* Get a survey by course module ID.
|
|
*
|
|
* @param courseId Course ID.
|
|
* @param cmId Course module ID.
|
|
* @param options Other options.
|
|
* @return Promise resolved when the survey is retrieved.
|
|
*/
|
|
getSurvey(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModSurveySurvey> {
|
|
return this.getSurveyDataByKey(courseId, 'coursemodule', cmId, options);
|
|
}
|
|
|
|
/**
|
|
* Get a survey by ID.
|
|
*
|
|
* @param courseId Course ID.
|
|
* @param id Survey ID.
|
|
* @param options Other options.
|
|
* @return Promise resolved when the survey is retrieved.
|
|
*/
|
|
getSurveyById(courseId: number, id: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModSurveySurvey> {
|
|
return this.getSurveyDataByKey(courseId, 'id', id, options);
|
|
}
|
|
|
|
/**
|
|
* Invalidate the prefetched content.
|
|
*
|
|
* @param moduleId The module ID.
|
|
* @param courseId Course ID of the module.
|
|
* @param siteId Site ID. If not defined, current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateContent(moduleId: number, courseId: number, siteId?: string): Promise<void> {
|
|
siteId = siteId || CoreSites.getCurrentSiteId();
|
|
|
|
const promises: Promise<void>[] = [];
|
|
|
|
promises.push(this.getSurvey(courseId, moduleId).then(async (survey) => {
|
|
const ps: Promise<void>[] = [];
|
|
|
|
// Do not invalidate activity data before getting activity info, we need it!
|
|
ps.push(this.invalidateSurveyData(courseId, siteId));
|
|
ps.push(this.invalidateQuestions(survey.id, siteId));
|
|
|
|
await Promise.all(ps);
|
|
|
|
return;
|
|
}));
|
|
|
|
promises.push(CoreFilepool.invalidateFilesByComponent(siteId, AddonModSurveyProvider.COMPONENT, moduleId));
|
|
|
|
await CoreUtils.allPromises(promises);
|
|
}
|
|
|
|
/**
|
|
* Invalidates survey questions.
|
|
*
|
|
* @param surveyId Survey ID.
|
|
* @param siteId Site ID. If not defined, current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateQuestions(surveyId: number, siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKey(this.getQuestionsCacheKey(surveyId));
|
|
}
|
|
|
|
/**
|
|
* Invalidates survey data.
|
|
*
|
|
* @param courseId Course ID.
|
|
* @param siteId Site ID. If not defined, current site.
|
|
* @return Promise resolved when the data is invalidated.
|
|
*/
|
|
async invalidateSurveyData(courseId: number, siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
await site.invalidateWsCacheForKey(this.getSurveyCacheKey(courseId));
|
|
}
|
|
|
|
/**
|
|
* Report the survey as being viewed.
|
|
*
|
|
* @param id Module ID.
|
|
* @param name Name of the assign.
|
|
* @param siteId Site ID. If not defined, current site.
|
|
* @return Promise resolved when the WS call is successful.
|
|
*/
|
|
async logView(id: number, name?: string, siteId?: string): Promise<void> {
|
|
const params: AddonModSurveyViewSurveyWSParams = {
|
|
surveyid: id,
|
|
};
|
|
|
|
await CoreCourseLogHelper.logSingle(
|
|
'mod_survey_view_survey',
|
|
params,
|
|
AddonModSurveyProvider.COMPONENT,
|
|
id,
|
|
name,
|
|
'survey',
|
|
{},
|
|
siteId,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Send survey answers. If cannot send them to Moodle, they'll be stored in offline to be sent later.
|
|
*
|
|
* @param surveyId Survey ID.
|
|
* @param name Survey name.
|
|
* @param courseId Course ID the survey belongs to.
|
|
* @param answers Answers.
|
|
* @param siteId Site ID. If not defined, current site.
|
|
* @return Promise resolved with boolean if success: true if answers were sent to server,
|
|
* false if stored in device.
|
|
*/
|
|
async submitAnswers(
|
|
surveyId: number,
|
|
name: string,
|
|
courseId: number,
|
|
answers: AddonModSurveySubmitAnswerData[],
|
|
siteId?: string,
|
|
): Promise<boolean> {
|
|
|
|
// Convenience function to store a survey to be synchronized later.
|
|
const storeOffline = async (): Promise<boolean> => {
|
|
await AddonModSurveyOffline.saveAnswers(surveyId, name, courseId, answers, siteId);
|
|
|
|
return false;
|
|
};
|
|
|
|
siteId = siteId || CoreSites.getCurrentSiteId();
|
|
|
|
if (!CoreApp.isOnline()) {
|
|
// App is offline, store the message.
|
|
return storeOffline();
|
|
}
|
|
|
|
try {
|
|
// If there's already answers to be sent to the server, discard it first.
|
|
await AddonModSurveyOffline.deleteSurveyAnswers(surveyId, siteId);
|
|
|
|
// Device is online, try to send them to server.
|
|
await this.submitAnswersOnline(surveyId, answers, siteId);
|
|
|
|
return true;
|
|
} catch (error) {
|
|
if (CoreUtils.isWebServiceError(error)) {
|
|
// It's a WebService error, the user cannot send the message so don't store it.
|
|
throw error;
|
|
}
|
|
|
|
return storeOffline();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send survey answers to Moodle.
|
|
*
|
|
* @param surveyId Survey ID.
|
|
* @param answers Answers.
|
|
* @param siteId Site ID. If not defined, current site.
|
|
* @return Promise resolved when answers are successfully submitted.
|
|
*/
|
|
async submitAnswersOnline(surveyId: number, answers: AddonModSurveySubmitAnswerData[], siteId?: string): Promise<void> {
|
|
const site = await CoreSites.getSite(siteId);
|
|
|
|
const params: AddonModSurveySubmitAnswersWSParams = {
|
|
surveyid: surveyId,
|
|
answers: answers,
|
|
};
|
|
|
|
const response = await site.write<CoreStatusWithWarningsWSResponse>('mod_survey_submit_answers', params);
|
|
if (!response.status) {
|
|
throw new CoreError('Error submitting answers.');
|
|
}
|
|
}
|
|
|
|
}
|
|
export const AddonModSurvey = makeSingleton(AddonModSurveyProvider);
|
|
|
|
/**
|
|
* Params of mod_survey_view_survey WS.
|
|
*/
|
|
type AddonModSurveyViewSurveyWSParams = {
|
|
surveyid: number; // Survey instance id.
|
|
};
|
|
|
|
/**
|
|
* Survey returned by WS mod_survey_get_surveys_by_courses.
|
|
*/
|
|
export type AddonModSurveySurvey = {
|
|
id: number; // Survey id.
|
|
coursemodule: number; // Course module id.
|
|
course: number; // Course id.
|
|
name: string; // Survey name.
|
|
intro?: string; // The Survey intro.
|
|
introformat?: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
|
introfiles?: CoreWSExternalFile[]; // @since 3.2.
|
|
template?: number; // Survey type.
|
|
days?: number; // Days.
|
|
questions?: string; // Question ids.
|
|
surveydone?: number; // Did I finish the survey?.
|
|
timecreated?: number; // Time of creation.
|
|
timemodified?: number; // Time of last modification.
|
|
section?: number; // Course section id.
|
|
visible?: number; // Visible.
|
|
groupmode?: number; // Group mode.
|
|
groupingid?: number; // Group id.
|
|
};
|
|
|
|
/**
|
|
* Survey question.
|
|
*/
|
|
export type AddonModSurveyQuestion = {
|
|
id: number; // Question id.
|
|
text: string; // Question text.
|
|
shorttext: string; // Question short text.
|
|
multi: string; // Subquestions ids.
|
|
intro: string; // The question intro.
|
|
type: number; // Question type.
|
|
options: string; // Question options.
|
|
parent: number; // Parent question (for subquestions).
|
|
};
|
|
|
|
/**
|
|
* Params of mod_survey_get_questions WS.
|
|
*/
|
|
type AddonModSurveyGetQuestionsWSParams = {
|
|
surveyid: number; // Survey instance id.
|
|
};
|
|
|
|
/**
|
|
* Data returned by mod_survey_get_questions WS.
|
|
*/
|
|
export type AddonModSurveyGetQuestionsWSResponse = {
|
|
questions: AddonModSurveyQuestion[];
|
|
warnings?: CoreWSExternalWarning[];
|
|
};
|
|
|
|
/**
|
|
* Params of mod_survey_get_surveys_by_courses WS.
|
|
*/
|
|
type AddonModSurveyGetSurveysByCoursesWSParams = {
|
|
courseids?: number[]; // Array of course ids.
|
|
};
|
|
|
|
/**
|
|
* Data returned by mod_survey_get_surveys_by_courses WS.
|
|
*/
|
|
export type AddonModSurveyGetSurveysByCoursesWSResponse = {
|
|
surveys: AddonModSurveySurvey[];
|
|
warnings?: CoreWSExternalWarning[];
|
|
};
|
|
|
|
export type AddonModSurveySubmitAnswerData = {
|
|
key: string; // Answer key.
|
|
value: string; // Answer value.
|
|
};
|
|
|
|
/**
|
|
* Params of mod_survey_submit_answers WS.
|
|
*/
|
|
type AddonModSurveySubmitAnswersWSParams = {
|
|
surveyid: number; // Survey id.
|
|
answers: AddonModSurveySubmitAnswerData[];
|
|
};
|