import { Survey, SurveyChoice } from "../entities/Survey"; import { DatabaseHelper, JoinType } from "./DatabaseHelper"; import { NewSurvey } from "../entities/NewSurvey"; import { mysql_date } from "../utils/DateUtils"; import { SurveyResponse } from "../entities/SurveyResponse"; import { removeHTMLNodes } from "../utils/StringUtils"; /** * Survey helper * * @author Pierre HUBERT */ /** * Survey info table */ const SURVEY_INFO_TABLE = "sondage"; /** * Survey choices table */ const SURVEY_CHOICES_TABLE = "sondage_choix"; /** * Survey responses table */ const SURVEY_RESPONSE_TABLE = "sondage_reponse"; /** * Maximum number of choices for a survey */ export const MAXIMUM_NUMBER_SURVEY_CHOICES = 20; /** * Survey helper */ export class SurveyHelper { /** * Create a new survey * * @param survey Information about the survey to create */ public static async Create(survey: NewSurvey) { // Insert main row const surveyID = await DatabaseHelper.InsertRow(SURVEY_INFO_TABLE, { ID_utilisateurs: survey.userID, ID_texte: survey.postID, date_creation: mysql_date(), question: survey.question, allow_new_choices: survey.allowNewChoices ? 1 : 0, }) // Process choices for(const choice of survey.choices) { await this.CreateChoice(surveyID, choice); } } /** * Insert a new choice for the survey * * @param surveyID The ID of the target survey * @param choice The value of the choice */ public static async CreateChoice(surveyID: number, choice: string) { await DatabaseHelper.InsertRow(SURVEY_CHOICES_TABLE, { ID_sondage: surveyID, date_creation: mysql_date(), Choix: removeHTMLNodes(choice) }); } /** * Check out whether a survey is associated to a post or not * * @param postID Target post ID */ public static async Exists(postID: number) : Promise { return await DatabaseHelper.Count({ table: SURVEY_INFO_TABLE, where: { ID_texte: postID } }) > 0 } /** * Get the ID of the survey associated with a post * * @param postID Target post ID */ public static async GetID(postID: number) : Promise { const info = await DatabaseHelper.QueryRow({ table: SURVEY_INFO_TABLE, where: { ID_texte: postID }, fields: ["ID"] }); if(info == null) throw new Error("Survey for post " + postID + " not found!"); return info.ID; } /** * Cancel the response of a user to a survey * * @param userID Target user ID * @param surveyID Target survey */ public static async CancelResponse(userID: number, surveyID: number) { await DatabaseHelper.DeleteRows(SURVEY_RESPONSE_TABLE, { ID_sondage: surveyID, ID_utilisateurs: userID }); } /** * Check out whether a choice for the survey exists or not * * @param surveyID Target survey ID * @param choiceID Target choice ID */ public static async ChoiceExists(surveyID: number, choiceID: number) : Promise { return await DatabaseHelper.Count({ table: SURVEY_CHOICES_TABLE, where: { ID_sondage: surveyID, ID: choiceID } }) > 0; } /** * Save user response to a survey * * @param userID Target user * @param surveyID Target survey * @param choiceID Selected choice */ public static async SendResponse(userID: number, surveyID: number, choiceID: number) { await DatabaseHelper.InsertRow(SURVEY_RESPONSE_TABLE, { ID_utilisateurs: userID, ID_sondage: surveyID, ID_sondage_choix: choiceID, date_envoi: mysql_date() }); } /** * Block new survey choices from being created * * @param surveyID Target survey ID */ public static async BlockNewChoicesCreation(surveyID: number) { await DatabaseHelper.UpdateRows({ table: SURVEY_INFO_TABLE, where: { "ID": surveyID }, set: { allow_new_choices: 0 } }) } /** * Delete the survey associated to a post * * @param postID Target post ID */ public static async Delete(postID: number) { const surveyID = await this.GetID(postID); await DatabaseHelper.DeleteRows(SURVEY_RESPONSE_TABLE, { ID_sondage: surveyID }); await DatabaseHelper.DeleteRows(SURVEY_CHOICES_TABLE, { ID_sondage: surveyID }); await DatabaseHelper.DeleteRows(SURVEY_INFO_TABLE, { ID: surveyID }); } /** * Get information about the survey of a post * * @param postID The ID of the associated post */ public static async GetInfo(postID: number) : Promise { // Get main information about the survey const surveyRow = await DatabaseHelper.QueryRow({ table: SURVEY_INFO_TABLE, where: { ID_texte: postID } }); if(surveyRow == null) throw new Error("Could not find survey for post " + postID + " !"); return await this.ParseDatabaseSurveyRow(surveyRow); } /** * Get information about a survey, given its ID * * @param surveyID The ID of the survey */ public static async GetInfoBySurveyID(surveyID: number) : Promise { // Get main information about the survey const surveyRow = await DatabaseHelper.QueryRow({ table: SURVEY_INFO_TABLE, where: { ID: surveyID } }); if(surveyRow == null) throw new Error("Could not find survey " + surveyID + " !"); return await this.ParseDatabaseSurveyRow(surveyRow); } /** * Turn a database row into a Survey object * * @param row Information about the survey */ private static async ParseDatabaseSurveyRow(row: any) : Promise { const survey = this.DBToSurveyInfo(row); // Get the choices of the survey const choices = await DatabaseHelper.Query({ table: SURVEY_CHOICES_TABLE, tableAlias: "c", joinType: JoinType.LEFT, joins: [ { table: SURVEY_RESPONSE_TABLE, tableAlias: "r", condition: "c.ID = r.ID_sondage_choix" } ], where: { "c.ID_sondage": survey.id }, groupBy: "c.ID", fields: ["c.*", "COUNT(r.ID) AS count_choice"] }); choices.forEach((row) => survey.choices.push(this.DBToSurveyChoice(row))); return survey; } /** * Get the choice of a user for a survey * * @param surveyID Target survey * @param userID Target user */ public static async GetUserChoice(surveyID: number, userID: number) { const result = await DatabaseHelper.QueryRow({ table: SURVEY_RESPONSE_TABLE, where: { ID_utilisateurs: userID, ID_sondage: surveyID } }); return result == null ? 0 /* no response yet */ : result.ID_sondage_choix; } /** * Export all the responses to surveys of a user * * @param userID The ID of the target user */ public static async ExportAllUserResponses(userID: number) : Promise { return (await DatabaseHelper.Query({ table: SURVEY_RESPONSE_TABLE, where: { ID_utilisateurs: userID } })).map(this.DBTosurveyResponse) } /** * Delete all user responses to surveys * * @param userID Target user ID */ public static async DeleteAllUserResponses(userID: number) { await DatabaseHelper.DeleteRows(SURVEY_RESPONSE_TABLE, { ID_utilisateurs: userID }); } /** * Turn a database entry into a survey object * * @param row The row to transform */ private static DBToSurveyInfo(row: any) : Survey { return new Survey({ id: row.ID, userID: row.ID_utilisateurs, postID: row.ID_texte, timeCreate: new Date(row.date_creation).getTime()/1000, question: row.question, choices: [], allowNewChoices: row.allow_new_choices == 1, }); } /** * Turn a database entry into a survey choice * * @param row The row to transform */ private static DBToSurveyChoice(row: any) : SurveyChoice { return { id: row.ID, name: row.Choix, count: row.count_choice }; } /** * Turn a database entry into a survey response object * * @param row The row */ private static DBTosurveyResponse(row: any) : SurveyResponse { return new SurveyResponse({ id: row.ID, timeSent: new Date(row.date_envoi).getTime()/1000, userID: row.ID_utilisateurs, surveyID: row.ID_sondage, choiceID: row.ID_sondage_choix }); } }