Version 15.182

This commit is contained in:
Antonio Cañas Vargas 2016-04-06 01:10:04 +02:00
parent 5c87432630
commit dcd1dd8f53
7 changed files with 294 additions and 184 deletions

View File

@ -1087,7 +1087,8 @@ CREATE TABLE IF NOT EXISTS tst_answers (
AnsInd TINYINT NOT NULL,
Answer TEXT NOT NULL,
Feedback TEXT NOT NULL,
Image VARCHAR(43) NOT NULL,
ImageName VARCHAR(43) NOT NULL,
ImageTitle TEXT NOT NULL,
Correct ENUM('N','Y') NOT NULL,
INDEX(QstCod));
--
@ -1145,7 +1146,8 @@ CREATE TABLE IF NOT EXISTS tst_questions (
Shuffle ENUM('N','Y') NOT NULL,
Stem TEXT NOT NULL,
Feedback TEXT NOT NULL,
Image VARCHAR(43) NOT NULL,
ImageName VARCHAR(43) NOT NULL,
ImageTitle TEXT NOT NULL,
NumHits INT NOT NULL DEFAULT 0,
NumHitsNotBlank INT NOT NULL DEFAULT 0,
Score DOUBLE PRECISION NOT NULL DEFAULT 0,

View File

@ -131,13 +131,20 @@
/****************************** Public constants *****************************/
/*****************************************************************************/
#define Log_PLATFORM_VERSION "SWAD 15.181 (2016-04-05)"
#define Log_PLATFORM_VERSION "SWAD 15.182 (2016-04-06)"
#define CSS_FILE "swad15.178.2.css"
#define JS_FILE "swad15.178.2.js"
// 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
/*
Version 15.182: Apr 06, 2016 Get fields title/attribution of images from form. (198610 lines)
4 changes necessary in database:
ALTER TABLE tst_questions CHANGE COLUMN Image ImageName VARCHAR(43) NOT NULL;
ALTER TABLE tst_questions ADD COLUMN ImageTitle TEXT NOT NULL AFTER ImageName;
ALTER TABLE tst_answers CHANGE COLUMN Image ImageName VARCHAR(43) NOT NULL;
ALTER TABLE tst_answers ADD COLUMN ImageTitle TEXT NOT NULL AFTER ImageName;
Version 15.181: Apr 05, 2016 New fields in test questions with the title/attribution of images. (198515 lines)
Version 15.180.7: Apr 05, 2016 Changes in layout of editor of question. (198473 lines)
Version 15.180.6: Apr 05, 2016 Changes in layout of editor of question. (198490 lines)

View File

@ -2290,24 +2290,26 @@ mysql> DESCRIBE timetable_tut;
/***** Table tst_answers *****/
/*
mysql> DESCRIBE tst_answers;
+----------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------------+------+-----+---------+-------+
| QstCod | int(11) | NO | MUL | NULL | |
| AnsInd | tinyint(4) | NO | | NULL | |
| Answer | text | NO | | NULL | |
| Feedback | text | NO | | NULL | |
| Image | varchar(43) | NO | | NULL | |
| Correct | enum('N','Y') | NO | | NULL | |
+----------+---------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
+------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------+------+-----+---------+-------+
| QstCod | int(11) | NO | MUL | NULL | |
| AnsInd | tinyint(4) | NO | | NULL | |
| Answer | text | NO | | NULL | |
| Feedback | text | NO | | NULL | |
| ImageName | varchar(43) | NO | | NULL | |
| ImageTitle | text | NO | | NULL | |
| Correct | enum('N','Y') | NO | | NULL | |
+------------+---------------+------+-----+---------+-------+
7 rows in set (0.00 sec)
*/
DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_answers ("
"QstCod INT NOT NULL,"
"AnsInd TINYINT NOT NULL,"
"Answer TEXT NOT NULL,"
"Feedback TEXT NOT NULL,"
"Image VARCHAR(43) NOT NULL,"
"ImageName VARCHAR(43) NOT NULL,"
"ImageTitle TEXT NOT NULL,"
"Correct ENUM('N','Y') NOT NULL,"
"INDEX(QstCod))");
@ -2421,12 +2423,13 @@ mysql> DESCRIBE tst_questions;
| Shuffle | enum('N','Y') | NO | | NULL | |
| Stem | text | NO | | NULL | |
| Feedback | text | NO | | NULL | |
| Image | varchar(43) | NO | | NULL | |
| ImageName | varchar(43) | NO | | NULL | |
| ImageTitle | text | NO | | NULL | |
| NumHits | int(11) | NO | | 0 | |
| NumHitsNotBlank | int(11) | NO | | 0 | |
| Score | double | NO | | 0 | |
+-----------------+---------------------------------------------------------------------------+------+-----+---------+----------------+
11 rows in set (0.00 sec)
12 rows in set (0.00 sec)
*/
DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_questions ("
"QstCod INT NOT NULL AUTO_INCREMENT,"
@ -2436,7 +2439,8 @@ mysql> DESCRIBE tst_questions;
"Shuffle ENUM('N','Y') NOT NULL,"
"Stem TEXT NOT NULL,"
"Feedback TEXT NOT NULL,"
"Image VARCHAR(43) NOT NULL,"
"ImageName VARCHAR(43) NOT NULL,"
"ImageTitle TEXT NOT NULL,"
"NumHits INT NOT NULL DEFAULT 0,"
"NumHitsNotBlank INT NOT NULL DEFAULT 0,"
"Score DOUBLE PRECISION NOT NULL DEFAULT 0,"

View File

@ -67,13 +67,54 @@ static void Img_ProcessImage (const char *FileNameImgOriginal,
const char *FileNameImgProcessed,
unsigned Width,unsigned Height,unsigned Quality);
/*****************************************************************************/
/*************************** Reset image title *******************************/
/*****************************************************************************/
void Img_ResetImageTitle (struct Image *Image)
{
if (Image->Title)
free ((void *) Image->Title);
Image->Title = NULL;
}
/*****************************************************************************/
/************ Get image title from a string and copy to struct ***************/
/*****************************************************************************/
void Img_GetImageNameTitle (const char *Name,const char *Title,
struct Image *Image)
{
size_t Length;
Img_ResetImageTitle (Image);
if (Name[0])
{
strncpy (Image->Name,Name,Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Image->Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
if (Image->Name[0]) // There is an image
if (Title[0])
{
Length = strlen (Title);
if ((Image->Title = (char *) malloc (Length+1)) == NULL)
Lay_ShowErrorAndExit ("Error allocating memory for image title.");
strncpy (Image->Title,Title,Length);
Image->Title[Length] = '\0';
}
}
else // No image in this question
Image->Name[0] = '\0';
}
/*****************************************************************************/
/***************************** Get image from form ***************************/
/*****************************************************************************/
void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image,
void (*GetImageName) (unsigned NumOpt,char *ImageName),
const char *ParamAction,const char *ParamFile,
void (*GetImageNameFromDB) (unsigned NumOpt,struct Image *Image),
const char *ParamAction,const char *ParamFile,const char *ParamTitle,
unsigned Width,unsigned Height,unsigned Quality)
{
Image->Action = Img_GetImageActionFromForm (ParamAction);
@ -83,30 +124,34 @@ void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image,
case Img_ACTION_NO_IMAGE: // Do not use image (remove current image if exists)
/***** Reset image name *****/
Image->Name[0] = '\0';
Img_ResetImageTitle (Image);
break;
case Img_ACTION_KEEP_IMAGE: // Keep current image unchanged
/***** Get image name *****/
GetImageName (NumOpt,Image->Name);
GetImageNameFromDB (NumOpt,Image);
if (Image->Name[0])
Image->Status = Img_NAME_STORED_IN_DB;
break;
case Img_ACTION_NEW_IMAGE: // Upload new image
/***** Get new image (if present ==> process and create temporary file) *****/
Img_GetAndProcessImageFileFromForm (Image,ParamFile,Width,Height,Quality);
Img_GetAndProcessImageFileFromForm (Image,ParamFile,ParamTitle,
Width,Height,Quality);
if (Image->Status != Img_FILE_PROCESSED) // No new image received-processed successfully
{
/* Reset image name */
Image->Name[0] = '\0';
Image->Status = Img_FILE_NONE;
Image->Name[0] = '\0';
Img_ResetImageTitle (Image);
}
break;
case Img_ACTION_CHANGE_IMAGE: // Replace old image by new image
/***** Get new image (if present ==> process and create temporary file) *****/
Img_GetAndProcessImageFileFromForm (Image,ParamFile,Width,Height,Quality);
Img_GetAndProcessImageFileFromForm (Image,ParamFile,ParamTitle,
Width,Height,Quality);
if (Image->Status != Img_FILE_PROCESSED) // No new image received-processed successfully
{
/* Get image name */
GetImageName (NumOpt,Image->Name);
GetImageNameFromDB (NumOpt,Image);
Image->Status = (Image->Name[0] ? Img_NAME_STORED_IN_DB :
Img_FILE_NONE);
}
@ -137,7 +182,7 @@ Img_Action_t Img_GetImageActionFromForm (const char *ParamAction)
// Return true if image is created
void Img_GetAndProcessImageFileFromForm (struct Image *Image,
const char *ParamFile,
const char *ParamFile,const char *ParamTitle,
unsigned Width,unsigned Height,
unsigned Quality)
{
@ -150,6 +195,8 @@ void Img_GetAndProcessImageFileFromForm (struct Image *Image,
char FileNameImgOrig[PATH_MAX+1]; // Full name of original uploaded file
char FileNameImgTmp[PATH_MAX+1]; // Full name of temporary processed file
bool WrongType = false;
char Title[Cns_MAX_BYTES_TEXT+1];
size_t Length;
/***** Rest image file status *****/
Image->Status = Img_FILE_NONE;
@ -214,6 +261,17 @@ void Img_GetAndProcessImageFileFromForm (struct Image *Image,
/***** Remove temporary original file *****/
unlink (FileNameImgOrig);
/***** 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
Length = strlen (Title);
if (Length > 0)
{
if ((Image->Title = (char *) malloc (Length+1)) == NULL)
Lay_ShowErrorAndExit ("Error allocating memory for image title.");
strncpy (Image->Title,Title,Length);
Image->Title[Length] = '\0';
}
}
}

View File

@ -85,19 +85,24 @@ struct Image
Img_Action_t Action;
Img_FileStatus_t Status;
char Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1];
char *Title; // Title/attribution
};
/*****************************************************************************/
/***************************** Public prototypes *****************************/
/*****************************************************************************/
void Img_ResetImageTitle (struct Image *Image);
void Img_GetImageNameTitle (const char *Name,const char *Title,
struct Image *Image);
void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image,
void (*GetImageName) (unsigned NumOpt,char *ImageName),
const char *ParamAction,const char *ParamFile,
void (*GetImageNameFromDB) (unsigned NumOpt,struct Image *Image),
const char *ParamAction,const char *ParamFile,const char *ParamTitle,
unsigned Width,unsigned Height,unsigned Quality);
Img_Action_t Img_GetImageActionFromForm (const char *ParamAction);
void Img_GetAndProcessImageFileFromForm (struct Image *Image,
const char *ParamFile,
const char *ParamFile,const char *ParamTitle,
unsigned Width,unsigned Height,
unsigned Quality);

View File

@ -220,9 +220,10 @@ static int Tst_CountNumAnswerTypesInList (void);
static void Tst_PutFormEditOneQst (char *Stem,char *Feedback);
static void Tst_InitImagesOfQuestion (void);
static void Tst_FreeImagesOfQuestion (void);
static void Tst_GetQstDataFromDB (char *Stem,char *Feedback);
static void Tst_GetImageNameFromDB (unsigned NumOpt,char *ImageName);
static void Tst_GetImageFromDB (unsigned NumOpt,struct Image *Image);
static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr);
static void Tst_GetQstFromForm (char *Stem,char *Feedback);
@ -902,16 +903,17 @@ static void Tst_ShowTstResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank,
/***** Get row of the result of the query *****/
row = mysql_fetch_row (mysql_res);
/*
row[0] QstCod
row[1] UNIX_TIMESTAMP(EditTime)
row[2] AnsType
row[3] Shuffle
row[4] Stem
row[5] Image
row[6] Feedback
row[7] NumHits
row[8] NumHitsNotBlank
row[9] Score
row[ 0] QstCod
row[ 1] UNIX_TIMESTAMP(EditTime)
row[ 2] AnsType
row[ 3] Shuffle
row[ 4] Stem
row[ 5] Feedback
row[ 6] ImageName
row[ 7] ImageTitle
row[ 8] NumHits
row[ 9] NumHitsNotBlank
row[10] Score
*/
/***** Get the code of question (row[0]) *****/
@ -966,16 +968,17 @@ static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
{
extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES];
/*
row[0] QstCod
row[1] UNIX_TIMESTAMP(EditTime)
row[2] AnsType
row[3] Shuffle
row[4] Stem
row[5] Image
row[6] Feedback
row[7] NumHits
row[8] NumHitsNotBlank
row[9] Score
row[ 0] QstCod
row[ 1] UNIX_TIMESTAMP(EditTime)
row[ 2] AnsType
row[ 3] Shuffle
row[ 4] Stem
row[ 5] Feedback
row[ 6] ImageName
row[ 7] ImageTitle
row[ 8] NumHits
row[ 9] NumHitsNotBlank
row[10] Score
*/
/***** Write number of question *****/
@ -991,15 +994,15 @@ static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
"</td>",
Txt_TST_STR_ANSWER_TYPES[Gbl.Test.AnswerType]);
/***** Write stem (row[4]), answers depending on shuffle (row[3]) and feedback (row[6]) *****/
/***** Write stem (row[4]), image (row[6], row[7]),
answers depending on shuffle (row[3]) and feedback (row[5]) *****/
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">",
Gbl.RowEvenOdd);
Tst_WriteQstStem (row[4],"TEST_EXA");
if (row[5][0])
if (row[6][0])
{
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
strncpy (Gbl.Test.Image.Name,row[5],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Gbl.Test.Image.Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
Img_GetImageNameTitle (row[6],row[7],&Gbl.Test.Image);
Img_ShowImage (&Gbl.Test.Image,"TEST_IMG_SHOW_STEM");
}
if (Gbl.Action.Act == ActSeeTst)
@ -1012,6 +1015,10 @@ static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
}
fprintf (Gbl.F.Out,"</td>"
"</tr>");
/***** Free answers and images of this test question *****/
Tst_FreeTextChoiceAnswers ();
Tst_FreeImagesOfQuestion ();
}
/*****************************************************************************/
@ -2304,22 +2311,23 @@ static unsigned long Tst_GetQuestionsForEdit (MYSQL_RES **mysql_res)
/***** Select questions *****/
/* Start query */
/*
row[0] QstCod
row[1] UNIX_TIMESTAMP(EditTime)
row[2] AnsType
row[3] Shuffle
row[4] Stem
row[5] Image
row[6] Feedback
row[7] NumHits
row[8] NumHitsNotBlank
row[9] Score
row[ 0] QstCod
row[ 1] UNIX_TIMESTAMP(EditTime)
row[ 2] AnsType
row[ 3] Shuffle
row[ 4] Stem
row[ 5] Feedback
row[ 6] ImageName
row[ 7] ImageTitle
row[ 8] NumHits
row[ 9] NumHitsNotBlank
row[10] Score
*/
sprintf (Query,"SELECT tst_questions.QstCod,"
"UNIX_TIMESTAMP(tst_questions.EditTime) AS F,"
"tst_questions.AnsType,tst_questions.Shuffle,"
"tst_questions.Stem,tst_questions.Image,"
"tst_questions.Feedback,"
"tst_questions.Stem,tst_questions.Feedback,"
"tst_questions.ImageName,tst_questions.ImageTitle,"
"tst_questions.NumHits,tst_questions.NumHitsNotBlank,"
"tst_questions.Score"
" FROM tst_questions");
@ -2441,16 +2449,17 @@ static unsigned long Tst_GetQuestionsForExam (MYSQL_RES **mysql_res)
/***** Select questions without hidden tags *****/
/*
row[0] QstCod
row[1] UNIX_TIMESTAMP(EditTime)
row[2] AnsType
row[3] Shuffle
row[4] Stem
row[5] Image
row[6] Feedback
row[7] NumHits
row[8] NumHitsNotBlank
row[9] Score
row[ 0] QstCod
row[ 1] UNIX_TIMESTAMP(EditTime)
row[ 2] AnsType
row[ 3] Shuffle
row[ 4] Stem
row[ 5] Feedback
row[ 6] ImageName
row[ 7] ImageTitle
row[ 8] NumHits
row[ 9] NumHitsNotBlank
row[10] Score
*/
/* Start query */
// Reject questions with any tag hidden
@ -2459,8 +2468,8 @@ static unsigned long Tst_GetQuestionsForExam (MYSQL_RES **mysql_res)
sprintf (Query,"SELECT DISTINCTROW tst_questions.QstCod,"
"UNIX_TIMESTAMP(tst_questions.EditTime),"
"tst_questions.AnsType,tst_questions.Shuffle,"
"tst_questions.Stem,tst_questions.Image,"
"tst_questions.Feedback,"
"tst_questions.Stem,tst_questions.Feedback,"
"tst_questions.ImageName,tst_questions.ImageTitle,"
"tst_questions.NumHits,tst_questions.NumHitsNotBlank,"
"tst_questions.Score"
" FROM tst_questions,tst_question_tags,tst_tags"
@ -2564,19 +2573,20 @@ static bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res)
/***** Get data of a question from database *****/
/*
row[0] QstCod
row[1] UNIX_TIMESTAMP(EditTime)
row[2] AnsType
row[3] Shuffle
row[4] Stem
row[5] Image
row[6] Feedback
row[7] NumHits
row[8] NumHitsNotBlank
row[9] Score
row[ 0] QstCod
row[ 1] UNIX_TIMESTAMP(EditTime)
row[ 2] AnsType
row[ 3] Shuffle
row[ 4] Stem
row[ 5] Feedback
row[ 6] ImageName
row[ 7] ImageTitle
row[ 8] NumHits
row[ 9] NumHitsNotBlank
row[10] Score
*/
sprintf (Query,"SELECT QstCod,UNIX_TIMESTAMP(EditTime),"
"AnsType,Shuffle,Stem,Image,Feedback,"
"AnsType,Shuffle,Stem,Feedback,ImageName,ImageTitle,"
"NumHits,NumHitsNotBlank,Score"
" FROM tst_questions"
" WHERE QstCod='%ld'",
@ -2684,16 +2694,17 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
row = mysql_fetch_row (mysql_res);
/*
row[0] QstCod
row[1] UNIX_TIMESTAMP(EditTime)
row[2] AnsType
row[3] Shuffle
row[4] Stem
row[5] Image
row[6] Feedback
row[7] NumHits
row[8] NumHitsNotBlank
row[9] Score
row[ 0] QstCod
row[ 1] UNIX_TIMESTAMP(EditTime)
row[ 2] AnsType
row[ 3] Shuffle
row[ 4] Stem
row[ 5] Feedback
row[ 6] ImageName
row[ 7] ImageTitle
row[ 8] NumHits
row[ 9] NumHitsNotBlank
row[10] Score
*/
/* row[0] holds the code of the question */
if ((QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
@ -2784,36 +2795,40 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
}
fprintf (Gbl.F.Out,"</td>");
/* Write the stem (row[4]), the image (row[5],vthe feedback (row[6]) and the answers */
/* Write the stem (row[4]), the image (row[6], row[7]),
the feedback (row[5]) and the answers */
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">",
Gbl.RowEvenOdd);
Tst_WriteQstStem (row[4],"TEST_EDI");
if (row[5][0])
if (row[6][0])
{
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
strncpy (Gbl.Test.Image.Name,row[5],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Gbl.Test.Image.Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
Img_GetImageNameTitle (row[6],row[7],&Gbl.Test.Image);
Img_ShowImage (&Gbl.Test.Image,"TEST_IMG_EDIT_LIST_STEM");
}
Tst_WriteQstFeedback (row[6],"TEST_EDI_LIGHT");
Tst_WriteQstFeedback (row[5],"TEST_EDI_LIGHT");
Tst_WriteAnswersOfAQstEdit (QstCod);
fprintf (Gbl.F.Out,"</td>");
/* Free answers and images of this test question */
Tst_FreeTextChoiceAnswers ();
Tst_FreeImagesOfQuestion ();
/* Get number of hits
(number of times that the question has been answered,
including blank answers) (row[7]) */
if (sscanf (row[7],"%lu",&NumHitsThisQst) != 1)
including blank answers) (row[8]) */
if (sscanf (row[8],"%lu",&NumHitsThisQst) != 1)
Lay_ShowErrorAndExit ("Wrong number of hits to a question.");
/* Get number of hits not blank
(number of times that the question has been answered
with a not blank answer) (row[8]) */
if (sscanf (row[8],"%lu",&NumHitsNotBlankThisQst) != 1)
with a not blank answer) (row[9]) */
if (sscanf (row[9],"%lu",&NumHitsNotBlankThisQst) != 1)
Lay_ShowErrorAndExit ("Wrong number of hits not blank to a question.");
/* Get the acumulated score of the question (row[9]) */
/* Get the acumulated score of the question (row[10]) */
setlocale (LC_NUMERIC,"en_US.utf8"); // To get decimal point
if (sscanf (row[9],"%lf",&TotalScoreThisQst) != 1)
if (sscanf (row[10],"%lf",&TotalScoreThisQst) != 1)
Lay_ShowErrorAndExit ("Wrong score of a question.");
setlocale (LC_NUMERIC,"es_ES.utf8"); // Return to spanish system (TODO: this should be internationalized!!!!!!!)
@ -2890,7 +2905,7 @@ unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle)
unsigned long NumRows;
/***** Get answers of a question from database *****/
sprintf (Query,"SELECT AnsInd,Answer,Correct,Feedback,Image"
sprintf (Query,"SELECT AnsInd,Answer,Correct,Feedback,ImageName,ImageTitle"
" FROM tst_answers"
" WHERE QstCod='%ld' ORDER BY %s",
QstCod,
@ -2989,8 +3004,7 @@ static void Tst_WriteAnswersOfAQstEdit (long QstCod)
if (row[4][0])
{
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
strncpy (Gbl.Test.Answer.Options[NumOpt].Image.Name,row[4],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Gbl.Test.Answer.Options[NumOpt].Image.Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
Img_GetImageNameTitle (row[4],row[5],&Gbl.Test.Answer.Options[NumOpt].Image);
}
/* Put an icon that indicates whether the answer is correct or wrong */
@ -3285,8 +3299,7 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
if (row[4][0])
{
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
strncpy (Gbl.Test.Answer.Options[NumOpt].Image.Name,row[4],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Gbl.Test.Answer.Options[NumOpt].Image.Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
Img_GetImageNameTitle (row[4],row[5],&Gbl.Test.Answer.Options[NumOpt].Image);
}
/***** Write selectors and letter of this option *****/
@ -3319,8 +3332,9 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
/***** End of table *****/
fprintf (Gbl.F.Out,"</table>");
/***** Free answers *****/
/***** Free answers and images of this test question *****/
Tst_FreeTextChoiceAnswers ();
Tst_FreeImagesOfQuestion ();
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
@ -3354,7 +3368,7 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
row[1] Answer
row[2] Correct
row[3] Feedback
row[4] Image
row[4] ImageName
*/
for (NumOpt = 0;
NumOpt < Gbl.Test.Answer.NumOptions;
@ -3390,8 +3404,7 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
if (row[4][0])
{
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
strncpy (Gbl.Test.Answer.Options[NumOpt].Image.Name,row[4],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Gbl.Test.Answer.Options[NumOpt].Image.Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
Img_GetImageNameTitle (row[4],row[5],&Gbl.Test.Answer.Options[NumOpt].Image);
}
/***** Assign correctness (row[2]) of this answer (this option) *****/
@ -3565,8 +3578,9 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
/***** End of table *****/
fprintf (Gbl.F.Out,"</table>");
/***** Free answers *****/
/***** Free answers and images of this test question *****/
Tst_FreeTextChoiceAnswers ();
Tst_FreeImagesOfQuestion ();
}
/*****************************************************************************/
@ -4451,7 +4465,7 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
Stem);
Tst_PutFormToEditQstImage (&Gbl.Test.Image,"TEST_IMG_EDIT_ONE_STEM",
NULL,"STEM", // Title / attribution
"ImgAct","FileImg","TitImg",false);
"ImgAct","FilImg","TitImg",false);
/***** Feedback *****/
fprintf (Gbl.F.Out,"<label class=\"%s\">"
@ -4626,9 +4640,9 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
fprintf (Gbl.F.Out,"<tr>"
"<td class=\"LEFT_TOP COLOR%u\">",
Gbl.RowEvenOdd);
sprintf (ParamAction,"ImgAct%u" ,NumOpt);
sprintf (ParamFile ,"FileImg%u",NumOpt);
sprintf (ParamTitle ,"TitImg%u" ,NumOpt);
sprintf (ParamAction,"ImgAct%u",NumOpt);
sprintf (ParamFile ,"FilImg%u",NumOpt);
sprintf (ParamTitle ,"TitImg%u",NumOpt);
Tst_PutFormToEditQstImage (&Gbl.Test.Answer.Options[NumOpt].Image,
"TEST_IMG_EDIT_ONE_ANS",
NULL,"ANS_STR", // Title / attribution
@ -4728,6 +4742,7 @@ static void Tst_InitImagesOfQuestion (void)
Gbl.Test.Image.Action = Img_ACTION_NO_IMAGE;
Gbl.Test.Image.Status = Img_FILE_NONE;
Gbl.Test.Image.Name[0] = '\0';
Gbl.Test.Image.Title = NULL;
for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++)
@ -4735,9 +4750,25 @@ static void Tst_InitImagesOfQuestion (void)
Gbl.Test.Answer.Options[NumOpt].Image.Action = Img_ACTION_NO_IMAGE;
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_FILE_NONE;
Gbl.Test.Answer.Options[NumOpt].Image.Name[0] = '\0';
Gbl.Test.Answer.Options[NumOpt].Image.Title = NULL;
}
}
/*****************************************************************************/
/*********************** Free images of a question ***************************/
/*****************************************************************************/
static void Tst_FreeImagesOfQuestion (void)
{
unsigned NumOpt;
Img_ResetImageTitle (&Gbl.Test.Image);
for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++)
Img_ResetImageTitle (&Gbl.Test.Answer.Options[NumOpt].Image);
}
/*****************************************************************************/
/****************** Get data of a question from database *********************/
/*****************************************************************************/
@ -4753,7 +4784,7 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
/***** Get the type of answer and the stem from the database *****/
/* Get the question from database */
sprintf (Query,"SELECT AnsType,Shuffle,Stem,Image,Feedback"
sprintf (Query,"SELECT AnsType,Shuffle,Stem,Feedback,ImageName,ImageTitle"
" FROM tst_questions"
" WHERE QstCod='%ld' AND CrsCod='%ld'",
Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod);
@ -4771,25 +4802,24 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
strncpy (Stem,row[2],Cns_MAX_BYTES_TEXT);
Stem[Cns_MAX_BYTES_TEXT] = '\0';
/* Get the image of the question from the database (row[3]) */
if (row[3][0])
{
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
strncpy (Gbl.Test.Image.Name,row[3],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Gbl.Test.Image.Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
}
else
Gbl.Test.Image.Status = Img_FILE_NONE;
/* Get the feedback of the question from the database (row[4]) */
/* Get the feedback of the question from the database (row[3]) */
Feedback[0] = '\0';
if (row[4])
if (row[4][0])
if (row[3])
if (row[3][0])
{
strncpy (Feedback,row[4],Cns_MAX_BYTES_TEXT);
Feedback[Cns_MAX_BYTES_TEXT] = '\0';
}
/* Get the image name of the question from the database (row[4]) */
if (row[4][0])
{
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
Img_GetImageNameTitle (row[4],row[5],&Gbl.Test.Image);
}
else
Gbl.Test.Image.Status = Img_FILE_NONE;
/* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res);
@ -4854,8 +4884,7 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
if (row[4][0])
{
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
strncpy (Gbl.Test.Answer.Options[NumOpt].Image.Name,row[4],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Gbl.Test.Answer.Options[NumOpt].Image.Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
Img_GetImageNameTitle (row[4],row[5],&Gbl.Test.Image);
}
Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[2][0]) == 'Y');
@ -4874,7 +4903,7 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
// NumOpt >= Tst_MAX_OPTIONS_PER_QUESTION ==> image associated to stem
// 0 <= NumOpt < Tst_MAX_OPTIONS_PER_QUESTION ==> image associated to answer
static void Tst_GetImageNameFromDB (unsigned NumOpt,char *ImageName)
static void Tst_GetImageFromDB (unsigned NumOpt,struct Image *Image)
{
char Query[256];
MYSQL_RES *mysql_res;
@ -4883,12 +4912,12 @@ static void Tst_GetImageNameFromDB (unsigned NumOpt,char *ImageName)
/***** Build query depending on NumOpt *****/
if (NumOpt < Tst_MAX_OPTIONS_PER_QUESTION)
// Get image associated to answer
sprintf (Query,"SELECT Image FROM tst_answers"
sprintf (Query,"SELECT ImageName,ImageTitle FROM tst_answers"
" WHERE QstCod='%ld' AND AnsInd='%u'",
Gbl.Test.QstCod,NumOpt);
else
// Get image associated to stem
sprintf (Query,"SELECT Image FROM tst_questions"
sprintf (Query,"SELECT ImageName,ImageTitle FROM tst_questions"
" WHERE QstCod='%ld' AND CrsCod='%ld'",
Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod);
@ -4896,14 +4925,8 @@ static void Tst_GetImageNameFromDB (unsigned NumOpt,char *ImageName)
DB_QuerySELECT (Query,&mysql_res,"can not get image name");
row = mysql_fetch_row (mysql_res);
/***** Get the image of the question from the database (row[0]) *****/
if (row[0][0]) // Image name stored in database
{
strncpy (ImageName,row[0],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
ImageName[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
}
else // No image in this question
ImageName[0] = '\0';
/***** Get the image name (row[0]) *****/
Img_GetImageNameTitle (row[0],row[1],Image);
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
@ -5003,6 +5026,7 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
unsigned NumCorrectAns;
char ParamAction[32];
char ParamFile[32];
char ParamTitle[32];
/***** Get question code *****/
Tst_GetQstCod ();
@ -5038,17 +5062,17 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
/***** Get question stem *****/
Par_GetParToHTML ("Stem",Stem,Cns_MAX_BYTES_TEXT);
/***** Get question feedback *****/
Par_GetParToHTML ("Feedback",Feedback,Cns_MAX_BYTES_TEXT);
/***** Get image associated to the stem *****/
Img_GetImageFromForm (Tst_MAX_OPTIONS_PER_QUESTION,&Gbl.Test.Image,
Tst_GetImageNameFromDB,
"ImgAct","FileImg",
Tst_GetImageFromDB,
"ImgAct","FilImg","TitImg",
Tst_PHOTO_SAVED_MAX_WIDTH,
Tst_PHOTO_SAVED_MAX_HEIGHT,
Tst_PHOTO_SAVED_QUALITY);
/***** Get question feedback *****/
Par_GetParToHTML ("Feedback",Feedback,Cns_MAX_BYTES_TEXT);
/***** Get answers *****/
Gbl.Test.Shuffle = false;
switch (Gbl.Test.AnswerType)
@ -5101,10 +5125,11 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE)
{
sprintf (ParamAction,"ImgAct%u",NumOpt);
sprintf (ParamFile,"FileImg%u",NumOpt);
sprintf (ParamFile ,"FilImg%u",NumOpt);
sprintf (ParamFile ,"TitImg%u",NumOpt);
Img_GetImageFromForm (NumOpt,&Gbl.Test.Answer.Options[NumOpt].Image,
Tst_GetImageNameFromDB,
ParamAction,ParamFile,
Tst_GetImageFromDB,
ParamAction,ParamFile,ParamTitle,
Tst_PHOTO_SAVED_MAX_WIDTH,
Tst_PHOTO_SAVED_MAX_HEIGHT,
Tst_PHOTO_SAVED_QUALITY);
@ -5744,15 +5769,20 @@ static void Tst_InsertOrUpdateQstIntoDB (void)
{
/***** Insert question in the table of questions *****/
sprintf (Query,"INSERT INTO tst_questions"
" (CrsCod,EditTime,AnsType,Shuffle,Stem,Image,Feedback,NumHits,Score)"
" VALUES ('%ld',NOW(),'%s','%c','%s','%s','%s','0','0')",
" (CrsCod,EditTime,AnsType,Shuffle,"
"Stem,Feedback,ImageName,ImageTitle,"
"NumHits,Score)"
" VALUES ('%ld',NOW(),'%s','%c',"
"'%s','%s','%s','%s',"
"'0','0')",
Gbl.CurrentCrs.Crs.CrsCod,
Tst_StrAnswerTypesDB[Gbl.Test.AnswerType],
Gbl.Test.Shuffle ? 'Y' :
'N',
Gbl.Test.Stem.Text,
Gbl.Test.Feedback.Text ? Gbl.Test.Feedback.Text : "",
Gbl.Test.Image.Name,
Gbl.Test.Feedback.Text ? Gbl.Test.Feedback.Text : "");
Gbl.Test.Image.Title ? Gbl.Test.Image.Title : "");
Gbl.Test.QstCod = DB_QueryINSERTandReturnCode (Query,"can not create question");
/* Update image status */
@ -5765,14 +5795,15 @@ static void Tst_InsertOrUpdateQstIntoDB (void)
/* Update question in database */
sprintf (Query,"UPDATE tst_questions"
" SET EditTime=NOW(),AnsType='%s',Shuffle='%c',"
"Stem='%s',Image='%s',Feedback='%s'"
"Stem='%s',Feedback='%s',ImageName='%s',ImageTitle='%s'"
" WHERE QstCod='%ld' AND CrsCod='%ld'",
Tst_StrAnswerTypesDB[Gbl.Test.AnswerType],
Gbl.Test.Shuffle ? 'Y' :
'N',
Gbl.Test.Stem.Text,
Gbl.Test.Image.Name,
Gbl.Test.Feedback.Text ? Gbl.Test.Feedback.Text : "",
Gbl.Test.Image.Name,
Gbl.Test.Image.Title ? Gbl.Test.Image.Title : "",
Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod);
DB_QueryUPDATE (Query,"can not update question");
@ -5874,13 +5905,15 @@ static void Tst_InsertAnswersIntoDB (void)
NumOpt++)
if (Gbl.Test.Answer.Options[NumOpt].Text[0])
{
sprintf (Query,"INSERT INTO tst_answers"
" (QstCod,AnsInd,Answer,Feedback,Image,Correct)"
" VALUES (%ld,%u,'%s','%s','%s','%c')",
sprintf (Query,"INSERT INTO tst_answers (QstCod,AnsInd,"
"Answer,Feedback,ImageName,ImageTitle,Correct)"
" VALUES ('%ld','%u',"
"'%s','%s','%s','%s','%c')",
Gbl.Test.QstCod,NumOpt,
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].Image.Name,
Gbl.Test.Answer.Options[NumOpt].Image.Title ? Gbl.Test.Answer.Options[NumOpt].Image.Title : "",
Gbl.Test.Answer.Options[NumOpt].Correct ? 'Y' :
'N');
DB_QueryINSERT (Query,"can not create answer");
@ -5958,11 +5991,11 @@ static void Tst_RemoveImgFilesFromStemOfQsts (long CrsCod,
/***** Get names of images associated to stems of test questions from database *****/
if (QstCod > 0) // Only one question
sprintf (Query,"SELECT Image FROM tst_questions"
sprintf (Query,"SELECT ImageName FROM tst_questions"
" WHERE QstCod='%ld' AND CrsCod='%ld'",
QstCod,CrsCod);
else // All questions in the course
sprintf (Query,"SELECT Image FROM tst_questions"
sprintf (Query,"SELECT ImageName FROM tst_questions"
" WHERE CrsCod='%ld'",
CrsCod);
NumImages = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test images");
@ -6003,7 +6036,7 @@ static void Tst_RemoveImgFilesFromAnsOfQsts (long CrsCod,
if (QstCod > 0) // Only one question
{
if (AnsInd < Tst_MAX_OPTIONS_PER_QUESTION) // Only one answer
sprintf (Query,"SELECT tst_answers.Image"
sprintf (Query,"SELECT tst_answers.ImageName"
" FROM tst_questions,tst_answers"
" WHERE tst_questions.CrsCod='%ld'" // Extra check
" AND tst_questions.QstCod='%ld'" // Extra check
@ -6012,7 +6045,7 @@ static void Tst_RemoveImgFilesFromAnsOfQsts (long CrsCod,
" AND tst_answers.AnsInd='%u'",
CrsCod,QstCod,QstCod,AnsInd);
else // All answers of a question
sprintf (Query,"SELECT tst_answers.Image"
sprintf (Query,"SELECT tst_answers.ImageName"
" FROM tst_questions,tst_answers"
" WHERE tst_questions.CrsCod='%ld'" // Extra check
" AND tst_questions.QstCod='%ld'" // Extra check
@ -6021,7 +6054,7 @@ static void Tst_RemoveImgFilesFromAnsOfQsts (long CrsCod,
CrsCod,QstCod,QstCod);
}
else // All answers of all questions in the course
sprintf (Query,"SELECT tst_answers.Image"
sprintf (Query,"SELECT tst_answers.ImageName"
" FROM tst_questions,tst_answers"
" WHERE tst_questions.CrsCod='%ld'"
" AND tst_questions.QstCod=tst_answers.QstCod",
@ -7365,16 +7398,17 @@ static void Tst_ShowExamTstResult (time_t TstTimeUTC)
/***** Get row of the result of the query *****/
row = mysql_fetch_row (mysql_res);
/*
row[0] QstCod
row[1] UNIX_TIMESTAMP(EditTime)
row[2] AnsType
row[3] Shuffle
row[4] Stem
row[5] Image
row[6] Feedback
row[7] NumHits
row[8] NumHitsNotBlank
row[9] Score
row[ 0] QstCod
row[ 1] UNIX_TIMESTAMP(EditTime)
row[ 2] AnsType
row[ 3] Shuffle
row[ 4] Stem
row[ 5] Feedback
row[ 6] ImageName
row[ 7] ImageTitle
row[ 8] NumHits
row[ 9] NumHitsNotBlank
row[10] Score
*/
/***** If this question has been edited later than test exam time ==> don't show question ****/
EditTimeUTC = Dat_GetUNIXTimeFromStr (row[1]);

View File

@ -198,7 +198,7 @@ void TsI_CreateXML (unsigned long NumRows,MYSQL_RES *mysql_res)
row[2] AnsType
row[3] Shuffle
row[4] Stem
row[5] Image
row[5] ImageName
row[6] Feedback
row[7] NumHits
row[8] NumHitsNotBlank