// swad_survey.c: surveys /* SWAD (Shared Workspace At a Distance), is a web platform developed at the University of Granada (Spain), and used to support university teaching. This file is part of SWAD core. Copyright (C) 1999-2019 Antonio Caņas Vargas This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ /*****************************************************************************/ /********************************* Headers ***********************************/ /*****************************************************************************/ #define _GNU_SOURCE // For asprintf #include // For PATH_MAX #include // For NULL #include // For asprintf #include // For calloc #include // For string functions #include "swad_box.h" #include "swad_database.h" #include "swad_form.h" #include "swad_global.h" #include "swad_group.h" #include "swad_HTML.h" #include "swad_notification.h" #include "swad_pagination.h" #include "swad_parameter.h" #include "swad_role.h" #include "swad_setting.h" #include "swad_survey.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /***************************** Private constants *****************************/ /*****************************************************************************/ #define Svy_MAX_CHARS_ANSWER (1024 - 1) // 1023 #define Svy_MAX_BYTES_ANSWER ((Svy_MAX_CHARS_ANSWER + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 16383 #define Svy_MAX_BYTES_LIST_ANSWER_TYPES (10 + (Svy_NUM_ANS_TYPES - 1) * (1 + 10)) const char *Svy_StrAnswerTypesDB[Svy_NUM_ANS_TYPES] = { "unique_choice", "multiple_choice", }; #define Svy_MAX_ANSWERS_PER_QUESTION 10 struct SurveyQuestion // Must be initialized to 0 before using it { long QstCod; unsigned QstInd; Svy_AnswerType_t AnswerType; struct { char *Text; } AnsChoice[Svy_MAX_ANSWERS_PER_QUESTION]; bool AllAnsTypes; char ListAnsTypes[Svy_MAX_BYTES_LIST_ANSWER_TYPES + 1]; }; /*****************************************************************************/ /******************************* Private types *******************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private variables *****************************/ /*****************************************************************************/ long Svy_CurrentSvyCod; // Used as parameter in contextual links long Svy_CurrentQstCod; // Used as parameter in contextual links /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void Svy_ListAllSurveys (struct SurveyQuestion *SvyQst); static bool Svy_CheckIfICanCreateSvy (void); static void Svy_PutIconsListSurveys (void); static void Svy_PutIconToCreateNewSvy (void); static void Svy_PutButtonToCreateNewSvy (void); static void Svy_PutParamsToCreateNewSvy (void); static void Svy_ParamsWhichGroupsToShow (void); static void Svy_ShowOneSurvey (long SvyCod,struct SurveyQuestion *SvyQst, bool ShowOnlyThisSvyComplete); static void Svy_WriteAuthor (struct Survey *Svy); static void Svy_WriteStatus (struct Survey *Svy); static void Svy_GetParamSvyOrder (void); static void Svy_PutFormsToRemEditOneSvy (const struct Survey *Svy, const char *Anchor); static void Svy_PutParams (void); static void Svy_GetListSurveys (void); static void Svy_SetAllowedAndHiddenScopes (unsigned *ScopesAllowed, unsigned *HiddenAllowed); static void Svy_GetSurveyTxtFromDB (long SvyCod,char Txt[Cns_MAX_BYTES_TEXT + 1]); static void Svy_PutParamSvyCod (long SvyCod); static long Svy_GetParamSvyCod (void); static void Svy_PutButtonToResetSurvey (void); static bool Svy_CheckIfSimilarSurveyExists (struct Survey *Svy); static void Svy_SetDefaultAndAllowedScope (struct Survey *Svy); static void Svy_ShowLstGrpsToEditSurvey (long SvyCod); static void Svy_UpdateNumUsrsNotifiedByEMailAboutSurvey (long SvyCod, unsigned NumUsrsToBeNotifiedByEMail); static void Svy_CreateSurvey (struct Survey *Svy,const char *Txt); static void Svy_UpdateSurvey (struct Survey *Svy,const char *Txt); static bool Svy_CheckIfSvyIsAssociatedToGrps (long SvyCod); static void Svy_RemoveAllTheGrpsAssociatedToAndSurvey (long SvyCod); static void Svy_CreateGrps (long SvyCod); static void Svy_GetAndWriteNamesOfGrpsAssociatedToSvy (struct Survey *Svy); static bool Svy_CheckIfICanDoThisSurveyBasedOnGrps (long SvyCod); static unsigned Svy_GetNumQstsSvy (long SvyCod); static void Svy_ShowFormEditOneQst (long SvyCod,struct SurveyQuestion *SvyQst, char Txt[Cns_MAX_BYTES_TEXT + 1]); static void Svy_InitQst (struct SurveyQuestion *SvyQst); static void Svy_PutParamQstCod (long QstCod); static long Svy_GetParamQstCod (void); static void Svy_RemAnswersOfAQuestion (long QstCod); static Svy_AnswerType_t Svy_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD); static bool Svy_CheckIfAnswerExists (long QstCod,unsigned AnsInd); static unsigned Svy_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res); static bool Svy_AllocateTextChoiceAnswer (struct SurveyQuestion *SvyQst,unsigned NumAns); static void Svy_FreeTextChoiceAnswers (struct SurveyQuestion *SvyQst,unsigned NumAnswers); static void Svy_FreeTextChoiceAnswer (struct SurveyQuestion *SvyQst,unsigned NumAns); static unsigned Svy_GetQstIndFromQstCod (long QstCod); static unsigned Svy_GetNextQuestionIndexInSvy (long SvyCod); static void Svy_ListSvyQuestions (struct Survey *Svy, struct SurveyQuestion *SvyQst); static void Svy_PutParamsToEditQuestion (void); static void Svy_PutIconToAddNewQuestion (void); static void Svy_PutButtonToCreateNewQuestion (void); static void Svy_WriteQstStem (const char *Stem); static void Svy_WriteAnswersOfAQst (struct Survey *Svy, struct SurveyQuestion *SvyQst, bool PutFormAnswerSurvey); static void Svy_DrawBarNumUsrs (unsigned NumUsrs,unsigned MaxUsrs); static void Svy_PutIconToRemoveOneQst (void); static void Svy_PutParamsRemoveOneQst (void); static void Svy_ReceiveAndStoreUserAnswersToASurvey (long SvyCod); static void Svy_IncreaseAnswerInDB (long QstCod,unsigned AnsInd); static void Svy_RegisterIHaveAnsweredSvy (long SvyCod); static bool Svy_CheckIfIHaveAnsweredSvy (long SvyCod); static unsigned Svy_GetNumUsrsWhoHaveAnsweredSvy (long SvyCod); /*****************************************************************************/ /***************************** List all surveys ******************************/ /*****************************************************************************/ void Svy_SeeAllSurveys (void) { struct SurveyQuestion SvyQst; /***** Initialize question to zero *****/ Svy_InitQst (&SvyQst); /***** Get parameters *****/ Svy_GetParamSvyOrder (); Grp_GetParamWhichGrps (); Gbl.Svys.CurrentPage = Pag_GetParamPagNum (Pag_SURVEYS); /***** Show all surveys *****/ Svy_ListAllSurveys (&SvyQst); } /*****************************************************************************/ /*************************** Show all the surveys ****************************/ /*****************************************************************************/ static void Svy_ListAllSurveys (struct SurveyQuestion *SvyQst) { extern const char *Hlp_ASSESSMENT_Surveys; extern const char *Txt_Surveys; extern const char *Txt_START_END_TIME_HELP[Dat_NUM_START_END_TIME]; extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME]; extern const char *Txt_Survey; extern const char *Txt_Status; extern const char *Txt_No_surveys; Svy_Order_t Order; struct Pagination Pagination; unsigned NumSvy; /***** Get number of groups in current course *****/ if (!Gbl.Crs.Grps.NumGrps) Gbl.Crs.Grps.WhichGrps = Grp_ALL_GROUPS; /***** Get list of surveys *****/ Svy_GetListSurveys (); /***** Compute variables related to pagination *****/ Pagination.NumItems = Gbl.Svys.Num; Pagination.CurrentPage = (int) Gbl.Svys.CurrentPage; Pag_CalculatePagination (&Pagination); Gbl.Svys.CurrentPage = (unsigned) Pagination.CurrentPage; /***** Write links to pages *****/ if (Pagination.MoreThanOnePage) Pag_WriteLinksToPagesCentered (Pag_SURVEYS, 0, &Pagination); /***** Begin box *****/ Box_BoxBegin ("100%",Txt_Surveys,Svy_PutIconsListSurveys, Hlp_ASSESSMENT_Surveys,Box_NOT_CLOSABLE); /***** Select whether show only my groups or all groups *****/ if (Gbl.Crs.Grps.NumGrps) { Set_StartSettingsHead (); Grp_ShowFormToSelWhichGrps (ActSeeAllSvy,Svy_ParamsWhichGroupsToShow); Set_EndSettingsHead (); } if (Gbl.Svys.Num) { /***** Table head *****/ HTM_TABLE_BeginWideMarginPadding (2); HTM_TR_Begin (NULL); HTM_TH (1,1,"CONTEXT_COL",NULL); // Column for contextual icons for (Order = Svy_ORDER_BY_START_DATE; Order <= Svy_ORDER_BY_END_DATE; Order++) { HTM_TH_Begin (1,1,"LM"); /* Form to change order */ Frm_StartForm (ActSeeAllSvy); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Pag_SURVEYS,Gbl.Svys.CurrentPage); Par_PutHiddenParamUnsigned ("Order",(unsigned) Order); Frm_LinkFormSubmit (Txt_START_END_TIME_HELP[Order],"TIT_TBL",NULL); if (Order == Gbl.Svys.SelectedOrder) fprintf (Gbl.F.Out,""); fprintf (Gbl.F.Out,"%s",Txt_START_END_TIME[Order]); if (Order == Gbl.Svys.SelectedOrder) fprintf (Gbl.F.Out,""); Frm_LinkFormEnd (); Frm_EndForm (); HTM_TH_End (); } HTM_TH (1,1,"LM",Txt_Survey); HTM_TH (1,1,"CM",Txt_Status); HTM_TR_End (); /***** Write all the surveys *****/ for (NumSvy = Pagination.FirstItemVisible; NumSvy <= Pagination.LastItemVisible; NumSvy++) Svy_ShowOneSurvey (Gbl.Svys.LstSvyCods[NumSvy - 1],SvyQst,false); /***** End table *****/ HTM_TABLE_End (); } else // No surveys created Ale_ShowAlert (Ale_INFO,Txt_No_surveys); /***** Button to create a new survey *****/ if (Svy_CheckIfICanCreateSvy ()) Svy_PutButtonToCreateNewSvy (); /***** End box *****/ Box_BoxEnd (); /***** Write again links to pages *****/ if (Pagination.MoreThanOnePage) Pag_WriteLinksToPagesCentered (Pag_SURVEYS, 0, &Pagination); /***** Free list of surveys *****/ Svy_FreeListSurveys (); } /*****************************************************************************/ /******************* Check if I can create a new survey **********************/ /*****************************************************************************/ static bool Svy_CheckIfICanCreateSvy (void) { switch (Gbl.Usrs.Me.Role.Logged) { case Rol_TCH: case Rol_DEG_ADM: case Rol_CTR_ADM: case Rol_INS_ADM: case Rol_SYS_ADM: return true; default: return false; } return false; } /*****************************************************************************/ /***************** Put contextual icons in list of surveys *******************/ /*****************************************************************************/ static void Svy_PutIconsListSurveys (void) { /***** Put icon to create a new survey *****/ if (Svy_CheckIfICanCreateSvy ()) Svy_PutIconToCreateNewSvy (); /***** Put icon to show a figure *****/ Gbl.Figures.FigureType = Fig_SURVEYS; Fig_PutIconToShowFigure (); } /*****************************************************************************/ /********************** Put icon to create a new survey **********************/ /*****************************************************************************/ static void Svy_PutIconToCreateNewSvy (void) { extern const char *Txt_New_survey; Ico_PutContextualIconToAdd (ActFrmNewSvy,NULL,Svy_PutParamsToCreateNewSvy, Txt_New_survey); } /*****************************************************************************/ /********************* Put button to create a new survey *********************/ /*****************************************************************************/ static void Svy_PutButtonToCreateNewSvy (void) { extern const char *Txt_New_survey; Frm_StartForm (ActFrmNewSvy); Svy_PutParamsToCreateNewSvy (); Btn_PutConfirmButton (Txt_New_survey); Frm_EndForm (); } /*****************************************************************************/ /******************* Put parameters to create a new survey *******************/ /*****************************************************************************/ static void Svy_PutParamsToCreateNewSvy (void) { Svy_PutHiddenParamSvyOrder (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Pag_SURVEYS,Gbl.Svys.CurrentPage); } /*****************************************************************************/ /**************** Put params to select which groups to show ******************/ /*****************************************************************************/ static void Svy_ParamsWhichGroupsToShow (void) { Svy_PutHiddenParamSvyOrder (); Pag_PutHiddenParamPagNum (Pag_SURVEYS,Gbl.Svys.CurrentPage); } /*****************************************************************************/ /****************************** Show one survey ******************************/ /*****************************************************************************/ void Svy_SeeOneSurvey (void) { struct Survey Svy; struct SurveyQuestion SvyQst; /***** Initialize question to zero *****/ Svy_InitQst (&SvyQst); /***** Get parameters *****/ Svy_GetParamSvyOrder (); Grp_GetParamWhichGrps (); Gbl.Svys.CurrentPage = Pag_GetParamPagNum (Pag_SURVEYS); /***** Get survey code *****/ if ((Svy.SvyCod = Svy_GetParamSvyCod ()) == -1L) Lay_ShowErrorAndExit ("Code of survey is missing."); /***** Show survey *****/ Svy_ShowOneSurvey (Svy.SvyCod,&SvyQst,true); } /*****************************************************************************/ /****************************** Show one survey ******************************/ /*****************************************************************************/ static void Svy_ShowOneSurvey (long SvyCod,struct SurveyQuestion *SvyQst, bool ShowOnlyThisSvyComplete) { extern const char *Hlp_ASSESSMENT_Surveys; extern const char *Txt_Survey; extern const char *Txt_View_survey; extern const char *Txt_No_of_questions; extern const char *Txt_No_of_users; extern const char *Txt_Scope; extern const char *Txt_Country; extern const char *Txt_Institution; extern const char *Txt_Centre; extern const char *Txt_Degree; extern const char *Txt_Course; extern const char *Txt_Users; extern const char *Txt_Answer_survey; extern const char *Txt_View_survey_results; char *Anchor = NULL; static unsigned UniqueId = 0; char *Id; struct Survey Svy; char Txt[Cns_MAX_BYTES_TEXT + 1]; /***** Begin box *****/ if (ShowOnlyThisSvyComplete) Box_BoxBegin (NULL,Txt_Survey,NULL, Hlp_ASSESSMENT_Surveys,Box_NOT_CLOSABLE); /***** Get data of this survey *****/ Svy.SvyCod = SvyCod; Svy_GetDataOfSurveyByCod (&Svy); /***** Set anchor string *****/ Frm_SetAnchorStr (Svy.SvyCod,&Anchor); /***** Begin table *****/ if (ShowOnlyThisSvyComplete) HTM_TABLE_BeginWidePadding (2); /***** Write first row of data of this assignment *****/ HTM_TR_Begin (NULL); /* Forms to remove/edit this assignment */ if (ShowOnlyThisSvyComplete) HTM_TD_Begin ("rowspan=\"2\" class=\"CONTEXT_COL\""); else HTM_TD_Begin ("rowspan=\"2\" class=\"CONTEXT_COL COLOR%u\"",Gbl.RowEvenOdd); if (Svy.Status.ICanEdit) Svy_PutFormsToRemEditOneSvy (&Svy,Anchor); HTM_TD_End (); /* Start date/time */ UniqueId++; if (asprintf (&Id,"svy_date_start_%u",UniqueId) < 0) Lay_NotEnoughMemoryExit (); if (ShowOnlyThisSvyComplete) HTM_TD_Begin ("id=\"%s\" class=\"%s LT\"", Id, Svy.Status.Visible ? (Svy.Status.Open ? "DATE_GREEN" : "DATE_RED") : (Svy.Status.Open ? "DATE_GREEN_LIGHT" : "DATE_RED_LIGHT")); else HTM_TD_Begin ("id=\"%s\" class=\"%s LT COLOR%u\"", Id, Svy.Status.Visible ? (Svy.Status.Open ? "DATE_GREEN" : "DATE_RED") : (Svy.Status.Open ? "DATE_GREEN_LIGHT" : "DATE_RED_LIGHT"), Gbl.RowEvenOdd); Dat_WriteLocalDateHMSFromUTC (Id,Svy.TimeUTC[Svy_START_TIME], Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK, true,true,true,0x7); HTM_TD_End (); free ((void *) Id); /* End date/time */ if (asprintf (&Id,"svy_date_end_%u",UniqueId) < 0) Lay_NotEnoughMemoryExit (); if (ShowOnlyThisSvyComplete) HTM_TD_Begin ("id=\"%s\" class=\"%s LT\"", Id, Svy.Status.Visible ? (Svy.Status.Open ? "DATE_GREEN" : "DATE_RED") : (Svy.Status.Open ? "DATE_GREEN_LIGHT" : "DATE_RED_LIGHT")); else HTM_TD_Begin ("id=\"%s\" class=\"%s LT COLOR%u\"", Id, Svy.Status.Visible ? (Svy.Status.Open ? "DATE_GREEN" : "DATE_RED") : (Svy.Status.Open ? "DATE_GREEN_LIGHT" : "DATE_RED_LIGHT"), Gbl.RowEvenOdd); Dat_WriteLocalDateHMSFromUTC (Id,Svy.TimeUTC[Svy_END_TIME], Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK, true,false,true,0x7); HTM_TD_End (); free ((void *) Id); /* Survey title */ if (ShowOnlyThisSvyComplete) HTM_TD_Begin ("class=\"LT\""); else HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); HTM_ARTICLE_Begin (Anchor); Frm_StartForm (ActSeeSvy); Svy_PutParamSvyCod (SvyCod); Svy_PutHiddenParamSvyOrder (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Pag_SURVEYS,Gbl.Svys.CurrentPage); Frm_LinkFormSubmit (Txt_View_survey, Svy.Status.Visible ? "ASG_TITLE" : "ASG_TITLE_LIGHT",NULL); fprintf (Gbl.F.Out,"%s",Svy.Title); Frm_LinkFormEnd (); Frm_EndForm (); HTM_ARTICLE_End (); /* Number of questions and number of distinct users who have already answered this survey */ HTM_DIV_Begin ("class=\"%s\"", Svy.Status.Visible ? "ASG_GRP" : "ASG_GRP_LIGHT"); fprintf (Gbl.F.Out,"%s: %u; %s: %u", Txt_No_of_questions, Svy.NumQsts, Txt_No_of_users, Svy.NumUsrs); HTM_DIV_End (); HTM_TD_End (); /* Status of the survey */ if (ShowOnlyThisSvyComplete) HTM_TD_Begin ("rowspan=\"2\" class=\"LT\""); else HTM_TD_Begin ("rowspan=\"2\" class=\"LT COLOR%u\"",Gbl.RowEvenOdd); Svy_WriteStatus (&Svy); if (!ShowOnlyThisSvyComplete) { /* Possible button to answer this survey */ if (Svy.Status.ICanAnswer) { HTM_DIV_Begin ("class=\"BUTTONS_AFTER_ALERT\""); Frm_StartForm (ActSeeSvy); Svy_PutParamSvyCod (Svy.SvyCod); Svy_PutHiddenParamSvyOrder (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Pag_SURVEYS,Gbl.Svys.CurrentPage); Btn_PutCreateButtonInline (Txt_Answer_survey); Frm_EndForm (); HTM_DIV_End (); } /* Possible button to see the result of the survey */ else if (Svy.Status.ICanViewResults) { HTM_DIV_Begin ("class=\"BUTTONS_AFTER_ALERT\""); Frm_StartForm (ActSeeSvy); Svy_PutParamSvyCod (Svy.SvyCod); Svy_PutHiddenParamSvyOrder (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Pag_SURVEYS,Gbl.Svys.CurrentPage); Btn_PutConfirmButtonInline (Txt_View_survey_results); Frm_EndForm (); HTM_DIV_End (); } } HTM_TD_End (); HTM_TR_End (); /***** Write second row of data of this survey *****/ HTM_TR_Begin (NULL); /* 1st column: Author of the survey */ if (ShowOnlyThisSvyComplete) HTM_TD_Begin ("colspan=\"2\" class=\"LT\""); else HTM_TD_Begin ("colspan=\"2\" class=\"LT COLOR%u\"",Gbl.RowEvenOdd); Svy_WriteAuthor (&Svy); HTM_TD_End (); /* 2nd column: Scope, Users, Groups and Text */ if (ShowOnlyThisSvyComplete) HTM_TD_Begin ("class=\"LT\""); else HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); /* Scope of the survey */ HTM_DIV_Begin ("class=\"%s\"",Svy.Status.Visible ? "ASG_GRP" : "ASG_GRP_LIGHT"); fprintf (Gbl.F.Out,"%s: ",Txt_Scope); switch (Svy.Scope) { case Hie_UNK: // Unknown Lay_ShowErrorAndExit ("Wrong survey scope."); break; case Hie_SYS: // System fprintf (Gbl.F.Out,"%s",Cfg_PLATFORM_SHORT_NAME); break; case Hie_CTY: // Country fprintf (Gbl.F.Out,"%s %s",Txt_Country,Gbl.Hierarchy.Cty.Name[Gbl.Prefs.Language]); break; case Hie_INS: // Institution fprintf (Gbl.F.Out,"%s %s",Txt_Institution,Gbl.Hierarchy.Ins.ShrtName); break; case Hie_CTR: // Centre fprintf (Gbl.F.Out,"%s %s",Txt_Centre,Gbl.Hierarchy.Ctr.ShrtName); break; case Hie_DEG: // Degree fprintf (Gbl.F.Out,"%s %s",Txt_Degree,Gbl.Hierarchy.Deg.ShrtName); break; case Hie_CRS: // Course fprintf (Gbl.F.Out,"%s %s",Txt_Course,Gbl.Hierarchy.Crs.ShrtName); break; } HTM_DIV_End (); /* Users' roles who can answer the survey */ HTM_DIV_Begin ("class=\"%s\"",Svy.Status.Visible ? "ASG_GRP" : "ASG_GRP_LIGHT"); fprintf (Gbl.F.Out,"%s:
",Txt_Users); Rol_WriteSelectorRoles (1 << Rol_STD | 1 << Rol_NET | 1 << Rol_TCH, Svy.Roles, true,false); HTM_DIV_End (); /* Groups whose users can answer this survey */ if (Svy.Scope == Hie_CRS) if (Gbl.Crs.Grps.NumGrps) Svy_GetAndWriteNamesOfGrpsAssociatedToSvy (&Svy); /* Text of the survey */ Svy_GetSurveyTxtFromDB (Svy.SvyCod,Txt); Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Txt,Cns_MAX_BYTES_TEXT,false); // Convert from HTML to rigorous HTML Str_InsertLinks (Txt,Cns_MAX_BYTES_TEXT,60); // Insert links HTM_DIV_Begin ("class=\"PAR %s\"",Svy.Status.Visible ? "DAT" : "DAT_LIGHT"); fprintf (Gbl.F.Out,"%s",Txt); HTM_DIV_End (); HTM_TD_End (); HTM_TR_End (); /***** Write questions of this survey *****/ if (ShowOnlyThisSvyComplete) { HTM_TR_Begin (NULL); HTM_TD_Begin ("colspan=\"5\""); Svy_ListSvyQuestions (&Svy,SvyQst); HTM_TD_End (); HTM_TR_End (); } Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; /***** Mark possible notification as seen *****/ if (Svy.Scope == Hie_CRS) // Only course surveys are notified Ntf_MarkNotifAsSeen (Ntf_EVENT_SURVEY, SvyCod,Svy.Cod, Gbl.Usrs.Me.UsrDat.UsrCod); if (ShowOnlyThisSvyComplete) { /***** End table *****/ HTM_TABLE_End (); /***** End box *****/ Box_BoxEnd (); } /***** Free anchor string *****/ Frm_FreeAnchorStr (Anchor); } /*****************************************************************************/ /*********************** Write the author of a survey ************************/ /*****************************************************************************/ static void Svy_WriteAuthor (struct Survey *Svy) { Usr_WriteAuthor1Line (Svy->UsrCod,!Svy->Status.Visible); } /*****************************************************************************/ /************************ Write status of a survey ***************************/ /*****************************************************************************/ static void Svy_WriteStatus (struct Survey *Svy) { extern const char *Txt_Hidden_survey; extern const char *Txt_Visible_survey; extern const char *Txt_Closed_survey; extern const char *Txt_Open_survey; extern const char *Txt_SURVEY_Type_of_user_not_allowed; extern const char *Txt_SURVEY_Type_of_user_allowed; extern const char *Txt_SURVEY_You_belong_to_the_scope_of_the_survey; extern const char *Txt_SURVEY_You_dont_belong_to_the_scope_of_the_survey; extern const char *Txt_SURVEY_You_have_already_answered; extern const char *Txt_SURVEY_You_have_not_answered; /***** Start list with items of status *****/ HTM_UL_Begin (NULL); /* Write whether survey is visible or hidden */ if (Svy->Status.Visible) { HTM_LI_Begin ("class=\"STATUS_GREEN\""); fprintf (Gbl.F.Out,"%s",Txt_Visible_survey); } else { HTM_LI_Begin ("class=\"STATUS_RED_LIGHT\""); fprintf (Gbl.F.Out,"%s",Txt_Hidden_survey); } HTM_LI_End (); /* Write whether survey is open or closed */ if (Svy->Status.Open) { HTM_LI_Begin ("class=\"%s\"", Svy->Status.Visible ? "STATUS_GREEN" : "STATUS_GREEN_LIGHT"); fprintf (Gbl.F.Out,"%s",Txt_Open_survey); } else { HTM_LI_Begin ("class=\"%s\"", Svy->Status.Visible ? "STATUS_RED" : "STATUS_RED_LIGHT"); fprintf (Gbl.F.Out,"%s",Txt_Closed_survey); } HTM_LI_End (); /* Write whether survey can be answered by me or not depending on user type */ if (Svy->Status.IAmLoggedWithAValidRoleToAnswer) { HTM_LI_Begin ("class=\"%s\"", Svy->Status.Visible ? "STATUS_GREEN" : "STATUS_GREEN_LIGHT"); fprintf (Gbl.F.Out,"%s",Txt_SURVEY_Type_of_user_allowed); } else { HTM_LI_Begin ("class=\"%s\"", Svy->Status.Visible ? "STATUS_RED" : "STATUS_RED_LIGHT"); fprintf (Gbl.F.Out,"%s",Txt_SURVEY_Type_of_user_not_allowed); } HTM_LI_End (); /* Write whether survey can be answered by me or not depending on groups */ if (Svy->Status.IBelongToScope) { HTM_LI_Begin ("class=\"%s\"", Svy->Status.Visible ? "STATUS_GREEN" : "STATUS_GREEN_LIGHT"); fprintf (Gbl.F.Out,"%s",Txt_SURVEY_You_belong_to_the_scope_of_the_survey); } else { HTM_LI_Begin ("class=\"%s\"", Svy->Status.Visible ? "STATUS_RED" : "STATUS_RED_LIGHT"); fprintf (Gbl.F.Out,"%s",Txt_SURVEY_You_dont_belong_to_the_scope_of_the_survey); } HTM_LI_End (); /* Write whether survey has been already answered by me or not */ if (Svy->Status.IHaveAnswered) { HTM_LI_Begin ("class=\"%s\"", Svy->Status.Visible ? "STATUS_GREEN" : "STATUS_GREEN_LIGHT"); fprintf (Gbl.F.Out,"%s",Txt_SURVEY_You_have_already_answered); } else { HTM_LI_Begin ("class=\"%s\"", Svy->Status.Visible ? "STATUS_RED" : "STATUS_RED_LIGHT"); fprintf (Gbl.F.Out,"%s",Txt_SURVEY_You_have_not_answered); } HTM_LI_End (); /***** End list with items of status *****/ HTM_UL_End (); } /*****************************************************************************/ /********* Get parameter with the type or order in list of surveys ***********/ /*****************************************************************************/ static void Svy_GetParamSvyOrder (void) { Gbl.Svys.SelectedOrder = (Svy_Order_t) Par_GetParToUnsignedLong ("Order", 0, Svy_NUM_ORDERS - 1, (unsigned long) Svy_ORDER_DEFAULT); } /*****************************************************************************/ /***** Put a hidden parameter with the type of order in list of surveys ******/ /*****************************************************************************/ void Svy_PutHiddenParamSvyOrder (void) { Par_PutHiddenParamUnsigned ("Order",(unsigned) Gbl.Svys.SelectedOrder); } /*****************************************************************************/ /******************* Put a link (form) to edit one survey ********************/ /*****************************************************************************/ static void Svy_PutFormsToRemEditOneSvy (const struct Survey *Svy, const char *Anchor) { extern const char *Txt_Reset; Svy_CurrentSvyCod = Svy->SvyCod; // Used as parameters in contextual links /***** Put form to remove survey *****/ Ico_PutContextualIconToRemove (ActReqRemSvy,Svy_PutParams); /***** Put form to reset survey *****/ Lay_PutContextualLinkOnlyIcon (ActReqRstSvy,NULL,Svy_PutParams, "recycle.svg", Txt_Reset); /***** Put form to hide/show survey *****/ if (Svy->Status.Visible) Ico_PutContextualIconToHide (ActHidSvy,Anchor,Svy_PutParams); else Ico_PutContextualIconToUnhide (ActShoSvy,Anchor,Svy_PutParams); /***** Put form to edit survey *****/ Ico_PutContextualIconToEdit (ActEdiOneSvy,Svy_PutParams); } /*****************************************************************************/ /********************** Params used to edit a survey *************************/ /*****************************************************************************/ static void Svy_PutParams (void) { if (Svy_CurrentSvyCod > 0) Svy_PutParamSvyCod (Svy_CurrentSvyCod); Att_PutHiddenParamAttOrder (); Grp_PutParamWhichGrps (); Pag_PutHiddenParamPagNum (Pag_SURVEYS,Gbl.Svys.CurrentPage); } /*****************************************************************************/ /*********************** Get list of all the surveys *************************/ /*****************************************************************************/ static void Svy_GetListSurveys (void) { char *SubQuery[Hie_NUM_LEVELS]; static const char *OrderBySubQuery[Svy_NUM_ORDERS] = { "StartTime DESC,EndTime DESC,Title DESC", // Svy_ORDER_BY_START_DATE "EndTime DESC,StartTime DESC,Title DESC", // Svy_ORDER_BY_END_DATE }; MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned long NumRows; unsigned NumSvy; unsigned ScopesAllowed = 0; unsigned HiddenAllowed = 0; long Cods[Hie_NUM_LEVELS]; Hie_Level_t Scope; bool SubQueryFilled = false; /***** Free list of surveys *****/ if (Gbl.Svys.LstIsRead) Svy_FreeListSurveys (); /***** Set allowed and hidden scopes to get list depending on my user's role *****/ Svy_SetAllowedAndHiddenScopes (&ScopesAllowed,&HiddenAllowed); /***** Get list of surveys from database *****/ Cods[Hie_SYS] = -1L; // System Cods[Hie_CTY] = Gbl.Hierarchy.Cty.CtyCod; // Country Cods[Hie_INS] = Gbl.Hierarchy.Ins.InsCod; // Institution Cods[Hie_CTR] = Gbl.Hierarchy.Ctr.CtrCod; // Centre Cods[Hie_DEG] = Gbl.Hierarchy.Deg.DegCod; // Degree Cods[Hie_CRS] = Gbl.Hierarchy.Crs.CrsCod; // Course /* Fill subqueries for system, country, institution, centre and degree */ for (Scope = Hie_SYS; Scope <= Hie_DEG; Scope++) if (ScopesAllowed & 1 << Scope) { if (asprintf (&SubQuery[Scope],"%s(Scope='%s' AND Cod=%ld%s)", SubQueryFilled ? " OR " : "", Sco_GetDBStrFromScope (Scope),Cods[Scope], (HiddenAllowed & 1 << Scope) ? "" : " AND Hidden='N'") < 0) Lay_NotEnoughMemoryExit (); SubQueryFilled = true; } else { if (asprintf (&SubQuery[Scope],"%s","") < 0) Lay_NotEnoughMemoryExit (); } /* Fill subquery for course */ if (ScopesAllowed & 1 << Hie_CRS) { if (Gbl.Crs.Grps.WhichGrps == Grp_MY_GROUPS) { if (asprintf (&SubQuery[Hie_CRS],"%s(" "Scope='%s' AND Cod=%ld%s" " AND " "(SvyCod NOT IN" " (SELECT SvyCod FROM svy_grp)" " OR" " SvyCod IN" " (SELECT svy_grp.SvyCod" " FROM svy_grp,crs_grp_usr" " WHERE crs_grp_usr.UsrCod=%ld" " AND svy_grp.GrpCod=crs_grp_usr.GrpCod))" ")", SubQueryFilled ? " OR " : "", Sco_GetDBStrFromScope (Hie_CRS),Cods[Hie_CRS], (HiddenAllowed & 1 << Hie_CRS) ? "" : " AND Hidden='N'", Gbl.Usrs.Me.UsrDat.UsrCod) < 0) Lay_NotEnoughMemoryExit (); } else // Gbl.Crs.Grps.WhichGrps == Grp_ALL_GROUPS { if (asprintf (&SubQuery[Hie_CRS],"%s(Scope='%s' AND Cod=%ld%s)", SubQueryFilled ? " OR " : "", Sco_GetDBStrFromScope (Hie_CRS),Cods[Hie_CRS], (HiddenAllowed & 1 << Hie_CRS) ? "" : " AND Hidden='N'") < 0) Lay_NotEnoughMemoryExit (); } SubQueryFilled = true; } else { if (asprintf (&SubQuery[Hie_CRS],"%s","") < 0) Lay_NotEnoughMemoryExit (); } /* Make query */ if (SubQueryFilled) NumRows = DB_QuerySELECT (&mysql_res,"can not get surveys", "SELECT SvyCod FROM surveys" " WHERE %s%s%s%s%s%s" " ORDER BY %s", SubQuery[Hie_SYS], SubQuery[Hie_CTY], SubQuery[Hie_INS], SubQuery[Hie_CTR], SubQuery[Hie_DEG], SubQuery[Hie_CRS], OrderBySubQuery[Gbl.Svys.SelectedOrder]); else { Lay_ShowErrorAndExit ("Can not get list of surveys."); NumRows = 0; // Not reached. Initialized to avoid warning } /* Free allocated memory for subqueries */ for (Scope = Hie_SYS; Scope <= Hie_CRS; Scope++) free ((void *) SubQuery[Scope]); if (NumRows) // Surveys found... { Gbl.Svys.Num = (unsigned) NumRows; /***** Create list of surveys *****/ if ((Gbl.Svys.LstSvyCods = (long *) calloc (NumRows,sizeof (long))) == NULL) Lay_NotEnoughMemoryExit (); /***** Get the surveys codes *****/ for (NumSvy = 0; NumSvy < Gbl.Svys.Num; NumSvy++) { /* Get next survey code */ row = mysql_fetch_row (mysql_res); if ((Gbl.Svys.LstSvyCods[NumSvy] = Str_ConvertStrCodToLongCod (row[0])) < 0) Lay_ShowErrorAndExit ("Error: wrong survey code."); } } else Gbl.Svys.Num = 0; /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); Gbl.Svys.LstIsRead = true; } /*****************************************************************************/ /*** Set allowed and hidden scopes to get list depending on my user's role ***/ /*****************************************************************************/ static void Svy_SetAllowedAndHiddenScopes (unsigned *ScopesAllowed, unsigned *HiddenAllowed) { switch (Gbl.Usrs.Me.Role.Logged) { case Rol_UNK: // User not logged in ********************************* *ScopesAllowed = 0; *HiddenAllowed = 0; break; case Rol_GST: // User not belonging to any course ******************* *ScopesAllowed = 1 << Hie_SYS; *HiddenAllowed = 0; break; case Rol_USR: // Student or teacher in other courses... // ...but not belonging to the current course ********* *ScopesAllowed = 1 << Hie_SYS; *HiddenAllowed = 0; if (Usr_CheckIfIBelongToCty (Gbl.Hierarchy.Cty.CtyCod)) { *ScopesAllowed |= 1 << Hie_CTY; if (Usr_CheckIfIBelongToIns (Gbl.Hierarchy.Ins.InsCod)) { *ScopesAllowed |= 1 << Hie_INS; if (Usr_CheckIfIBelongToCtr (Gbl.Hierarchy.Ctr.CtrCod)) { *ScopesAllowed |= 1 << Hie_CTR; if (Usr_CheckIfIBelongToDeg (Gbl.Hierarchy.Deg.DegCod)) *ScopesAllowed |= 1 << Hie_DEG; } } } break; case Rol_STD: // Student in current course ************************** *ScopesAllowed = 1 << Hie_SYS; *HiddenAllowed = 0; if (Usr_CheckIfIBelongToCty (Gbl.Hierarchy.Cty.CtyCod)) { *ScopesAllowed |= 1 << Hie_CTY; if (Usr_CheckIfIBelongToIns (Gbl.Hierarchy.Ins.InsCod)) { *ScopesAllowed |= 1 << Hie_INS; if (Usr_CheckIfIBelongToCtr (Gbl.Hierarchy.Ctr.CtrCod)) { *ScopesAllowed |= 1 << Hie_CTR; if (Usr_CheckIfIBelongToDeg (Gbl.Hierarchy.Deg.DegCod)) { *ScopesAllowed |= 1 << Hie_DEG; if (Gbl.Usrs.Me.IBelongToCurrentCrs) *ScopesAllowed |= 1 << Hie_CRS; } } } } break; case Rol_NET: // Non-editing teacher in current course ************** case Rol_TCH: // Teacher in current course ************************** *ScopesAllowed = 1 << Hie_SYS; *HiddenAllowed = 0; if (Usr_CheckIfIBelongToCty (Gbl.Hierarchy.Cty.CtyCod)) { *ScopesAllowed |= 1 << Hie_CTY; if (Usr_CheckIfIBelongToIns (Gbl.Hierarchy.Ins.InsCod)) { *ScopesAllowed |= 1 << Hie_INS; if (Usr_CheckIfIBelongToCtr (Gbl.Hierarchy.Ctr.CtrCod)) { *ScopesAllowed |= 1 << Hie_CTR; if (Usr_CheckIfIBelongToDeg (Gbl.Hierarchy.Deg.DegCod)) { *ScopesAllowed |= 1 << Hie_DEG; if (Gbl.Usrs.Me.IBelongToCurrentCrs) { *ScopesAllowed |= 1 << Hie_CRS; *HiddenAllowed |= 1 << Hie_CRS; // A non-editing teacher or teacher can view hidden course surveys } } } } } break; case Rol_DEG_ADM: // Degree administrator ******************************* *ScopesAllowed = 1 << Hie_SYS; *HiddenAllowed = 0; if (Gbl.Hierarchy.Cty.CtyCod > 0) // Country selected { *ScopesAllowed |= 1 << Hie_CTY; if (Gbl.Hierarchy.Ins.InsCod > 0) // Institution selected { *ScopesAllowed |= 1 << Hie_INS; if (Gbl.Hierarchy.Ctr.CtrCod > 0) // Centre selected { *ScopesAllowed |= 1 << Hie_CTR; if (Gbl.Hierarchy.Deg.DegCod > 0) // Degree selected { *ScopesAllowed |= 1 << Hie_DEG; *HiddenAllowed |= 1 << Hie_DEG; // A degree admin can view hidden degree surveys } } } } break; case Rol_CTR_ADM: // Centre administrator ******************************* *ScopesAllowed = 1 << Hie_SYS; *HiddenAllowed = 0; if (Gbl.Hierarchy.Cty.CtyCod > 0) // Country selected { *ScopesAllowed |= 1 << Hie_CTY; if (Gbl.Hierarchy.Ins.InsCod > 0) // Institution selected { *ScopesAllowed |= 1 << Hie_INS; if (Gbl.Hierarchy.Ctr.CtrCod > 0) // Centre selected { *ScopesAllowed |= 1 << Hie_CTR; *HiddenAllowed |= 1 << Hie_CTR; // A centre admin can view hidden centre surveys } } } break; case Rol_INS_ADM: // Institution administrator ************************** *ScopesAllowed = 1 << Hie_SYS; *HiddenAllowed = 0; if (Gbl.Hierarchy.Cty.CtyCod > 0) // Country selected { *ScopesAllowed |= 1 << Hie_CTY; if (Gbl.Hierarchy.Ins.InsCod > 0) // Institution selected { *ScopesAllowed |= 1 << Hie_INS; *HiddenAllowed |= 1 << Hie_INS; // An institution admin can view hidden institution surveys } } break; case Rol_SYS_ADM: // System administrator (superuser) ******************* *ScopesAllowed = 1 << Hie_SYS; *HiddenAllowed = 1 << Hie_SYS; // A system admin can view hidden system surveys if (Gbl.Hierarchy.Cty.CtyCod > 0) // Country selected { *ScopesAllowed |= 1 << Hie_CTY; *HiddenAllowed |= 1 << Hie_CTY; // A system admin can view hidden country surveys if (Gbl.Hierarchy.Ins.InsCod > 0) // Institution selected { *ScopesAllowed |= 1 << Hie_INS; *HiddenAllowed |= 1 << Hie_INS; // A system admin can view hidden institution surveys if (Gbl.Hierarchy.Ctr.CtrCod > 0) // Centre selected { *ScopesAllowed |= 1 << Hie_CTR; *HiddenAllowed |= 1 << Hie_CTR; // A system admin can view hidden centre surveys if (Gbl.Hierarchy.Deg.DegCod > 0) // Degree selected { *ScopesAllowed |= 1 << Hie_DEG; *HiddenAllowed |= 1 << Hie_DEG; // A system admin can view hidden degree surveys if (Gbl.Hierarchy.Level == Hie_CRS) // Course selected { *ScopesAllowed |= 1 << Hie_CRS; *HiddenAllowed |= 1 << Hie_CRS; // A system admin can view hidden course surveys } } } } } break; } } /*****************************************************************************/ /********************* Get survey data using its code ************************/ /*****************************************************************************/ void Svy_GetDataOfSurveyByCod (struct Survey *Svy) { MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned long NumRows; /***** Get data of survey from database *****/ NumRows = DB_QuerySELECT (&mysql_res,"can not get survey data", "SELECT SvyCod,Scope,Cod,Hidden,Roles,UsrCod," "UNIX_TIMESTAMP(StartTime)," "UNIX_TIMESTAMP(EndTime)," "NOW() BETWEEN StartTime AND EndTime," "Title" " FROM surveys" " WHERE SvyCod=%ld", Svy->SvyCod); if (NumRows) // Survey found... { /* Get row */ row = mysql_fetch_row (mysql_res); /* Get code of the survey (row[0]) */ Svy->SvyCod = Str_ConvertStrCodToLongCod (row[0]); /* Get survey scope (row[1]) */ if ((Svy->Scope = Sco_GetScopeFromDBStr (row[1])) == Hie_UNK) Lay_ShowErrorAndExit ("Wrong survey scope."); /* Get code of the country, institution, centre, degree or course (row[2]) */ Svy->Cod = Str_ConvertStrCodToLongCod (row[2]); /* Get whether the survey is hidden (row[3]) */ Svy->Status.Visible = (row[3][0] == 'N'); /* Get roles (row[4]) */ if (sscanf (row[4],"%u",&Svy->Roles) != 1) Lay_ShowErrorAndExit ("Error when reading roles of survey."); /* Get author of the survey (row[5]) */ Svy->UsrCod = Str_ConvertStrCodToLongCod (row[5]); /* Get start date (row[6] holds the start UTC time) */ Svy->TimeUTC[Att_START_TIME] = Dat_GetUNIXTimeFromStr (row[6]); /* Get end date (row[7] holds the end UTC time) */ Svy->TimeUTC[Att_END_TIME ] = Dat_GetUNIXTimeFromStr (row[7]); /* Get whether the survey is open or closed (row(8)) */ Svy->Status.Open = (row[8][0] == '1'); /* Get the title of the survey (row[9]) */ Str_Copy (Svy->Title,row[9], Svy_MAX_BYTES_SURVEY_TITLE); /* Get number of questions and number of users who have already answer this survey */ Svy->NumQsts = Svy_GetNumQstsSvy (Svy->SvyCod); Svy->NumUsrs = Svy_GetNumUsrsWhoHaveAnsweredSvy (Svy->SvyCod); /* Am I logged with a valid role to answer this survey? */ Svy->Status.IAmLoggedWithAValidRoleToAnswer = (Svy->Roles & (1 << Gbl.Usrs.Me.Role.Logged)); /* Do I belong to valid groups to answer this survey? */ switch (Svy->Scope) { case Hie_UNK: // Unknown Lay_ShowErrorAndExit ("Wrong survey scope."); break; case Hie_SYS: // System Svy->Status.IBelongToScope = Gbl.Usrs.Me.Logged; break; case Hie_CTY: // Country Svy->Status.IBelongToScope = Usr_CheckIfIBelongToCty (Svy->Cod); break; case Hie_INS: // Institution Svy->Status.IBelongToScope = Usr_CheckIfIBelongToIns (Svy->Cod); break; case Hie_CTR: // Centre Svy->Status.IBelongToScope = Usr_CheckIfIBelongToCtr (Svy->Cod); break; case Hie_DEG: // Degree Svy->Status.IBelongToScope = Usr_CheckIfIBelongToDeg (Svy->Cod); break; case Hie_CRS: // Course Svy->Status.IBelongToScope = Usr_CheckIfIBelongToCrs (Svy->Cod) && Svy_CheckIfICanDoThisSurveyBasedOnGrps (Svy->SvyCod); break; } /* Have I answered this survey? */ Svy->Status.IHaveAnswered = Svy_CheckIfIHaveAnsweredSvy (Svy->SvyCod); /* Can I answer survey? */ Svy->Status.ICanAnswer = (Svy->NumQsts != 0) && Svy->Status.Visible && Svy->Status.Open && Svy->Status.IAmLoggedWithAValidRoleToAnswer && Svy->Status.IBelongToScope && !Svy->Status.IHaveAnswered; /* Can I view results of the survey? Can I edit survey? */ switch (Gbl.Usrs.Me.Role.Logged) { case Rol_STD: Svy->Status.ICanViewResults = (Svy->Scope == Hie_CRS || Svy->Scope == Hie_DEG || Svy->Scope == Hie_CTR || Svy->Scope == Hie_INS || Svy->Scope == Hie_CTY || Svy->Scope == Hie_SYS) && (Svy->NumQsts != 0) && Svy->Status.Visible && Svy->Status.Open && Svy->Status.IAmLoggedWithAValidRoleToAnswer && Svy->Status.IBelongToScope && Svy->Status.IHaveAnswered; Svy->Status.ICanEdit = false; break; case Rol_NET: Svy->Status.ICanViewResults = (Svy->Scope == Hie_CRS || Svy->Scope == Hie_DEG || Svy->Scope == Hie_CTR || Svy->Scope == Hie_INS || Svy->Scope == Hie_CTY || Svy->Scope == Hie_SYS) && Svy->NumQsts != 0 && !Svy->Status.ICanAnswer; Svy->Status.ICanEdit = false; break; case Rol_TCH: Svy->Status.ICanViewResults = (Svy->Scope == Hie_CRS || Svy->Scope == Hie_DEG || Svy->Scope == Hie_CTR || Svy->Scope == Hie_INS || Svy->Scope == Hie_CTY || Svy->Scope == Hie_SYS) && Svy->NumQsts != 0 && !Svy->Status.ICanAnswer; Svy->Status.ICanEdit = Svy->Scope == Hie_CRS && Svy->Status.IBelongToScope; break; case Rol_DEG_ADM: Svy->Status.ICanViewResults = (Svy->Scope == Hie_DEG || Svy->Scope == Hie_CTR || Svy->Scope == Hie_INS || Svy->Scope == Hie_CTY || Svy->Scope == Hie_SYS) && (Svy->NumQsts != 0) && !Svy->Status.ICanAnswer; Svy->Status.ICanEdit = Svy->Scope == Hie_DEG && Svy->Status.IBelongToScope; break; case Rol_CTR_ADM: Svy->Status.ICanViewResults = (Svy->Scope == Hie_CTR || Svy->Scope == Hie_INS || Svy->Scope == Hie_CTY || Svy->Scope == Hie_SYS) && (Svy->NumQsts != 0) && !Svy->Status.ICanAnswer; Svy->Status.ICanEdit = Svy->Scope == Hie_CTR && Svy->Status.IBelongToScope; break; case Rol_INS_ADM: Svy->Status.ICanViewResults = (Svy->Scope == Hie_INS || Svy->Scope == Hie_CTY || Svy->Scope == Hie_SYS) && (Svy->NumQsts != 0) && !Svy->Status.ICanAnswer; Svy->Status.ICanEdit = Svy->Scope == Hie_INS && Svy->Status.IBelongToScope; break; case Rol_SYS_ADM: Svy->Status.ICanViewResults = (Svy->NumQsts != 0); Svy->Status.ICanEdit = true; break; default: Svy->Status.ICanViewResults = false; Svy->Status.ICanEdit = false; break; } } else { /* Initialize to empty survey */ Svy->SvyCod = -1L; Svy->Scope = Hie_UNK; Svy->Roles = 0; Svy->UsrCod = -1L; Svy->TimeUTC[Svy_START_TIME] = Svy->TimeUTC[Svy_END_TIME ] = (time_t) 0; Svy->Title[0] = '\0'; Svy->NumQsts = 0; Svy->NumUsrs = 0; Svy->Status.Visible = true; Svy->Status.Open = false; Svy->Status.IAmLoggedWithAValidRoleToAnswer = false; Svy->Status.IBelongToScope = false; Svy->Status.IHaveAnswered = false; Svy->Status.ICanAnswer = false; Svy->Status.ICanViewResults = false; Svy->Status.ICanEdit = false; } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /**************************** Free list of surveys ***************************/ /*****************************************************************************/ void Svy_FreeListSurveys (void) { if (Gbl.Svys.LstIsRead && Gbl.Svys.LstSvyCods) { /***** Free memory used by the list of surveys *****/ free ((void *) Gbl.Svys.LstSvyCods); Gbl.Svys.LstSvyCods = NULL; Gbl.Svys.Num = 0; Gbl.Svys.LstIsRead = false; } } /*****************************************************************************/ /********************** Get survey text from database ************************/ /*****************************************************************************/ static void Svy_GetSurveyTxtFromDB (long SvyCod,char Txt[Cns_MAX_BYTES_TEXT + 1]) { MYSQL_RES *mysql_res; MYSQL_ROW row; unsigned long NumRows; /***** Get text of survey from database *****/ NumRows = DB_QuerySELECT (&mysql_res,"can not get survey text", "SELECT Txt FROM surveys WHERE SvyCod=%ld", SvyCod); /***** The result of the query must have one row or none *****/ if (NumRows == 1) { /* Get info text */ row = mysql_fetch_row (mysql_res); Str_Copy (Txt,row[0], Cns_MAX_BYTES_TEXT); } else Txt[0] = '\0'; /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); if (NumRows > 1) Lay_ShowErrorAndExit ("Error when getting survey text."); } /*****************************************************************************/ /******************** Get summary and content of a survey *******************/ /*****************************************************************************/ // This function may be called inside a web service, so don't report error void Svy_GetNotifSurvey (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1], char **ContentStr, long SvyCod,bool GetContent) { char Query[128]; MYSQL_RES *mysql_res; MYSQL_ROW row; size_t Length; SummaryStr[0] = '\0'; // Return nothing on error /***** Build query *****/ sprintf (Query,"SELECT Title,Txt FROM surveys WHERE SvyCod=%ld", SvyCod); if (!mysql_query (&Gbl.mysql,Query)) if ((mysql_res = mysql_store_result (&Gbl.mysql)) != NULL) { /***** Result should have a unique row *****/ if (mysql_num_rows (mysql_res) == 1) { /***** Get row *****/ row = mysql_fetch_row (mysql_res); /***** Get summary *****/ Str_Copy (SummaryStr,row[0], Ntf_MAX_BYTES_SUMMARY); /***** Get content *****/ if (GetContent) { Length = strlen (row[1]); if ((*ContentStr = (char *) malloc (Length + 1)) == NULL) Lay_ShowErrorAndExit ("Error allocating memory for notification content."); Str_Copy (*ContentStr,row[1], Length); } } mysql_free_result (mysql_res); } } /*****************************************************************************/ /******************* Write parameter with code of survey *********************/ /*****************************************************************************/ static void Svy_PutParamSvyCod (long SvyCod) { Par_PutHiddenParamLong ("SvyCod",SvyCod); } /*****************************************************************************/ /******************** Get parameter with code of survey **********************/ /*****************************************************************************/ static long Svy_GetParamSvyCod (void) { /***** Get code of survey *****/ return Par_GetParToLong ("SvyCod"); } /*****************************************************************************/ /*************** Ask for confirmation of removing of a survey ****************/ /*****************************************************************************/ void Svy_AskRemSurvey (void) { extern const char *Txt_Do_you_really_want_to_remove_the_survey_X; extern const char *Txt_Remove_survey; struct Survey Svy; struct SurveyQuestion SvyQst; /***** Initialize question to zero *****/ Svy_InitQst (&SvyQst); /***** Get parameters *****/ Svy_GetParamSvyOrder (); Grp_GetParamWhichGrps (); Gbl.Svys.CurrentPage = Pag_GetParamPagNum (Pag_SURVEYS); /***** Get survey code *****/ if ((Svy.SvyCod = Svy_GetParamSvyCod ()) == -1L) Lay_ShowErrorAndExit ("Code of survey is missing."); /***** Get data of the survey from database *****/ Svy_GetDataOfSurveyByCod (&Svy); if (!Svy.Status.ICanEdit) Lay_NoPermissionExit (); /***** Show question and button to remove survey *****/ Svy_CurrentSvyCod = Svy.SvyCod; Ale_ShowAlertAndButton (ActRemSvy,NULL,NULL,Svy_PutParams, Btn_REMOVE_BUTTON,Txt_Remove_survey, Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_survey_X, Svy.Title); /***** Show surveys again *****/ Svy_ListAllSurveys (&SvyQst); } /*****************************************************************************/ /****************************** Remove a survey ******************************/ /*****************************************************************************/ void Svy_RemoveSurvey (void) { extern const char *Txt_Survey_X_removed; struct Survey Svy; struct SurveyQuestion SvyQst; /***** Initialize question to zero *****/ Svy_InitQst (&SvyQst); /***** Get survey code *****/ if ((Svy.SvyCod = Svy_GetParamSvyCod ()) == -1L) Lay_ShowErrorAndExit ("Code of survey is missing."); /***** Get data of the survey from database *****/ Svy_GetDataOfSurveyByCod (&Svy); if (!Svy.Status.ICanEdit) Lay_NoPermissionExit (); /***** Remove all the users in this survey *****/ DB_QueryDELETE ("can not remove users who are answered a survey", "DELETE FROM svy_users WHERE SvyCod=%ld", Svy.SvyCod); /***** Remove all the answers in this survey *****/ DB_QueryDELETE ("can not remove answers of a survey", "DELETE FROM svy_answers USING svy_questions,svy_answers" " WHERE svy_questions.SvyCod=%ld" " AND svy_questions.QstCod=svy_answers.QstCod", Svy.SvyCod); /***** Remove all the questions in this survey *****/ DB_QueryDELETE ("can not remove questions of a survey", "DELETE FROM svy_questions" " WHERE SvyCod=%ld", Svy.SvyCod); /***** Remove all the groups of this survey *****/ Svy_RemoveAllTheGrpsAssociatedToAndSurvey (Svy.SvyCod); /***** Remove survey *****/ DB_QueryDELETE ("can not remove survey", "DELETE FROM surveys WHERE SvyCod=%ld", Svy.SvyCod); /***** Mark possible notifications as removed *****/ Ntf_MarkNotifAsRemoved (Ntf_EVENT_SURVEY,Svy.SvyCod); /***** Write message to show the change made *****/ Ale_ShowAlert (Ale_SUCCESS,Txt_Survey_X_removed, Svy.Title); /***** Show surveys again *****/ Svy_ListAllSurveys (&SvyQst); } /*****************************************************************************/ /***************** Ask for confirmation of reset of a survey *****************/ /*****************************************************************************/ void Svy_AskResetSurvey (void) { extern const char *Txt_Do_you_really_want_to_reset_the_survey_X; struct Survey Svy; struct SurveyQuestion SvyQst; /***** Initialize question to zero *****/ Svy_InitQst (&SvyQst); /***** Get parameters *****/ Svy_GetParamSvyOrder (); Grp_GetParamWhichGrps (); Gbl.Svys.CurrentPage = Pag_GetParamPagNum (Pag_SURVEYS); /***** Get survey code *****/ if ((Svy.SvyCod = Svy_GetParamSvyCod ()) == -1L) Lay_ShowErrorAndExit ("Code of survey is missing."); /***** Get data of the survey from database *****/ Svy_GetDataOfSurveyByCod (&Svy); if (!Svy.Status.ICanEdit) Lay_NoPermissionExit (); /***** Ask for confirmation of reset *****/ Ale_ShowAlert (Ale_WARNING,Txt_Do_you_really_want_to_reset_the_survey_X, Svy.Title); /***** Button of confirmation of reset *****/ Svy_CurrentSvyCod = Svy.SvyCod; Svy_PutButtonToResetSurvey (); /***** Show surveys again *****/ Svy_ListAllSurveys (&SvyQst); } /*****************************************************************************/ /************************* Put button to reset survey ************************/ /*****************************************************************************/ static void Svy_PutButtonToResetSurvey (void) { extern const char *Txt_Reset_survey; Frm_StartForm (ActRstSvy); Svy_PutParams (); Btn_PutRemoveButton (Txt_Reset_survey); Frm_EndForm (); } /*****************************************************************************/ /******************************* Reset a survey ******************************/ /*****************************************************************************/ void Svy_ResetSurvey (void) { extern const char *Txt_Survey_X_reset; struct Survey Svy; struct SurveyQuestion SvyQst; /***** Initialize question to zero *****/ Svy_InitQst (&SvyQst); /***** Get survey code *****/ if ((Svy.SvyCod = Svy_GetParamSvyCod ()) == -1L) Lay_ShowErrorAndExit ("Code of survey is missing."); /***** Get data of the survey from database *****/ Svy_GetDataOfSurveyByCod (&Svy); if (!Svy.Status.ICanEdit) Lay_NoPermissionExit (); /***** Remove all the users in this survey *****/ DB_QueryDELETE ("can not remove users who are answered a survey", "DELETE FROM svy_users WHERE SvyCod=%ld", Svy.SvyCod); /***** Reset all the answers in this survey *****/ DB_QueryUPDATE ("can not reset answers of a survey", "UPDATE svy_answers,svy_questions SET svy_answers.NumUsrs=0" " WHERE svy_questions.SvyCod=%ld" " AND svy_questions.QstCod=svy_answers.QstCod", Svy.SvyCod); /***** Write message to show the change made *****/ Ale_ShowAlert (Ale_SUCCESS,Txt_Survey_X_reset, Svy.Title); /***** Show surveys again *****/ Svy_ListAllSurveys (&SvyQst); } /*****************************************************************************/ /******************************** Hide a survey ******************************/ /*****************************************************************************/ void Svy_HideSurvey (void) { struct Survey Svy; struct SurveyQuestion SvyQst; /***** Initialize question to zero *****/ Svy_InitQst (&SvyQst); /***** Get parameters *****/ Svy_GetParamSvyOrder (); Grp_GetParamWhichGrps (); Gbl.Svys.CurrentPage = Pag_GetParamPagNum (Pag_SURVEYS); /***** Get survey code *****/ if ((Svy.SvyCod = Svy_GetParamSvyCod ()) == -1L) Lay_ShowErrorAndExit ("Code of survey is missing."); /***** Get data of the survey from database *****/ Svy_GetDataOfSurveyByCod (&Svy); if (!Svy.Status.ICanEdit) Lay_NoPermissionExit (); /***** Hide survey *****/ DB_QueryUPDATE ("can not hide survey", "UPDATE surveys SET Hidden='Y' WHERE SvyCod=%ld", Svy.SvyCod); /***** Show surveys again *****/ Svy_ListAllSurveys (&SvyQst); } /*****************************************************************************/ /******************************** Show a survey ******************************/ /*****************************************************************************/ void Svy_UnhideSurvey (void) { struct Survey Svy; struct SurveyQuestion SvyQst; /***** Initialize question to zero *****/ Svy_InitQst (&SvyQst); /***** Get parameters *****/ Svy_GetParamSvyOrder (); Grp_GetParamWhichGrps (); Gbl.Svys.CurrentPage = Pag_GetParamPagNum (Pag_SURVEYS); /***** Get survey code *****/ if ((Svy.SvyCod = Svy_GetParamSvyCod ()) == -1L) Lay_ShowErrorAndExit ("Code of survey is missing."); /***** Get data of the survey from database *****/ Svy_GetDataOfSurveyByCod (&Svy); if (!Svy.Status.ICanEdit) Lay_NoPermissionExit (); /***** Show survey *****/ DB_QueryUPDATE ("can not show survey", "UPDATE surveys SET Hidden='N' WHERE SvyCod=%ld", Svy.SvyCod); /***** Show surveys again *****/ Svy_ListAllSurveys (&SvyQst); } /*****************************************************************************/ /******************* Check if the title of a survey exists *******************/ /*****************************************************************************/ static bool Svy_CheckIfSimilarSurveyExists (struct Survey *Svy) { /***** Get number of surveys with a field value from database *****/ return (DB_QueryCOUNT ("can not get similar surveys", "SELECT COUNT(*) FROM surveys" " WHERE Scope='%s' AND Cod=%ld" " AND Title='%s' AND SvyCod<>%ld", Sco_GetDBStrFromScope (Svy->Scope),Svy->Cod, Svy->Title,Svy->SvyCod) != 0); } /*****************************************************************************/ /********************* Put a form to create a new survey *********************/ /*****************************************************************************/ void Svy_RequestCreatOrEditSvy (void) { extern const char *Hlp_ASSESSMENT_Surveys_new_survey; extern const char *Hlp_ASSESSMENT_Surveys_edit_survey; extern const char *The_ClassFormInBox[The_NUM_THEMES]; extern const char *Txt_New_survey; extern const char *Txt_Scope; extern const char *Txt_Edit_survey; extern const char *Txt_Title; extern const char *Txt_Description; extern const char *Txt_Users; extern const char *Txt_Create_survey; extern const char *Txt_Save_changes; struct Survey Svy; struct SurveyQuestion SvyQst; bool ItsANewSurvey; char Txt[Cns_MAX_BYTES_TEXT + 1]; /***** Initialize question to zero *****/ Svy_InitQst (&SvyQst); /***** Get parameters *****/ Svy_GetParamSvyOrder (); Grp_GetParamWhichGrps (); Gbl.Svys.CurrentPage = Pag_GetParamPagNum (Pag_SURVEYS); /***** Get the code of the survey *****/ ItsANewSurvey = ((Svy.SvyCod = Svy_GetParamSvyCod ()) == -1L); /***** Get from the database the data of the survey *****/ if (ItsANewSurvey) { /***** Put link (form) to create new survey *****/ if (!Svy_CheckIfICanCreateSvy ()) Lay_NoPermissionExit (); /* Initialize to empty survey */ Svy.SvyCod = -1L; Svy.Scope = Hie_UNK; Svy.Roles = (1 << Rol_STD); Svy.UsrCod = Gbl.Usrs.Me.UsrDat.UsrCod; Svy.TimeUTC[Svy_START_TIME] = Gbl.StartExecutionTimeUTC; Svy.TimeUTC[Svy_END_TIME ] = Gbl.StartExecutionTimeUTC + (24 * 60 * 60); // +24 hours Svy.Title[0] = '\0'; Svy.NumQsts = 0; Svy.NumUsrs = 0; Svy.Status.Visible = true; Svy.Status.Open = true; Svy.Status.IAmLoggedWithAValidRoleToAnswer = false; Svy.Status.IBelongToScope = false; Svy.Status.IHaveAnswered = false; Svy.Status.ICanAnswer = false; Svy.Status.ICanViewResults = false; } else { /* Get data of the survey from database */ Svy_GetDataOfSurveyByCod (&Svy); if (!Svy.Status.ICanEdit) Lay_NoPermissionExit (); /* Get text of the survey from database */ Svy_GetSurveyTxtFromDB (Svy.SvyCod,Txt); } /***** Begin form *****/ Svy_CurrentSvyCod = Svy.SvyCod; Frm_StartForm (ItsANewSurvey ? ActNewSvy : ActChgSvy); Svy_PutParams (); /***** Begin box and table *****/ if (ItsANewSurvey) Box_StartBoxTable (NULL,Txt_New_survey,NULL, Hlp_ASSESSMENT_Surveys_new_survey,Box_NOT_CLOSABLE,2); else Box_StartBoxTable (NULL, Svy.Title[0] ? Svy.Title : Txt_Edit_survey, NULL, Hlp_ASSESSMENT_Surveys_edit_survey,Box_NOT_CLOSABLE,2); /***** Scope of the survey *****/ HTM_TR_Begin (NULL); HTM_TD_Begin ("class=\"RM\""); fprintf (Gbl.F.Out,"