Version 15.183

This commit is contained in:
Antonio Cañas Vargas 2016-04-06 14:41:47 +02:00
parent dcd1dd8f53
commit ed9d37dc91
6 changed files with 186 additions and 96 deletions

View File

@ -126,18 +126,24 @@
// TODO: Do not show e-mails of administrators and teachers in lists openly // TODO: Do not show e-mails of administrators and teachers in lists openly
// TODO: Fix bug in marks reported by Francisco Ocaña // TODO: Fix bug in marks reported by Francisco Ocaña
// TODO: In Statistics > Degrees, show only degrees with students // TODO: In Statistics > Degrees, show only degrees with students
// TODO: Change PhotoAttribution in table centres from TEXT to VARCHAR(255) (check maximum length first)
/*****************************************************************************/ /*****************************************************************************/
/****************************** Public constants *****************************/ /****************************** Public constants *****************************/
/*****************************************************************************/ /*****************************************************************************/
#define Log_PLATFORM_VERSION "SWAD 15.182 (2016-04-06)" #define Log_PLATFORM_VERSION "SWAD 15.183 (2016-04-06)"
#define CSS_FILE "swad15.178.2.css" #define CSS_FILE "swad15.178.2.css"
#define JS_FILE "swad15.178.2.js" #define JS_FILE "swad15.178.2.js"
// Number of lines (includes comments but not blank lines) has been got with the following command: // Number of lines (includes comments but not blank lines) has been got with the following command:
// nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*.h sql/swad*.sql | tail -1 // nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*.h sql/swad*.sql | tail -1
/* /*
Version 15.183: Apr 06, 2016 Change in length of title/attribution of images. (198704 lines)
2 changes necessary in database:
ALTER TABLE tst_questions CHANGE COLUMN ImageTitle ImageTitle VARCHAR(255) NOT NULL;
ALTER TABLE tst_answers CHANGE COLUMN ImageTitle ImageTitle VARCHAR(255) NOT NULL;
Version 15.182: Apr 06, 2016 Get fields title/attribution of images from form. (198610 lines) Version 15.182: Apr 06, 2016 Get fields title/attribution of images from form. (198610 lines)
4 changes necessary in database: 4 changes necessary in database:
ALTER TABLE tst_questions CHANGE COLUMN Image ImageName VARCHAR(43) NOT NULL; ALTER TABLE tst_questions CHANGE COLUMN Image ImageName VARCHAR(43) NOT NULL;

View File

@ -2298,10 +2298,10 @@ mysql> DESCRIBE tst_answers;
| Answer | text | NO | | NULL | | | Answer | text | NO | | NULL | |
| Feedback | text | NO | | NULL | | | Feedback | text | NO | | NULL | |
| ImageName | varchar(43) | NO | | NULL | | | ImageName | varchar(43) | NO | | NULL | |
| ImageTitle | text | NO | | NULL | | | ImageTitle | varchar(255) | NO | | NULL | |
| Correct | enum('N','Y') | NO | | NULL | | | Correct | enum('N','Y') | NO | | NULL | |
+------------+---------------+------+-----+---------+-------+ +------------+---------------+------+-----+---------+-------+
7 rows in set (0.00 sec) 7 rows in set (0.01 sec)
*/ */
DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_answers (" DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_answers ("
"QstCod INT NOT NULL," "QstCod INT NOT NULL,"
@ -2309,7 +2309,7 @@ mysql> DESCRIBE tst_answers;
"Answer TEXT NOT NULL," "Answer TEXT NOT NULL,"
"Feedback TEXT NOT NULL," "Feedback TEXT NOT NULL,"
"ImageName VARCHAR(43) NOT NULL," "ImageName VARCHAR(43) NOT NULL,"
"ImageTitle TEXT NOT NULL," "ImageTitle VARCHAR(255) NOT NULL,"
"Correct ENUM('N','Y') NOT NULL," "Correct ENUM('N','Y') NOT NULL,"
"INDEX(QstCod))"); "INDEX(QstCod))");
@ -2424,7 +2424,7 @@ mysql> DESCRIBE tst_questions;
| Stem | text | NO | | NULL | | | Stem | text | NO | | NULL | |
| Feedback | text | NO | | NULL | | | Feedback | text | NO | | NULL | |
| ImageName | varchar(43) | NO | | NULL | | | ImageName | varchar(43) | NO | | NULL | |
| ImageTitle | text | NO | | NULL | | | ImageTitle | varchar(255) | NO | | NULL | |
| NumHits | int(11) | NO | | 0 | | | NumHits | int(11) | NO | | 0 | |
| NumHitsNotBlank | int(11) | NO | | 0 | | | NumHitsNotBlank | int(11) | NO | | 0 | |
| Score | double | NO | | 0 | | | Score | double | NO | | 0 | |
@ -2440,7 +2440,7 @@ mysql> DESCRIBE tst_questions;
"Stem TEXT NOT NULL," "Stem TEXT NOT NULL,"
"Feedback TEXT NOT NULL," "Feedback TEXT NOT NULL,"
"ImageName VARCHAR(43) NOT NULL," "ImageName VARCHAR(43) NOT NULL,"
"ImageTitle TEXT NOT NULL," "ImageTitle VARCHAR(255) NOT NULL,"
"NumHits INT NOT NULL DEFAULT 0," "NumHits INT NOT NULL DEFAULT 0,"
"NumHitsNotBlank INT NOT NULL DEFAULT 0," "NumHitsNotBlank INT NOT NULL DEFAULT 0,"
"Score DOUBLE PRECISION NOT NULL DEFAULT 0," "Score DOUBLE PRECISION NOT NULL DEFAULT 0,"

View File

@ -79,11 +79,11 @@ void Img_ResetImageTitle (struct Image *Image)
} }
/*****************************************************************************/ /*****************************************************************************/
/************ Get image title from a string and copy to struct ***************/ /********* Get image name and title from strings and copy to struct **********/
/*****************************************************************************/ /*****************************************************************************/
void Img_GetImageNameTitle (const char *Name,const char *Title, void Img_GetImageNameAndTitle (const char *Name,const char *Title,
struct Image *Image) struct Image *Image)
{ {
size_t Length; size_t Length;
@ -97,7 +97,11 @@ void Img_GetImageNameTitle (const char *Name,const char *Title,
if (Image->Name[0]) // There is an image if (Image->Name[0]) // There is an image
if (Title[0]) if (Title[0])
{ {
/* Get and limit length of the title */
Length = strlen (Title); Length = strlen (Title);
if (Length > Img_MAX_BYTES_TITLE)
Length = Img_MAX_BYTES_TITLE;
if ((Image->Title = (char *) malloc (Length+1)) == NULL) if ((Image->Title = (char *) malloc (Length+1)) == NULL)
Lay_ShowErrorAndExit ("Error allocating memory for image title."); Lay_ShowErrorAndExit ("Error allocating memory for image title.");
strncpy (Image->Title,Title,Length); strncpy (Image->Title,Title,Length);
@ -195,7 +199,7 @@ void Img_GetAndProcessImageFileFromForm (struct Image *Image,
char FileNameImgOrig[PATH_MAX+1]; // Full name of original uploaded file char FileNameImgOrig[PATH_MAX+1]; // Full name of original uploaded file
char FileNameImgTmp[PATH_MAX+1]; // Full name of temporary processed file char FileNameImgTmp[PATH_MAX+1]; // Full name of temporary processed file
bool WrongType = false; bool WrongType = false;
char Title[Cns_MAX_BYTES_TEXT+1]; char Title[Img_MAX_BYTES_TITLE+1];
size_t Length; size_t Length;
/***** Rest image file status *****/ /***** Rest image file status *****/
@ -263,7 +267,7 @@ void Img_GetAndProcessImageFileFromForm (struct Image *Image,
unlink (FileNameImgOrig); unlink (FileNameImgOrig);
/***** Get image title from form *****/ /***** Get image title from form *****/
Par_GetParToHTML (ParamTitle,Title,Cns_MAX_BYTES_TEXT); // TODO: Create a function to get only the length of a parameter Par_GetParToHTML (ParamTitle,Title,Img_MAX_BYTES_TITLE); // TODO: Create a function to get only the length of a parameter
Length = strlen (Title); Length = strlen (Title);
if (Length > 0) if (Length > 0)
{ {
@ -386,9 +390,13 @@ void Img_ShowImage (struct Image *Image,const char *ClassImg)
/***** Show image *****/ /***** Show image *****/
fprintf (Gbl.F.Out,"<div>" fprintf (Gbl.F.Out,"<div>"
"<img src=\"%s\" alt=\"\" class=\"%s\"/>" "<img src=\"%s\" class=\"%s\" alt=\"\"",
"</div>",
URL,ClassImg); URL,ClassImg);
if (Image->Title)
if (Image->Title[0])
fprintf (Gbl.F.Out," title=\"%s\"",Image->Title);
fprintf (Gbl.F.Out," />"
"</div>");
} }
else else
Lay_ShowAlert (Lay_WARNING,Txt_Image_not_found); Lay_ShowAlert (Lay_WARNING,Txt_Image_not_found);

View File

@ -31,6 +31,8 @@
/***************************** Public constants ******************************/ /***************************** Public constants ******************************/
/*****************************************************************************/ /*****************************************************************************/
#define Img_MAX_BYTES_TITLE 255
/*****************************************************************************/ /*****************************************************************************/
/******************************* Public types ********************************/ /******************************* Public types ********************************/
/*****************************************************************************/ /*****************************************************************************/
@ -93,8 +95,8 @@ struct Image
/*****************************************************************************/ /*****************************************************************************/
void Img_ResetImageTitle (struct Image *Image); void Img_ResetImageTitle (struct Image *Image);
void Img_GetImageNameTitle (const char *Name,const char *Title, void Img_GetImageNameAndTitle (const char *Name,const char *Title,
struct Image *Image); struct Image *Image);
void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image, void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image,
void (*GetImageNameFromDB) (unsigned NumOpt,struct Image *Image), void (*GetImageNameFromDB) (unsigned NumOpt,struct Image *Image),

View File

@ -155,8 +155,8 @@ static void Tst_ShowTestQuestionsWhenSeeing (MYSQL_RES *mysql_res);
static void Tst_ShowTstResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank,double *TotalScore); static void Tst_ShowTstResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank,double *TotalScore);
static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row, static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
double *ScoreThisQst,bool *AnswerIsNotBlank); double *ScoreThisQst,bool *AnswerIsNotBlank);
static void Tst_PutFormToEditQstImage (struct Image *Image,const char *ClassImg, static void Tst_PutFormToEditQstImage (struct Image *Image,
const char *TitleAttribution,const char *ClassTitle, const char *ClassImg,const char *ClassTitle,
const char *ParamAction, const char *ParamAction,
const char *ParamFile, const char *ParamFile,
const char *ParamTitle, const char *ParamTitle,
@ -1002,7 +1002,7 @@ static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
if (row[6][0]) if (row[6][0])
{ {
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameTitle (row[6],row[7],&Gbl.Test.Image); Img_GetImageNameAndTitle (row[6],row[7],&Gbl.Test.Image);
Img_ShowImage (&Gbl.Test.Image,"TEST_IMG_SHOW_STEM"); Img_ShowImage (&Gbl.Test.Image,"TEST_IMG_SHOW_STEM");
} }
if (Gbl.Action.Act == ActSeeTst) if (Gbl.Action.Act == ActSeeTst)
@ -1053,8 +1053,8 @@ void Tst_WriteQstStem (const char *Stem,const char *ClassStem)
/************* Put form to upload a new image for a test question ************/ /************* Put form to upload a new image for a test question ************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_PutFormToEditQstImage (struct Image *Image,const char *ClassImg, static void Tst_PutFormToEditQstImage (struct Image *Image,
const char *TitleAttribution,const char *ClassTitle, const char *ClassImg,const char *ClassTitle,
const char *ParamAction, const char *ParamAction,
const char *ParamFile, const char *ParamFile,
const char *ParamTitle, const char *ParamTitle,
@ -1147,14 +1147,12 @@ static void Tst_PutFormToEditQstImage (struct Image *Image,const char *ClassImg,
fprintf (Gbl.F.Out,"<label class=\"%s\">" fprintf (Gbl.F.Out,"<label class=\"%s\">"
"%s (%s):" "%s (%s):"
"</label><br />" "</label><br />"
"<textarea name=\"%s\" class=\"%s\" rows=\"1\">", "<input type=\"text\" name=\"%s\" class=\"%s\""
" maxlength=\"%u\" value=\"%s\">",
The_ClassForm[Gbl.Prefs.Theme], The_ClassForm[Gbl.Prefs.Theme],
Txt_Image_title_attribution,Txt_optional, Txt_Image_title_attribution,Txt_optional,
ParamTitle,ClassTitle); ParamTitle,ClassTitle,
if (TitleAttribution) Img_MAX_BYTES_TITLE,Image->Title ? Image->Title : "");
if (TitleAttribution[0])
fprintf (Gbl.F.Out,"%s",TitleAttribution);
fprintf (Gbl.F.Out,"</textarea>");
/***** End container *****/ /***** End container *****/
fprintf (Gbl.F.Out,"</div>"); fprintf (Gbl.F.Out,"</div>");
@ -2803,7 +2801,7 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
if (row[6][0]) if (row[6][0])
{ {
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameTitle (row[6],row[7],&Gbl.Test.Image); Img_GetImageNameAndTitle (row[6],row[7],&Gbl.Test.Image);
Img_ShowImage (&Gbl.Test.Image,"TEST_IMG_EDIT_LIST_STEM"); Img_ShowImage (&Gbl.Test.Image,"TEST_IMG_EDIT_LIST_STEM");
} }
Tst_WriteQstFeedback (row[5],"TEST_EDI_LIGHT"); Tst_WriteQstFeedback (row[5],"TEST_EDI_LIGHT");
@ -2901,13 +2899,12 @@ void Tst_WriteParamEditQst (void)
unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle) unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle)
{ {
char Query[512]; char Query[256];
unsigned long NumRows; unsigned long NumRows;
/***** Get answers of a question from database *****/ /***** Get answers of a question from database *****/
sprintf (Query,"SELECT AnsInd,Answer,Correct,Feedback,ImageName,ImageTitle" sprintf (Query,"SELECT AnsInd,Answer,Feedback,ImageName,ImageTitle,Correct"
" FROM tst_answers" " FROM tst_answers WHERE QstCod='%ld' ORDER BY %s",
" WHERE QstCod='%ld' ORDER BY %s",
QstCod, QstCod,
Shuffle ? "RAND(NOW())" : Shuffle ? "RAND(NOW())" :
"AnsInd"); "AnsInd");
@ -2935,7 +2932,14 @@ static void Tst_WriteAnswersOfAQstEdit (long QstCod)
double FloatNum[2]; double FloatNum[2];
Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct,Feedback Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct,Feedback
/*
row[ 0] AnsInd
row[ 1] Answer
row[ 2] Feedback
row[ 3] ImageName
row[ 4] ImageTitle
row[ 5] Correct
*/
/***** Write the answers *****/ /***** Write the answers *****/
switch (Gbl.Test.AnswerType) switch (Gbl.Test.AnswerType)
{ {
@ -2985,33 +2989,33 @@ static void Tst_WriteAnswersOfAQstEdit (long QstCod)
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Answer,LengthAnswer,false); Answer,LengthAnswer,false);
/* Convert the feedback (row[3]), that is in HTML, to rigorous HTML */ /* Convert the feedback (row[2]), that is in HTML, to rigorous HTML */
LengthFeedback = 0; LengthFeedback = 0;
Feedback = NULL; Feedback = NULL;
if (row[3]) if (row[2])
if (row[3][0]) if (row[2][0])
{ {
LengthFeedback = strlen (row[3]) * Str_MAX_LENGTH_SPEC_CHAR_HTML; LengthFeedback = strlen (row[2]) * Str_MAX_LENGTH_SPEC_CHAR_HTML;
if ((Feedback = malloc (LengthFeedback+1)) == NULL) if ((Feedback = malloc (LengthFeedback+1)) == NULL)
Lay_ShowErrorAndExit ("Not enough memory to store feedback."); Lay_ShowErrorAndExit ("Not enough memory to store feedback.");
strncpy (Feedback,row[3],LengthFeedback); strncpy (Feedback,row[2],LengthFeedback);
Feedback[LengthFeedback] = '\0'; Feedback[LengthFeedback] = '\0';
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Feedback,LengthFeedback,false); Feedback,LengthFeedback,false);
} }
/* Copy image */ /* Copy image */
if (row[4][0]) if (row[3][0])
{ {
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameTitle (row[4],row[5],&Gbl.Test.Answer.Options[NumOpt].Image); Img_GetImageNameAndTitle (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
} }
/* Put an icon that indicates whether the answer is correct or wrong */ /* Put an icon that indicates whether the answer is correct or wrong */
fprintf (Gbl.F.Out,"<tr>" fprintf (Gbl.F.Out,"<tr>"
"<td class=\"BT%u\">", "<td class=\"BT%u\">",
Gbl.RowEvenOdd); Gbl.RowEvenOdd);
if (Str_ConvertToUpperLetter (row[2][0]) == 'Y') if (Str_ConvertToUpperLetter (row[5][0]) == 'Y')
fprintf (Gbl.F.Out,"<img src=\"%s/ok_on16x16.gif\"" fprintf (Gbl.F.Out,"<img src=\"%s/ok_on16x16.gif\""
" alt=\"%s\" title=\"%s\"" " alt=\"%s\" title=\"%s\""
" class=\"ICON20x20\" />", " class=\"ICON20x20\" />",
@ -3026,7 +3030,7 @@ static void Tst_WriteAnswersOfAQstEdit (long QstCod)
"</td>", "</td>",
'a' + (char) NumOpt); 'a' + (char) NumOpt);
/* Write the text of the answer and the image (row[4]) */ /* Write the text of the answer and the image */
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP\">" fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP\">"
"<div class=\"TEST_EDI\">" "<div class=\"TEST_EDI\">"
"%s", "%s",
@ -3102,7 +3106,14 @@ static void Tst_WriteAnswersOfAQstAssessExam (unsigned NumQst,long QstCod,
/***** Get answers of a question from database *****/ /***** Get answers of a question from database *****/
Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct
/*
row[ 0] AnsInd
row[ 1] Answer
row[ 2] Feedback
row[ 3] ImageName
row[ 4] ImageTitle
row[ 5] Correct
*/
/***** Write answer depending on type *****/ /***** Write answer depending on type *****/
switch (Gbl.Test.AnswerType) switch (Gbl.Test.AnswerType)
{ {
@ -3180,7 +3191,14 @@ static void Tst_WriteTFAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
{ {
MYSQL_ROW row; MYSQL_ROW row;
char AnsTF; char AnsTF;
/*
row[ 0] AnsInd
row[ 1] Answer
row[ 2] Feedback
row[ 3] ImageName
row[ 4] ImageTitle
row[ 5] Correct
*/
/***** Check if number of rows is correct *****/ /***** Check if number of rows is correct *****/
Tst_CheckIfNumberOfAnswersIsOne (); Tst_CheckIfNumberOfAnswersIsOne ();
@ -3266,6 +3284,14 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
/***** Get answers of a question from database *****/ /***** Get answers of a question from database *****/
Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,Shuffle); // Result: AnsInd,Answer,Correct Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,Shuffle); // Result: AnsInd,Answer,Correct
/*
row[ 0] AnsInd
row[ 1] Answer
row[ 2] Feedback
row[ 3] ImageName
row[ 4] ImageTitle
row[ 5] Correct
*/
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions; NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++) NumOpt++)
@ -3296,10 +3322,10 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
Gbl.Test.Answer.Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); Gbl.Test.Answer.Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
/***** Copy image *****/ /***** Copy image *****/
if (row[4][0]) if (row[3][0])
{ {
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameTitle (row[4],row[5],&Gbl.Test.Answer.Options[NumOpt].Image); Img_GetImageNameAndTitle (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
} }
/***** Write selectors and letter of this option *****/ /***** Write selectors and letter of this option *****/
@ -3364,11 +3390,12 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
/***** Get text and correctness of answers for this question /***** Get text and correctness of answers for this question
from database (one row per answer) *****/ from database (one row per answer) *****/
/* /*
row[0] AnsInd row[ 0] AnsInd
row[1] Answer row[ 1] Answer
row[2] Correct row[ 2] Feedback
row[3] Feedback row[ 3] ImageName
row[4] ImageName row[ 4] ImageTitle
row[ 5] Correct
*/ */
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions; NumOpt < Gbl.Test.Answer.NumOptions;
@ -3388,27 +3415,27 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Gbl.Test.Answer.Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); Gbl.Test.Answer.Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
/***** Copy answer feedback (row[3]) and convert it, /***** Copy answer feedback (row[2]) and convert it,
that is in HTML, to rigorous HTML ******/ that is in HTML, to rigorous HTML ******/
if (Gbl.Test.Config.FeedbackType == Tst_FEEDBACK_FULL_FEEDBACK) if (Gbl.Test.Config.FeedbackType == Tst_FEEDBACK_FULL_FEEDBACK)
if (row[3]) if (row[2])
if (row[3][0]) if (row[2][0])
{ {
strncpy (Gbl.Test.Answer.Options[NumOpt].Feedback,row[3],Tst_MAX_BYTES_ANSWER_OR_FEEDBACK); strncpy (Gbl.Test.Answer.Options[NumOpt].Feedback,row[2],Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
Gbl.Test.Answer.Options[NumOpt].Feedback[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0'; Gbl.Test.Answer.Options[NumOpt].Feedback[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0';
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Gbl.Test.Answer.Options[NumOpt].Feedback,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); Gbl.Test.Answer.Options[NumOpt].Feedback,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
} }
/***** Copy image *****/ /***** Copy image *****/
if (row[4][0]) if (row[3][0])
{ {
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameTitle (row[4],row[5],&Gbl.Test.Answer.Options[NumOpt].Image); Img_GetImageNameAndTitle (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
} }
/***** Assign correctness (row[2]) of this answer (this option) *****/ /***** Assign correctness (row[5]) of this answer (this option) *****/
Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[2][0]) == 'Y'); Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[5][0]) == 'Y');
} }
/***** Get indexes for this question from string *****/ /***** Get indexes for this question from string *****/
@ -3606,7 +3633,14 @@ static void Tst_WriteTextAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
MYSQL_ROW row; MYSQL_ROW row;
char TextAnsUsr[Tst_MAX_SIZE_ANSWERS_ONE_QST],TextAnsOK[Tst_MAX_SIZE_ANSWERS_ONE_QST]; char TextAnsUsr[Tst_MAX_SIZE_ANSWERS_ONE_QST],TextAnsOK[Tst_MAX_SIZE_ANSWERS_ONE_QST];
bool Correct = false; bool Correct = false;
/*
row[ 0] AnsInd
row[ 1] Answer
row[ 2] Feedback
row[ 3] ImageName
row[ 4] ImageTitle
row[ 5] Correct
*/
/***** Get text and correctness of answers for this question from database (one row per answer) *****/ /***** Get text and correctness of answers for this question from database (one row per answer) *****/
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions; NumOpt < Gbl.Test.Answer.NumOptions;
@ -3624,19 +3658,19 @@ static void Tst_WriteTextAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
Gbl.Test.Answer.Options[NumOpt].Text[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0'; Gbl.Test.Answer.Options[NumOpt].Text[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0';
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,Gbl.Test.Answer.Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,Gbl.Test.Answer.Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
/***** Copy answer feedback (row[3]) and convert it, that is in HTML, to rigorous HTML ******/ /***** Copy answer feedback (row[2]) and convert it, that is in HTML, to rigorous HTML ******/
if (Gbl.Test.Config.FeedbackType == Tst_FEEDBACK_FULL_FEEDBACK) if (Gbl.Test.Config.FeedbackType == Tst_FEEDBACK_FULL_FEEDBACK)
if (row[3]) if (row[2])
if (row[3][0]) if (row[2][0])
{ {
strncpy (Gbl.Test.Answer.Options[NumOpt].Feedback,row[3],Tst_MAX_BYTES_ANSWER_OR_FEEDBACK); strncpy (Gbl.Test.Answer.Options[NumOpt].Feedback,row[2],Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
Gbl.Test.Answer.Options[NumOpt].Feedback[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0'; Gbl.Test.Answer.Options[NumOpt].Feedback[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0';
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
Gbl.Test.Answer.Options[NumOpt].Feedback,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); Gbl.Test.Answer.Options[NumOpt].Feedback,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
} }
/***** Assign correctness (row[2]) of this answer (this option) *****/ /***** Assign correctness (row[5]) of this answer (this option) *****/
Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[2][0]) == 'Y'); Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[5][0]) == 'Y');
} }
/***** Header with the title of each column *****/ /***** Header with the title of each column *****/
@ -3781,7 +3815,14 @@ static void Tst_WriteIntAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
{ {
MYSQL_ROW row; MYSQL_ROW row;
long IntAnswerUsr,IntAnswerCorr; long IntAnswerUsr,IntAnswerCorr;
/*
row[ 0] AnsInd
row[ 1] Answer
row[ 2] Feedback
row[ 3] ImageName
row[ 4] ImageTitle
row[ 5] Correct
*/
/***** Check if number of rows is correct *****/ /***** Check if number of rows is correct *****/
Tst_CheckIfNumberOfAnswersIsOne (); Tst_CheckIfNumberOfAnswersIsOne ();
@ -3887,7 +3928,14 @@ static void Tst_WriteFloatAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
unsigned i; unsigned i;
double FloatAnsUsr = 0.0,Tmp; double FloatAnsUsr = 0.0,Tmp;
double FloatAnsCorr[2]; double FloatAnsCorr[2];
/*
row[ 0] AnsInd
row[ 1] Answer
row[ 2] Feedback
row[ 3] ImageName
row[ 4] ImageTitle
row[ 5] Correct
*/
/***** Check if number of rows is correct *****/ /***** Check if number of rows is correct *****/
if (Gbl.Test.Answer.NumOptions != 2) if (Gbl.Test.Answer.NumOptions != 2)
Lay_ShowErrorAndExit ("Wrong float range."); Lay_ShowErrorAndExit ("Wrong float range.");
@ -4464,7 +4512,7 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
Txt_Stem, Txt_Stem,
Stem); Stem);
Tst_PutFormToEditQstImage (&Gbl.Test.Image,"TEST_IMG_EDIT_ONE_STEM", Tst_PutFormToEditQstImage (&Gbl.Test.Image,"TEST_IMG_EDIT_ONE_STEM",
NULL,"STEM", // Title / attribution "STEM", // Title / attribution
"ImgAct","FilImg","TitImg",false); "ImgAct","FilImg","TitImg",false);
/***** Feedback *****/ /***** Feedback *****/
@ -4645,7 +4693,7 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
sprintf (ParamTitle ,"TitImg%u",NumOpt); sprintf (ParamTitle ,"TitImg%u",NumOpt);
Tst_PutFormToEditQstImage (&Gbl.Test.Answer.Options[NumOpt].Image, Tst_PutFormToEditQstImage (&Gbl.Test.Answer.Options[NumOpt].Image,
"TEST_IMG_EDIT_ONE_ANS", "TEST_IMG_EDIT_ONE_ANS",
NULL,"ANS_STR", // Title / attribution "ANS_STR", // Title / attribution
ParamAction,ParamFile,ParamTitle, ParamAction,ParamFile,ParamTitle,
OptionsDisabled); OptionsDisabled);
fprintf (Gbl.F.Out,"</td>" fprintf (Gbl.F.Out,"</td>"
@ -4791,7 +4839,14 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
DB_QuerySELECT (Query,&mysql_res,"can not get a question"); DB_QuerySELECT (Query,&mysql_res,"can not get a question");
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/*
row[ 0] AnsType
row[ 1] Shuffle
row[ 2] Stem
row[ 3] Feedback
row[ 4] ImageName
row[ 5] ImageTitle
*/
/* Get the type of answer */ /* Get the type of answer */
Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]); Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]);
@ -4807,7 +4862,7 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
if (row[3]) if (row[3])
if (row[3][0]) if (row[3][0])
{ {
strncpy (Feedback,row[4],Cns_MAX_BYTES_TEXT); strncpy (Feedback,row[3],Cns_MAX_BYTES_TEXT);
Feedback[Cns_MAX_BYTES_TEXT] = '\0'; Feedback[Cns_MAX_BYTES_TEXT] = '\0';
} }
@ -4815,7 +4870,7 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
if (row[4][0]) if (row[4][0])
{ {
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameTitle (row[4],row[5],&Gbl.Test.Image); Img_GetImageNameAndTitle (row[4],row[5],&Gbl.Test.Image);
} }
else else
Gbl.Test.Image.Status = Img_FILE_NONE; Gbl.Test.Image.Status = Img_FILE_NONE;
@ -4839,6 +4894,14 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
/***** Get the answers from the database *****/ /***** Get the answers from the database *****/
Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (Gbl.Test.QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct,Feedback Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (Gbl.Test.QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct,Feedback
/*
row[ 0] AnsInd
row[ 1] Answer
row[ 2] Feedback
row[ 3] ImageName
row[ 4] ImageTitle
row[ 5] Correct
*/
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions; NumOpt < Gbl.Test.Answer.NumOptions;
NumOpt++) NumOpt++)
@ -4872,22 +4935,22 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
strncpy (Gbl.Test.Answer.Options[NumOpt].Text,row[1],Tst_MAX_BYTES_ANSWER_OR_FEEDBACK); strncpy (Gbl.Test.Answer.Options[NumOpt].Text,row[1],Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
Gbl.Test.Answer.Options[NumOpt].Text[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0'; Gbl.Test.Answer.Options[NumOpt].Text[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0';
// Feedback is initialized to empty string // Feedback (row[2]) is initialized to empty string
if (row[3]) if (row[2])
if (row[3][0]) if (row[2][0])
{ {
strncpy (Gbl.Test.Answer.Options[NumOpt].Feedback,row[3],Tst_MAX_BYTES_ANSWER_OR_FEEDBACK); strncpy (Gbl.Test.Answer.Options[NumOpt].Feedback,row[2],Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
Gbl.Test.Answer.Options[NumOpt].Feedback[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0'; Gbl.Test.Answer.Options[NumOpt].Feedback[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0';
} }
/* Copy image */ /* Copy image */
if (row[4][0]) if (row[3][0])
{ {
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameTitle (row[4],row[5],&Gbl.Test.Image); Img_GetImageNameAndTitle (row[3],row[4],&Gbl.Test.Answer.Options[NumOpt].Image);
} }
Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[2][0]) == 'Y'); Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[5][0]) == 'Y');
break; break;
default: default:
break; break;
@ -4926,7 +4989,7 @@ static void Tst_GetImageFromDB (unsigned NumOpt,struct Image *Image)
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/***** Get the image name (row[0]) *****/ /***** Get the image name (row[0]) *****/
Img_GetImageNameTitle (row[0],row[1],Image); Img_GetImageNameAndTitle (row[0],row[1],Image);
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
@ -5126,7 +5189,7 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
{ {
sprintf (ParamAction,"ImgAct%u",NumOpt); sprintf (ParamAction,"ImgAct%u",NumOpt);
sprintf (ParamFile ,"FilImg%u",NumOpt); sprintf (ParamFile ,"FilImg%u",NumOpt);
sprintf (ParamFile ,"TitImg%u",NumOpt); sprintf (ParamTitle ,"TitImg%u",NumOpt);
Img_GetImageFromForm (NumOpt,&Gbl.Test.Answer.Options[NumOpt].Image, Img_GetImageFromForm (NumOpt,&Gbl.Test.Answer.Options[NumOpt].Image,
Tst_GetImageFromDB, Tst_GetImageFromDB,
ParamAction,ParamFile,ParamTitle, ParamAction,ParamFile,ParamTitle,
@ -5870,8 +5933,9 @@ static void Tst_InsertAnswersIntoDB (void)
switch (Gbl.Test.AnswerType) switch (Gbl.Test.AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
sprintf (Query,"INSERT INTO tst_answers (QstCod,AnsInd,Answer,Feedback,Correct)" sprintf (Query,"INSERT INTO tst_answers"
" VALUES (%ld,0,'%ld','','Y')", " (QstCod,AnsInd,Answer,Feedback,ImageName,ImageTitle,Correct)"
" VALUES (%ld,0,'%ld','','','','Y')",
Gbl.Test.QstCod, Gbl.Test.QstCod,
Gbl.Test.Answer.Integer); Gbl.Test.Answer.Integer);
DB_QueryINSERT (Query,"can not create answer"); DB_QueryINSERT (Query,"can not create answer");
@ -5882,8 +5946,9 @@ static void Tst_InsertAnswersIntoDB (void)
i < 2; i < 2;
i++) i++)
{ {
sprintf (Query,"INSERT INTO tst_answers (QstCod,AnsInd,Answer,Feedback,Correct)" sprintf (Query,"INSERT INTO tst_answers"
" VALUES (%ld,%u,'%lg','','Y')", " (QstCod,AnsInd,Answer,Feedback,ImageName,ImageTitle,Correct)"
" VALUES (%ld,%u,'%lg','','','','Y')",
Gbl.Test.QstCod,i, Gbl.Test.QstCod,i,
Gbl.Test.Answer.FloatingPoint[i]); Gbl.Test.Answer.FloatingPoint[i]);
DB_QueryINSERT (Query,"can not create answer"); DB_QueryINSERT (Query,"can not create answer");
@ -5891,8 +5956,9 @@ static void Tst_InsertAnswersIntoDB (void)
setlocale (LC_NUMERIC,"es_ES.utf8"); // Return to spanish system (TODO: this should be internationalized!!!!!!!) setlocale (LC_NUMERIC,"es_ES.utf8"); // Return to spanish system (TODO: this should be internationalized!!!!!!!)
break; break;
case Tst_ANS_TRUE_FALSE: case Tst_ANS_TRUE_FALSE:
sprintf (Query,"INSERT INTO tst_answers (QstCod,AnsInd,Answer,Feedback,Correct)" sprintf (Query,"INSERT INTO tst_answers"
" VALUES (%ld,0,'%c','','Y')", " (QstCod,AnsInd,Answer,Feedback,ImageName,ImageTitle,Correct)"
" VALUES (%ld,0,'%c','','','','Y')",
Gbl.Test.QstCod, Gbl.Test.QstCod,
Gbl.Test.Answer.TF); Gbl.Test.Answer.TF);
DB_QueryINSERT (Query,"can not create answer"); DB_QueryINSERT (Query,"can not create answer");
@ -5905,10 +5971,9 @@ static void Tst_InsertAnswersIntoDB (void)
NumOpt++) NumOpt++)
if (Gbl.Test.Answer.Options[NumOpt].Text[0]) if (Gbl.Test.Answer.Options[NumOpt].Text[0])
{ {
sprintf (Query,"INSERT INTO tst_answers (QstCod,AnsInd," sprintf (Query,"INSERT INTO tst_answers"
"Answer,Feedback,ImageName,ImageTitle,Correct)" " (QstCod,AnsInd,Answer,Feedback,ImageName,ImageTitle,Correct)"
" VALUES ('%ld','%u'," " VALUES ('%ld','%u','%s','%s','%s','%s','%c')",
"'%s','%s','%s','%s','%c')",
Gbl.Test.QstCod,NumOpt, Gbl.Test.QstCod,NumOpt,
Gbl.Test.Answer.Options[NumOpt].Text, Gbl.Test.Answer.Options[NumOpt].Text,
Gbl.Test.Answer.Options[NumOpt].Feedback ? Gbl.Test.Answer.Options[NumOpt].Feedback : "", Gbl.Test.Answer.Options[NumOpt].Feedback ? Gbl.Test.Answer.Options[NumOpt].Feedback : "",

View File

@ -306,7 +306,14 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod)
double FloatNum[2]; double FloatNum[2];
Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct
/*
row[ 0] AnsInd
row[ 1] Answer
row[ 2] Feedback
row[ 3] ImageName
row[ 4] ImageTitle
row[ 5] Correct
*/
/***** Write the answers *****/ /***** Write the answers *****/
switch (Gbl.Test.AnswerType) switch (Gbl.Test.AnswerType)
{ {
@ -355,16 +362,18 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod)
fprintf (Gbl.Test.XML.FileXML,"<option"); fprintf (Gbl.Test.XML.FileXML,"<option");
if (Gbl.Test.AnswerType != Tst_ANS_TEXT) if (Gbl.Test.AnswerType != Tst_ANS_TEXT)
fprintf (Gbl.Test.XML.FileXML," correct=\"%s\"", fprintf (Gbl.Test.XML.FileXML," correct=\"%s\"",
Str_ConvertToUpperLetter (row[2][0]) == 'Y' ? "yes" : Str_ConvertToUpperLetter (row[5][0]) == 'Y' ? "yes" :
"no"); "no");
fprintf (Gbl.Test.XML.FileXML,">%s" fprintf (Gbl.Test.XML.FileXML,">%s"
"<text>%s</text>%s", "<text>%s</text>%s",
Txt_NEW_LINE, Txt_NEW_LINE,
row[1],Txt_NEW_LINE); row[1],Txt_NEW_LINE);
if (row[3])
if (row[3][0]) /* Write the feedback (row[2]) */
if (row[2])
if (row[2][0])
fprintf (Gbl.Test.XML.FileXML,"<feedback>%s</feedback>%s", fprintf (Gbl.Test.XML.FileXML,"<feedback>%s</feedback>%s",
row[3],Txt_NEW_LINE); row[2],Txt_NEW_LINE);
fprintf (Gbl.Test.XML.FileXML,"</option>%s", fprintf (Gbl.Test.XML.FileXML,"</option>%s",
Txt_NEW_LINE); Txt_NEW_LINE);
} }