Version 22.117: May 22, 2023 Teachers can allow comments in a survey question.

This commit is contained in:
acanas 2023-05-22 14:34:35 +02:00
parent 710a82e846
commit 1a1d0196b5
8 changed files with 315 additions and 206 deletions

View File

@ -1428,6 +1428,7 @@ CREATE TABLE IF NOT EXISTS svy_questions (
SvyCod INT NOT NULL, SvyCod INT NOT NULL,
QstInd INT NOT NULL DEFAULT 0, QstInd INT NOT NULL DEFAULT 0,
AnsType ENUM('unique_choice','multiple_choice') NOT NULL, AnsType ENUM('unique_choice','multiple_choice') NOT NULL,
CommentsAllowed ENUM('N','Y') NOT NULL DEFAULT 'N',
Stem TEXT NOT NULL, Stem TEXT NOT NULL,
UNIQUE INDEX(QstCod), UNIQUE INDEX(QstCod),
INDEX(SvyCod)); INDEX(SvyCod));

View File

@ -629,10 +629,14 @@ TODO: Emilce Barrera Mesa: Podr
TODO: Emilce Barrera Mesa: Mis estudiantes presentan muchas dificultades a la hora de poner la foto porque la plataforma es muy exigente respecto al fondo de la imagen. TODO: Emilce Barrera Mesa: Mis estudiantes presentan muchas dificultades a la hora de poner la foto porque la plataforma es muy exigente respecto al fondo de la imagen.
*/ */
#define Log_PLATFORM_VERSION "SWAD 22.116.1 (2023-05-21)" #define Log_PLATFORM_VERSION "SWAD 22.117 (2023-05-22)"
#define CSS_FILE "swad22.107.36.css" #define CSS_FILE "swad22.107.36.css"
#define JS_FILE "swad22.49.js" #define JS_FILE "swad22.49.js"
/* /*
Version 22.117: May 22, 2023 Teachers can allow comments in a survey question. (337196 lines)
1 change necessary in database:
ALTER TABLE svy_questions ADD COLUMN CommentsAllowed ENUM('N','Y') NOT NULL DEFAULT 'N' AFTER AnsType;
Version 22.116.1: May 21, 2023 Rubrics only availables for superusers. (337098 lines) Version 22.116.1: May 21, 2023 Rubrics only availables for superusers. (337098 lines)
Version 22.116: May 20, 2023 Changes in rubric scores. (337093 lines) Version 22.116: May 20, 2023 Changes in rubric scores. (337093 lines)
Version 22.115: May 19, 2023 Generalization of rubric scores. (337010 lines) Version 22.115: May 19, 2023 Generalization of rubric scores. (337010 lines)

View File

@ -3058,22 +3058,24 @@ mysql> DESCRIBE svy_groups;
/***** Table svy_questions *****/ /***** Table svy_questions *****/
/* /*
mysql> DESCRIBE svy_questions; mysql> DESCRIBE svy_questions;
+---------+-----------------------------------------+------+-----+---------+----------------+ +-----------------+-----------------------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra | | Field | Type | Null | Key | Default | Extra |
+---------+-----------------------------------------+------+-----+---------+----------------+ +-----------------+-----------------------------------------+------+-----+---------+----------------+
| QstCod | int(11) | NO | PRI | NULL | auto_increment | | QstCod | int | NO | PRI | NULL | auto_increment |
| SvyCod | int(11) | NO | MUL | NULL | | | SvyCod | int | NO | MUL | NULL | |
| QstInd | int(11) | NO | | 0 | | | QstInd | int | NO | | 0 | |
| AnsType | enum('unique_choice','multiple_choice') | NO | | NULL | | | AnsType | enum('unique_choice','multiple_choice') | NO | | NULL | |
| Stem | text | NO | | NULL | | | CommentsAllowed | enum('N','Y') | NO | | N | |
+---------+-----------------------------------------+------+-----+---------+----------------+ | Stem | text | NO | | NULL | |
5 rows in set (0.00 sec) +-----------------+-----------------------------------------+------+-----+---------+----------------+
6 rows in set (0,00 sec)
*/ */
DB_CreateTable ("CREATE TABLE IF NOT EXISTS svy_questions (" DB_CreateTable ("CREATE TABLE IF NOT EXISTS svy_questions ("
"QstCod INT NOT NULL AUTO_INCREMENT," "QstCod INT NOT NULL AUTO_INCREMENT,"
"SvyCod INT NOT NULL," "SvyCod INT NOT NULL,"
"QstInd INT NOT NULL DEFAULT 0," "QstInd INT NOT NULL DEFAULT 0,"
"AnsType ENUM ('unique_choice','multiple_choice') NOT NULL," "AnsType ENUM ('unique_choice','multiple_choice') NOT NULL,"
"CommentsAllowed ENUM('N','Y') NOT NULL DEFAULT 'N'"
"Stem TEXT NOT NULL," // Cns_MAX_BYTES_TEXT "Stem TEXT NOT NULL," // Cns_MAX_BYTES_TEXT
"UNIQUE INDEX(QstCod)," "UNIQUE INDEX(QstCod),"
"INDEX(SvyCod))"); "INDEX(SvyCod))");

View File

@ -70,21 +70,6 @@ extern struct Globals Gbl;
#define Svy_MAX_BYTES_LIST_ANSWER_TYPES (Svy_NUM_ANS_TYPES * (Cns_MAX_DECIMAL_DIGITS_UINT + 1)) #define Svy_MAX_BYTES_LIST_ANSWER_TYPES (Svy_NUM_ANS_TYPES * (Cns_MAX_DECIMAL_DIGITS_UINT + 1))
#define Svy_MAX_ANSWERS_PER_QUESTION 10
struct Svy_Question // 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 prototypes ****************************/ /***************************** Private prototypes ****************************/
/*****************************************************************************/ /*****************************************************************************/
@ -136,6 +121,9 @@ static void Svy_WriteQstStem (const char *Stem);
static void Svy_WriteAnswersOfAQst (struct Svy_Survey *Svy, static void Svy_WriteAnswersOfAQst (struct Svy_Survey *Svy,
struct Svy_Question *SvyQst, struct Svy_Question *SvyQst,
bool PutFormAnswerSurvey); bool PutFormAnswerSurvey);
static void Svy_WriteCommentsOfAQst (struct Svy_Survey *Svy,
struct Svy_Question *SvyQst,
bool PutFormAnswerSurvey);
static void Svy_DrawBarNumUsrs (unsigned NumUsrs,unsigned MaxUsrs); static void Svy_DrawBarNumUsrs (unsigned NumUsrs,unsigned MaxUsrs);
static void Svy_PutIconToRemoveOneQst (void *Surveys); static void Svy_PutIconToRemoveOneQst (void *Surveys);
@ -1229,33 +1217,36 @@ void Svy_GetSurveyDataByCod (struct Svy_Survey *Svy)
switch (Gbl.Usrs.Me.Role.Logged) switch (Gbl.Usrs.Me.Role.Logged)
{ {
case Rol_STD: case Rol_STD:
Svy->Status.ICanViewResults = ( Svy->Scope == HieLvl_CRS || Svy->Status.ICanViewResults = ( Svy->Scope == HieLvl_CRS ||
Svy->Scope == HieLvl_DEG ||
Svy->Scope == HieLvl_CTR ||
Svy->Scope == HieLvl_INS ||
Svy->Scope == HieLvl_CTY ||
Svy->Scope == HieLvl_SYS) &&
( Svy->NumQsts != 0) &&
!Svy->Status.Hidden &&
Svy->Status.Open &&
Svy->Status.IAmLoggedWithAValidRoleToAnswer &&
Svy->Status.IBelongToScope &&
Svy->Status.IHaveAnswered;
Svy->Status.ICanViewComments = false;
Svy->Status.ICanEdit = false;
break;
case Rol_NET:
Svy->Status.ICanViewResults =
Svy->Status.ICanViewComments = (Svy->Scope == HieLvl_CRS ||
Svy->Scope == HieLvl_DEG || Svy->Scope == HieLvl_DEG ||
Svy->Scope == HieLvl_CTR || Svy->Scope == HieLvl_CTR ||
Svy->Scope == HieLvl_INS || Svy->Scope == HieLvl_INS ||
Svy->Scope == HieLvl_CTY || Svy->Scope == HieLvl_CTY ||
Svy->Scope == HieLvl_SYS) && Svy->Scope == HieLvl_SYS) &&
( Svy->NumQsts != 0) && Svy->NumQsts != 0 &&
!Svy->Status.Hidden && !Svy->Status.ICanAnswer;
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 == HieLvl_CRS ||
Svy->Scope == HieLvl_DEG ||
Svy->Scope == HieLvl_CTR ||
Svy->Scope == HieLvl_INS ||
Svy->Scope == HieLvl_CTY ||
Svy->Scope == HieLvl_SYS) &&
Svy->NumQsts != 0 &&
!Svy->Status.ICanAnswer;
Svy->Status.ICanEdit = false; Svy->Status.ICanEdit = false;
break; break;
case Rol_TCH: case Rol_TCH:
Svy->Status.ICanViewResults = (Svy->Scope == HieLvl_CRS || Svy->Status.ICanViewResults =
Svy->Status.ICanViewComments = (Svy->Scope == HieLvl_CRS ||
Svy->Scope == HieLvl_DEG || Svy->Scope == HieLvl_DEG ||
Svy->Scope == HieLvl_CTR || Svy->Scope == HieLvl_CTR ||
Svy->Scope == HieLvl_INS || Svy->Scope == HieLvl_INS ||
@ -1266,42 +1257,47 @@ void Svy_GetSurveyDataByCod (struct Svy_Survey *Svy)
Svy->Status.ICanEdit = Svy->Scope == HieLvl_CRS; // && Svy->Status.IBelongToScope Svy->Status.ICanEdit = Svy->Scope == HieLvl_CRS; // && Svy->Status.IBelongToScope
break; break;
case Rol_DEG_ADM: case Rol_DEG_ADM:
Svy->Status.ICanViewResults = (Svy->Scope == HieLvl_DEG || Svy->Status.ICanViewResults =
Svy->Scope == HieLvl_CTR || Svy->Status.ICanViewComments = (Svy->Scope == HieLvl_DEG ||
Svy->Scope == HieLvl_INS || Svy->Scope == HieLvl_CTR ||
Svy->Scope == HieLvl_CTY || Svy->Scope == HieLvl_INS ||
Svy->Scope == HieLvl_SYS) && Svy->Scope == HieLvl_CTY ||
(Svy->NumQsts != 0) && Svy->Scope == HieLvl_SYS) &&
!Svy->Status.ICanAnswer; (Svy->NumQsts != 0) &&
Svy->Status.ICanEdit = Svy->Scope == HieLvl_DEG && !Svy->Status.ICanAnswer;
Svy->Status.IBelongToScope; Svy->Status.ICanEdit = Svy->Scope == HieLvl_DEG &&
Svy->Status.IBelongToScope;
break; break;
case Rol_CTR_ADM: case Rol_CTR_ADM:
Svy->Status.ICanViewResults = (Svy->Scope == HieLvl_CTR || Svy->Status.ICanViewResults =
Svy->Scope == HieLvl_INS || Svy->Status.ICanViewComments = (Svy->Scope == HieLvl_CTR ||
Svy->Scope == HieLvl_CTY || Svy->Scope == HieLvl_INS ||
Svy->Scope == HieLvl_SYS) && Svy->Scope == HieLvl_CTY ||
(Svy->NumQsts != 0) && Svy->Scope == HieLvl_SYS) &&
!Svy->Status.ICanAnswer; (Svy->NumQsts != 0) &&
Svy->Status.ICanEdit = Svy->Scope == HieLvl_CTR && !Svy->Status.ICanAnswer;
Svy->Status.IBelongToScope; Svy->Status.ICanEdit = Svy->Scope == HieLvl_CTR &&
Svy->Status.IBelongToScope;
break; break;
case Rol_INS_ADM: case Rol_INS_ADM:
Svy->Status.ICanViewResults = (Svy->Scope == HieLvl_INS || Svy->Status.ICanViewResults =
Svy->Scope == HieLvl_CTY || Svy->Status.ICanViewComments = (Svy->Scope == HieLvl_INS ||
Svy->Scope == HieLvl_SYS) && Svy->Scope == HieLvl_CTY ||
(Svy->NumQsts != 0) && Svy->Scope == HieLvl_SYS) &&
!Svy->Status.ICanAnswer; (Svy->NumQsts != 0) &&
Svy->Status.ICanEdit = Svy->Scope == HieLvl_INS && !Svy->Status.ICanAnswer;
Svy->Status.IBelongToScope; Svy->Status.ICanEdit = Svy->Scope == HieLvl_INS &&
Svy->Status.IBelongToScope;
break; break;
case Rol_SYS_ADM: case Rol_SYS_ADM:
Svy->Status.ICanViewResults = (Svy->NumQsts != 0); Svy->Status.ICanViewResults =
Svy->Status.ICanEdit = true; Svy->Status.ICanViewComments = (Svy->NumQsts != 0);
Svy->Status.ICanEdit = true;
break; break;
default: default:
Svy->Status.ICanViewResults = false; Svy->Status.ICanViewResults = false;
Svy->Status.ICanEdit = false; Svy->Status.ICanViewComments = false;
Svy->Status.ICanEdit = false;
break; break;
} }
} }
@ -1324,6 +1320,7 @@ void Svy_GetSurveyDataByCod (struct Svy_Survey *Svy)
Svy->Status.IHaveAnswered = false; Svy->Status.IHaveAnswered = false;
Svy->Status.ICanAnswer = false; Svy->Status.ICanAnswer = false;
Svy->Status.ICanViewResults = false; Svy->Status.ICanViewResults = false;
Svy->Status.ICanViewComments = false;
Svy->Status.ICanEdit = false; Svy->Status.ICanEdit = false;
} }
@ -1666,6 +1663,7 @@ void Svy_ReqCreatOrEditSvy (void)
Surveys.Svy.Status.IHaveAnswered = false; Surveys.Svy.Status.IHaveAnswered = false;
Surveys.Svy.Status.ICanAnswer = false; Surveys.Svy.Status.ICanAnswer = false;
Surveys.Svy.Status.ICanViewResults = false; Surveys.Svy.Status.ICanViewResults = false;
Surveys.Svy.Status.ICanViewComments = false;
} }
else else
{ {
@ -2265,6 +2263,9 @@ static void Svy_ShowFormEditOneQst (struct Svy_Surveys *Surveys,
extern const char *Txt_Wording; extern const char *Txt_Wording;
extern const char *Txt_Type; extern const char *Txt_Type;
extern const char *Txt_SURVEY_STR_ANSWER_TYPES[Svy_NUM_ANS_TYPES]; extern const char *Txt_SURVEY_STR_ANSWER_TYPES[Svy_NUM_ANS_TYPES];
extern const char *Txt_Options;
extern const char *Txt_Comments;
extern const char *Txt_Comments_allowed;
extern const char *Txt_Save_changes; extern const char *Txt_Save_changes;
extern const char *Txt_Create; extern const char *Txt_Create;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
@ -2380,10 +2381,13 @@ static void Svy_ShowFormEditOneQst (struct Svy_Surveys *Surveys,
/***** Answers *****/ /***** Answers *****/
HTM_TR_Begin (NULL); HTM_TR_Begin (NULL);
HTM_TD_Empty (1); HTM_TD_Begin ("class=\"RT FORM_IN_%s\"",The_GetSuffix ());
HTM_TxtColon (Txt_Options);
HTM_TD_End ();
/* Unique or multiple choice answers */
HTM_TD_Begin ("class=\"LT\""); HTM_TD_Begin ("class=\"LT\"");
/* Unique or multiple choice answers */
HTM_TABLE_BeginPadding (2); HTM_TABLE_BeginPadding (2);
for (NumAns = 0; for (NumAns = 0;
NumAns < Svy_MAX_ANSWERS_PER_QUESTION; NumAns < Svy_MAX_ANSWERS_PER_QUESTION;
@ -2411,6 +2415,26 @@ static void Svy_ShowFormEditOneQst (struct Svy_Surveys *Surveys,
HTM_TR_End (); HTM_TR_End ();
} }
HTM_TABLE_End (); HTM_TABLE_End ();
HTM_TD_End ();
HTM_TR_End ();
/***** Comments allowed? *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"RT FORM_IN_%s\"",The_GetSuffix ());
HTM_TxtColon (Txt_Comments);
HTM_TD_End ();
HTM_TD_Begin ("class=\"LT FORM_IN_%s\"",The_GetSuffix ());
HTM_LABEL_Begin (NULL);
HTM_INPUT_CHECKBOX ("Comment",HTM_DONT_SUBMIT_ON_CHANGE,
"value=\"Y\"%s",
SvyQst->CommentsAllowed ? " checked=\"checked\"" :
"");
HTM_Txt (Txt_Comments_allowed);
HTM_LABEL_End ();
HTM_TD_End (); HTM_TD_End ();
HTM_TR_End (); HTM_TR_End ();
@ -2449,6 +2473,7 @@ static void Svy_InitQst (struct Svy_Question *SvyQst)
NumAns < Svy_MAX_ANSWERS_PER_QUESTION; NumAns < Svy_MAX_ANSWERS_PER_QUESTION;
NumAns++) NumAns++)
SvyQst->AnsChoice[NumAns].Text = NULL; SvyQst->AnsChoice[NumAns].Text = NULL;
SvyQst->CommentsAllowed = false;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -2504,14 +2529,12 @@ void Svy_ReceiveQst (void)
{ {
extern const char *Txt_You_must_type_the_question_stem; extern const char *Txt_You_must_type_the_question_stem;
extern const char *Txt_You_can_not_leave_empty_intermediate_answers; extern const char *Txt_You_can_not_leave_empty_intermediate_answers;
extern const char *Txt_You_must_type_at_least_the_first_two_answers;
extern const char *Txt_The_survey_has_been_modified; extern const char *Txt_The_survey_has_been_modified;
struct Svy_Surveys Surveys; struct Svy_Surveys Surveys;
struct Svy_Question SvyQst; struct Svy_Question SvyQst;
char Stem[Cns_MAX_BYTES_TEXT + 1]; char Stem[Cns_MAX_BYTES_TEXT + 1];
unsigned NumAns; unsigned NumAns;
char AnsStr[8 + 10 + 1]; char AnsStr[8 + 10 + 1];
unsigned NumLastAns;
bool ThereIsEndOfAnswers; bool ThereIsEndOfAnswers;
bool Error = false; bool Error = false;
@ -2550,40 +2573,25 @@ void Svy_ReceiveQst (void)
Par_GetParHTML (AnsStr,SvyQst.AnsChoice[NumAns].Text,Svy_MAX_BYTES_ANSWER); Par_GetParHTML (AnsStr,SvyQst.AnsChoice[NumAns].Text,Svy_MAX_BYTES_ANSWER);
} }
/***** Make sure that stem and answer are not empty *****/ /* Get if comments are allowed */
SvyQst.CommentsAllowed = Par_GetParBool ("Comment");
/***** Make sure that stem is not empty *****/
if (Stem[0]) if (Stem[0])
{ {
if (SvyQst.AnsChoice[0].Text[0]) // If the first answer has been filled for (NumAns = 0, ThereIsEndOfAnswers = false;
{ !Error && NumAns < Svy_MAX_ANSWERS_PER_QUESTION;
for (NumAns = 0, NumLastAns = 0, ThereIsEndOfAnswers = false; NumAns++)
!Error && NumAns < Svy_MAX_ANSWERS_PER_QUESTION; if (SvyQst.AnsChoice[NumAns].Text[0])
NumAns++) {
if (SvyQst.AnsChoice[NumAns].Text[0]) if (ThereIsEndOfAnswers)
{ {
if (ThereIsEndOfAnswers) Ale_ShowAlert (Ale_WARNING,Txt_You_can_not_leave_empty_intermediate_answers);
{ Error = true;
Ale_ShowAlert (Ale_WARNING,Txt_You_can_not_leave_empty_intermediate_answers); }
Error = true; }
} else
else ThereIsEndOfAnswers = true;
NumLastAns = NumAns;
}
else
ThereIsEndOfAnswers = true;
if (!Error)
{
if (NumLastAns < 1)
{
Ale_ShowAlert (Ale_WARNING,Txt_You_must_type_at_least_the_first_two_answers);
Error = true;
}
}
}
else // If first answer is empty
{
Ale_ShowAlert (Ale_WARNING,Txt_You_must_type_at_least_the_first_two_answers);
Error = true;
}
} }
else else
{ {
@ -2599,12 +2607,11 @@ void Svy_ReceiveQst (void)
if (SvyQst.QstCod < 0) // It's a new question if (SvyQst.QstCod < 0) // It's a new question
{ {
SvyQst.QstInd = Svy_GetNextQuestionIndexInSvy (Surveys.Svy.SvyCod); SvyQst.QstInd = Svy_GetNextQuestionIndexInSvy (Surveys.Svy.SvyCod);
SvyQst.QstCod = Svy_DB_CreateQuestion (Surveys.Svy.SvyCod,SvyQst.QstInd, SvyQst.QstCod = Svy_DB_CreateQuestion (Surveys.Svy.SvyCod,&SvyQst,Stem);
SvyQst.AnswerType,Stem);
} }
else // It's an existing question else // It's an existing question
/* Update question */ /* Update question */
Svy_DB_UpdateQuestion (Surveys.Svy.SvyCod,SvyQst.QstCod,SvyQst.AnswerType,Stem); Svy_DB_UpdateQuestion (Surveys.Svy.SvyCod,&SvyQst,Stem);
/* Insert, update or delete answers in the answers table */ /* Insert, update or delete answers in the answers table */
for (NumAns = 0; for (NumAns = 0;
@ -2774,6 +2781,9 @@ static void Svy_ListSvyQuestions (struct Svy_Surveys *Surveys)
The_GetColorRows ()); The_GetColorRows ());
Svy_WriteQstStem (Stem); Svy_WriteQstStem (Stem);
Svy_WriteAnswersOfAQst (&Surveys->Svy,&SvyQst,PutFormAnswerSurvey); Svy_WriteAnswersOfAQst (&Surveys->Svy,&SvyQst,PutFormAnswerSurvey);
if (SvyQst.CommentsAllowed)
Svy_WriteCommentsOfAQst (&Surveys->Svy,&SvyQst,PutFormAnswerSurvey);
HTM_TD_End (); HTM_TD_End ();
HTM_TR_End (); HTM_TR_End ();
@ -2823,8 +2833,11 @@ static void Svy_GetQstDataFromRow (MYSQL_RES *mysql_res,
/***** Get the answer type (row[2]) *****/ /***** Get the answer type (row[2]) *****/
SvyQst->AnswerType = Svy_DB_ConvertFromStrAnsTypDBToAnsTyp (row[2]); SvyQst->AnswerType = Svy_DB_ConvertFromStrAnsTypDBToAnsTyp (row[2]);
/***** Get the stem of the question from the database (row[3]) *****/ /***** Get whether the comments are allowed (row[3]) *****/
Str_Copy (Stem,row[3],Cns_MAX_BYTES_TEXT); SvyQst->CommentsAllowed = (row[3][0] == 'Y');
/***** Get the stem of the question from the database (row[4]) *****/
Str_Copy (Stem,row[4],Cns_MAX_BYTES_TEXT);
} }
/*****************************************************************************/ /*****************************************************************************/
@ -2901,84 +2914,113 @@ static void Svy_WriteAnswersOfAQst (struct Svy_Survey *Svy,
/* Write one row for each answer */ /* Write one row for each answer */
HTM_TABLE_BeginPadding (5); HTM_TABLE_BeginPadding (5);
for (NumAns = 0; for (NumAns = 0;
NumAns < NumAnswers; NumAns < NumAnswers;
NumAns++) NumAns++)
{ {
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/* Get number of users who have marked this answer (row[1]) */ /* Get number of users who have marked this answer (row[1]) */
if (sscanf (row[1],"%u",&NumUsrsThisAnswer) != 1) if (sscanf (row[1],"%u",&NumUsrsThisAnswer) != 1)
Err_ShowErrorAndExit ("Error when getting number of users who have marked an answer."); Err_ShowErrorAndExit ("Error when getting number of users who have marked an answer.");
/* Convert the answer (row[2]), that is in HTML, to rigorous HTML */ /* Convert the answer (row[2]), that is in HTML, to rigorous HTML */
if (!Svy_AllocateTextChoiceAnswer (SvyQst,NumAns)) if (!Svy_AllocateTextChoiceAnswer (SvyQst,NumAns))
/* Abort on error */ /* Abort on error */
Ale_ShowAlertsAndExit (); Ale_ShowAlertsAndExit ();
Str_Copy (SvyQst->AnsChoice[NumAns].Text,row[2],Svy_MAX_BYTES_ANSWER); Str_Copy (SvyQst->AnsChoice[NumAns].Text,row[2],Svy_MAX_BYTES_ANSWER);
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
SvyQst->AnsChoice[NumAns].Text,Svy_MAX_BYTES_ANSWER,false); SvyQst->AnsChoice[NumAns].Text,Svy_MAX_BYTES_ANSWER,false);
/* Selectors and label with the letter of the answer */ /* Selectors and label with the letter of the answer */
HTM_TR_Begin (NULL); HTM_TR_Begin (NULL);
if (PutFormAnswerSurvey) if (PutFormAnswerSurvey)
{ {
/* Write selector to choice this answer */ /* Write selector to choice this answer */
HTM_TD_Begin ("class=\"LT\""); HTM_TD_Begin ("class=\"LT\"");
snprintf (StrAns,sizeof (StrAns),"Ans%010u", snprintf (StrAns,sizeof (StrAns),"Ans%010u",
(unsigned) SvyQst->QstCod); (unsigned) SvyQst->QstCod);
if (SvyQst->AnswerType == Svy_ANS_UNIQUE_CHOICE) switch (SvyQst->AnswerType)
HTM_INPUT_RADIO (StrAns,HTM_DONT_SUBMIT_ON_CLICK, {
"id=\"Ans%010u_%010u\" value=\"%u\"" case Svy_ANS_UNIQUE_CHOICE:
" onclick=\"selectUnselectRadio(this,this.form.Ans%010u,%u)\"", HTM_INPUT_RADIO (StrAns,HTM_DONT_SUBMIT_ON_CLICK,
(unsigned) SvyQst->QstCod,NumAns,NumAns, "id=\"Ans%010u_%u\" value=\"%u\""
NumAns, " onclick=\"selectUnselectRadio(this,this.form.Ans%010u,%u)\"",
(unsigned) SvyQst->QstCod,NumAnswers); (unsigned) SvyQst->QstCod,NumAns,NumAns,
else // SvyQst->AnswerType == Svy_ANS_MULTIPLE_CHOICE (unsigned) SvyQst->QstCod,NumAnswers);
HTM_INPUT_CHECKBOX (StrAns,HTM_DONT_SUBMIT_ON_CHANGE, break;
"id=\"Ans%010u_%010u\" value=\"%u\"", case Svy_ANS_MULTIPLE_CHOICE:
(unsigned) SvyQst->QstCod,NumAns,NumAns, HTM_INPUT_CHECKBOX (StrAns,HTM_DONT_SUBMIT_ON_CHANGE,
NumAns); "id=\"Ans%010u_%u\" value=\"%u\"",
(unsigned) SvyQst->QstCod,NumAns,NumAns);
break;
default:
break;
}
HTM_TD_End ();
}
/* Write the number of option */
HTM_TD_Begin ("class=\"SVY_OPT LT\"");
HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"DAT_%s\"",
(unsigned) SvyQst->QstCod,NumAns,
The_GetSuffix ());
HTM_TxtF ("%u)",NumAns + 1);
HTM_LABEL_End ();
HTM_TD_End (); HTM_TD_End ();
}
/* Write the number of option */ /* Write the text of the answer */
HTM_TD_Begin ("class=\"SVY_OPT LT\""); HTM_TD_Begin ("class=\"LT\"");
HTM_LABEL_Begin ("for=\"Ans%010u_%010u\" class=\"DAT_%s\"", HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"DAT_%s\"",
(unsigned) SvyQst->QstCod,NumAns, (unsigned) SvyQst->QstCod,NumAns,
The_GetSuffix ()); The_GetSuffix ());
HTM_TxtF ("%u)",NumAns + 1); HTM_Txt (SvyQst->AnsChoice[NumAns].Text);
HTM_LABEL_End (); HTM_LABEL_End ();
HTM_TD_End (); HTM_TD_End ();
/* Write the text of the answer */ /* Show stats of this answer */
HTM_TD_Begin ("class=\"LT\""); if (Svy->Status.ICanViewResults)
HTM_LABEL_Begin ("for=\"Ans%010u_%010u\" class=\"DAT_%s\"", Svy_DrawBarNumUsrs (NumUsrsThisAnswer,Svy->NumUsrs);
(unsigned) SvyQst->QstCod,NumAns,
The_GetSuffix ());
HTM_Txt (SvyQst->AnsChoice[NumAns].Text);
HTM_LABEL_End ();
HTM_TD_End ();
/* Show stats of this answer */ HTM_TR_End ();
if (Svy->Status.ICanViewResults)
Svy_DrawBarNumUsrs (NumUsrsThisAnswer,Svy->NumUsrs);
HTM_TR_End (); /* Free memory allocated for the answer */
Svy_FreeTextChoiceAnswer (SvyQst,NumAns);
/* Free memory allocated for the answer */ }
Svy_FreeTextChoiceAnswer (SvyQst,NumAns);
}
HTM_TABLE_End (); HTM_TABLE_End ();
} }
else
HTM_BR ();
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
} }
/*****************************************************************************/
/************** Get and write the answers of a survey question ***************/
/*****************************************************************************/
static void Svy_WriteCommentsOfAQst (struct Svy_Survey *Svy,
struct Svy_Question *SvyQst,
bool PutFormAnswerSurvey)
{
if (PutFormAnswerSurvey)
{
HTM_TEXTAREA_Begin ("name=\"Comments\""
" cols=\"60\" rows=\"4\""
" class=\"INPUT_%s\"",
The_GetSuffix ());
HTM_TEXTAREA_End ();
}
else if (Svy->Status.ICanViewComments)
{
HTM_Txt ("Comentarios..."); // TODO
}
}
/*****************************************************************************/ /*****************************************************************************/
/***************** Draw a bar with the percentage of answers *****************/ /***************** Draw a bar with the percentage of answers *****************/
/*****************************************************************************/ /*****************************************************************************/

View File

@ -60,6 +60,7 @@ struct Svy_Survey
bool IHaveAnswered; // I have already answered this survey bool IHaveAnswered; // I have already answered this survey
bool ICanAnswer; bool ICanAnswer;
bool ICanViewResults; bool ICanViewResults;
bool ICanViewComments;
bool ICanEdit; bool ICanEdit;
} Status; } Status;
}; };
@ -83,6 +84,19 @@ typedef enum
} Svy_AnswerType_t; } Svy_AnswerType_t;
#define Svy_ANSWER_TYPE_DEFAULT Svy_ANS_UNIQUE_CHOICE #define Svy_ANSWER_TYPE_DEFAULT Svy_ANS_UNIQUE_CHOICE
#define Svy_MAX_ANSWERS_PER_QUESTION 10
struct Svy_Question // 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 CommentsAllowed;
};
/*****************************************************************************/ /*****************************************************************************/
/***************************** Public prototypes *****************************/ /***************************** Public prototypes *****************************/
/*****************************************************************************/ /*****************************************************************************/

View File

@ -836,19 +836,21 @@ void Svy_DB_RemoveGrpsSvysIn (HieLvl_Level_t Scope,long Cod)
/*************************** Create a new question ***************************/ /*************************** Create a new question ***************************/
/*****************************************************************************/ /*****************************************************************************/
long Svy_DB_CreateQuestion (long SvyCod,unsigned QstInd, long Svy_DB_CreateQuestion (long SvyCod,
Svy_AnswerType_t AnswerType, const struct Svy_Question *SvyQst,
const char Stem[Cns_MAX_BYTES_TEXT + 1]) const char Stem[Cns_MAX_BYTES_TEXT + 1])
{ {
return return
DB_QueryINSERTandReturnCode ("can not create question", DB_QueryINSERTandReturnCode ("can not create question",
"INSERT INTO svy_questions" "INSERT INTO svy_questions"
" (SvyCod,QstInd,AnsType,Stem)" " (SvyCod,QstInd,AnsType,CommentsAllowed,Stem)"
" VALUES" " VALUES"
" (%ld,%u,'%s','%s')", " (%ld,%u,'%s','%c','%s')",
SvyCod, SvyCod,
QstInd, SvyQst->QstInd,
Svy_DB_StrAnswerTypes[AnswerType], Svy_DB_StrAnswerTypes[SvyQst->AnswerType],
SvyQst->CommentsAllowed ? 'Y' :
'N',
Stem); Stem);
} }
@ -856,19 +858,22 @@ long Svy_DB_CreateQuestion (long SvyCod,unsigned QstInd,
/************************ Create an existing question ************************/ /************************ Create an existing question ************************/
/*****************************************************************************/ /*****************************************************************************/
void Svy_DB_UpdateQuestion (long SvyCod,long QstCod, void Svy_DB_UpdateQuestion (long SvyCod,
Svy_AnswerType_t AnswerType, const struct Svy_Question *SvyQst,
const char Stem[Cns_MAX_BYTES_TEXT + 1]) const char Stem[Cns_MAX_BYTES_TEXT + 1])
{ {
DB_QueryUPDATE ("can not update question", DB_QueryUPDATE ("can not update question",
"UPDATE svy_questions" "UPDATE svy_questions"
" SET Stem='%s'," " SET Stem='%s',"
"AnsType='%s'" "AnsType='%s',"
"CommentsAllowed='%c'"
" WHERE QstCod=%ld" " WHERE QstCod=%ld"
" AND SvyCod=%ld", // Extra check " AND SvyCod=%ld", // Extra check
Stem, Stem,
Svy_DB_StrAnswerTypes[AnswerType], Svy_DB_StrAnswerTypes[SvyQst->AnswerType],
QstCod, SvyQst->CommentsAllowed ? 'Y' :
'N',
SvyQst->QstCod,
SvyCod); SvyCod);
} }
@ -924,10 +929,11 @@ unsigned Svy_DB_GetSurveyQsts (MYSQL_RES **mysql_res,long SvyCod)
{ {
return (unsigned) return (unsigned)
DB_QuerySELECT (mysql_res,"can not get data of questions of a survey", DB_QuerySELECT (mysql_res,"can not get data of questions of a survey",
"SELECT QstCod," // row[0] "SELECT QstCod," // row[0]
"QstInd," // row[1] "QstInd," // row[1]
"AnsType," // row[2] "AnsType," // row[2]
"Stem" // row[3] "CommentsAllowed," // row[3]
"Stem" // row[4]
" FROM svy_questions" " FROM svy_questions"
" WHERE SvyCod=%ld" " WHERE SvyCod=%ld"
" ORDER BY QstInd", " ORDER BY QstInd",
@ -942,10 +948,11 @@ unsigned Svy_DB_GetQstDataByCod (MYSQL_RES **mysql_res,long QstCod,long SvyCod)
{ {
return (unsigned) return (unsigned)
DB_QuerySELECT (mysql_res,"can not get a question", DB_QuerySELECT (mysql_res,"can not get a question",
"SELECT QstCod," // row[0] "SELECT QstCod," // row[0]
"QstInd," // row[1] "QstInd," // row[1]
"AnsType," // row[2] "AnsType," // row[2]
"Stem" // row[3] "CommentsAllowed," // row[3]
"Stem" // row[4]
" FROM svy_questions" " FROM svy_questions"
" WHERE QstCod=%ld" " WHERE QstCod=%ld"
" AND SvyCod=%ld", // Extra check " AND SvyCod=%ld", // Extra check
@ -1110,10 +1117,7 @@ bool Svy_DB_CheckIfAnswerExists (long QstCod,unsigned AnsInd)
unsigned Svy_DB_GetAnswersQst (MYSQL_RES **mysql_res,long QstCod) unsigned Svy_DB_GetAnswersQst (MYSQL_RES **mysql_res,long QstCod)
{ {
unsigned NumAnswers; return (unsigned)
/***** Get answers of a question from database *****/
NumAnswers = (unsigned)
DB_QuerySELECT (mysql_res,"can not get answers of a question", DB_QuerySELECT (mysql_res,"can not get answers of a question",
"SELECT AnsInd," // row[0] "SELECT AnsInd," // row[0]
"NumUsrs," // row[1] "NumUsrs," // row[1]
@ -1122,10 +1126,6 @@ unsigned Svy_DB_GetAnswersQst (MYSQL_RES **mysql_res,long QstCod)
" WHERE QstCod=%ld" " WHERE QstCod=%ld"
" ORDER BY AnsInd", " ORDER BY AnsInd",
QstCod); QstCod);
if (!NumAnswers)
Err_WrongAnswerExit ();
return NumAnswers;
} }
/*****************************************************************************/ /*****************************************************************************/

View File

@ -73,11 +73,11 @@ void Svy_DB_RemoveGrpsAssociatedToSurvey (long SvyCod);
void Svy_DB_RemoveGrpsSvysIn (HieLvl_Level_t Scope,long Cod); void Svy_DB_RemoveGrpsSvysIn (HieLvl_Level_t Scope,long Cod);
//--------------------------- Surveys questions ------------------------------- //--------------------------- Surveys questions -------------------------------
long Svy_DB_CreateQuestion (long SvyCod,unsigned QstInd, long Svy_DB_CreateQuestion (long SvyCod,
Svy_AnswerType_t AnswerType, const struct Svy_Question *SvyQst,
const char Stem[Cns_MAX_BYTES_TEXT + 1]); const char Stem[Cns_MAX_BYTES_TEXT + 1]);
void Svy_DB_UpdateQuestion (long SvyCod,long QstCod, void Svy_DB_UpdateQuestion (long SvyCod,
Svy_AnswerType_t AnswerType, const struct Svy_Question *SvyQst,
const char Stem[Cns_MAX_BYTES_TEXT + 1]); const char Stem[Cns_MAX_BYTES_TEXT + 1]);
void Svy_DB_ChangeIndexesQsts (long SvyCod,unsigned QstInd); void Svy_DB_ChangeIndexesQsts (long SvyCod,unsigned QstInd);

View File

@ -5429,7 +5429,30 @@ const char *Txt_Comments =
#elif L==9 // pt #elif L==9 // pt
"Coment&aacute;rios"; "Coment&aacute;rios";
#elif L==10 // tr #elif L==10 // tr
"Comments"; // Çeviri lazim! "Yorumlar";
#endif
const char *Txt_Comments_allowed =
#if L==1 // ca
"Comentaris permesos";
#elif L==2 // de
"Kommentare erlaubt";
#elif L==3 // en
"Comments allowed";
#elif L==4 // es
"Comentarios permitidos";
#elif L==5 // fr
"Commentaires autoris&eacute;s";
#elif L==6 // gn
"Ojeheja umi comentario";
#elif L==7 // it
"Commenti consentiti";
#elif L==8 // pl
"Komentarze dozwolone";
#elif L==9 // pt
"Coment&aacute;rios permitidos";
#elif L==10 // tr
"Yorumlara izin verilir";
#endif #endif
const char *Txt_Configure_projects = const char *Txt_Configure_projects =
@ -28515,6 +28538,29 @@ const char *Txt_optional =
"optional"; // Çeviri lazim! "optional"; // Çeviri lazim!
#endif #endif
const char *Txt_Options =
#if L==1 // ca
"Opcions";
#elif L==2 // de
"Optionen";
#elif L==3 // en
"Options";
#elif L==4 // es
"Opciones";
#elif L==5 // fr
"Choix";
#elif L==6 // gn
"Opciones";
#elif L==7 // it
"Opzioni";
#elif L==8 // pl
"Opcje";
#elif L==9 // pt
"Op&ccedil;&otilde;es";
#elif L==10 // tr
"Se&ccedil;enekler";
#endif
const char *Txt_or_you_can_create_a_new_link_inside_the_folder_X = // Warning: it is very important to include %s in the following sentences const char *Txt_or_you_can_create_a_new_link_inside_the_folder_X = // Warning: it is very important to include %s in the following sentences
#if L==1 // ca #if L==1 // ca
"&hellip;o pot crear un novo enlla&ccedil;" "&hellip;o pot crear un novo enlla&ccedil;"