mirror of https://github.com/acanas/swad-core.git
Version 15.178
This commit is contained in:
parent
2b59faa4ef
commit
0d9402c11f
|
@ -1087,6 +1087,7 @@ CREATE TABLE IF NOT EXISTS tst_answers (
|
|||
AnsInd TINYINT NOT NULL,
|
||||
Answer TEXT NOT NULL,
|
||||
Feedback TEXT NOT NULL,
|
||||
Image VARCHAR(43) NOT NULL,
|
||||
Correct ENUM('N','Y') NOT NULL,
|
||||
INDEX(QstCod));
|
||||
--
|
||||
|
@ -1143,8 +1144,8 @@ CREATE TABLE IF NOT EXISTS tst_questions (
|
|||
AnsType ENUM ('int','float','true_false','unique_choice','multiple_choice','text') NOT NULL,
|
||||
Shuffle ENUM('N','Y') NOT NULL,
|
||||
Stem TEXT NOT NULL,
|
||||
Image CHAR(43) NOT NULL,
|
||||
Feedback TEXT NOT NULL,
|
||||
Image VARCHAR(43) NOT NULL,
|
||||
NumHits INT NOT NULL DEFAULT 0,
|
||||
NumHitsNotBlank INT NOT NULL DEFAULT 0,
|
||||
Score DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
|
|
|
@ -108,7 +108,6 @@
|
|||
// TODO: When page is refreshed in course works, prevent users to be duplicated
|
||||
// TODO: Reply to all
|
||||
// TODO: Hour in exam announcement should start at six a.m.
|
||||
|
||||
// TODO: Forum SWAD should be always named "SWAD"?
|
||||
// TODO: Enable chat for guests?
|
||||
// TODO: Go to forum post (or at least to forum thread) from social timeline and notifications?
|
||||
|
@ -118,34 +117,38 @@
|
|||
// TODO: FIX BUG: In results of search of students, no mark of confirmation is shown even if the student really has confirmed his/her registration in the course
|
||||
// TODO: Insert "http://" to WWW when WWW does not start with "*://"
|
||||
// TODO: Change links from external degrees to internal degrees in STATS > Degrees
|
||||
|
||||
// TODO: Icon to the left in list of forums is not correct when scope is system
|
||||
// TODO: Move info about number of files to bottom of file browsers
|
||||
|
||||
// TODO: To avoid wrong email addresses, when a user fills his/her email address, check if the domain is in the white list of allowed domains. If not, ask for confirmation.
|
||||
// TODO: Filtering email addresses --> an email address can not finish in "."
|
||||
|
||||
// TODO: Upload an image in social posts, in test questions, in forum posts, in private messages, etc.
|
||||
|
||||
// TODO: Important!!!! E-mail should not be visible for not logged users
|
||||
// TODO: Do not show e-mails of administrators and teachers in lists openly
|
||||
// TODO: Fix bug in marks reported by Francisco Ocaña
|
||||
|
||||
// TODO: In Statistics > Degrees, show only degrees with students
|
||||
// TODO: Change layout of confirm / reject incription. Use green and red buttons
|
||||
|
||||
// TODO: Ask for confirmation when removing a test question?
|
||||
// TODO: Ask for confirmation when removing a test question
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************** Public constants *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
#define Log_PLATFORM_VERSION "SWAD 15.177 (2016-04-04)"
|
||||
#define Log_PLATFORM_VERSION "SWAD 15.178 (2016-04-04)"
|
||||
#define CSS_FILE "swad15.175.10.css"
|
||||
#define JS_FILE "swad15.131.3.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.178: Apr 04, 2016 Code refactoring related to images in test questions. (198244 lines)
|
||||
5 changes necessary in database:
|
||||
ALTER TABLE tst_questions CHANGE COLUMN Image ImageOld CHAR(43) NOT NULL;
|
||||
ALTER TABLE tst_questions ADD COLUMN Image VARCHAR(43) NOT NULL AFTER Feedback;
|
||||
UPDATE tst_questions SET Image=ImageOld;
|
||||
ALTER TABLE tst_questions DROP COLUMN ImageOld;
|
||||
ALTER TABLE tst_answers ADD COLUMN Image VARCHAR(43) NOT NULL AFTER Feedback;
|
||||
|
||||
Version 15.177: Apr 04, 2016 Code refactoring related to images. (198083 lines)
|
||||
Version 15.176: Apr 04, 2016 Code refactoring related to images. (198019 lines)
|
||||
Version 15.175.11:Apr 04, 2016 Code refactoring related to image associated to a test question.
|
||||
|
|
|
@ -2297,15 +2297,17 @@ mysql> DESCRIBE tst_answers;
|
|||
| AnsInd | tinyint(4) | NO | | NULL | |
|
||||
| Answer | text | NO | | NULL | |
|
||||
| Feedback | text | NO | | NULL | |
|
||||
| Image | varchar(43) | NO | | NULL | |
|
||||
| Correct | enum('N','Y') | NO | | NULL | |
|
||||
+----------+---------------+------+-----+---------+-------+
|
||||
5 rows in set (0.00 sec)
|
||||
6 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,"
|
||||
"Correct ENUM('N','Y') NOT NULL,"
|
||||
"INDEX(QstCod))");
|
||||
|
||||
|
@ -2418,13 +2420,13 @@ mysql> DESCRIBE tst_questions;
|
|||
| AnsType | enum('int','float','true_false','unique_choice','multiple_choice','text') | NO | | NULL | |
|
||||
| Shuffle | enum('N','Y') | NO | | NULL | |
|
||||
| Stem | text | NO | | NULL | |
|
||||
| Image | char(43) | NO | | NULL | |
|
||||
| Feedback | text | NO | | NULL | |
|
||||
| Image | varchar(43) | NO | | NULL | |
|
||||
| NumHits | int(11) | NO | | 0 | |
|
||||
| NumHitsNotBlank | int(11) | NO | | 0 | |
|
||||
| Score | double | NO | | 0 | |
|
||||
+-----------------+---------------------------------------------------------------------------+------+-----+---------+----------------+
|
||||
11 rows in set (0.01 sec)
|
||||
11 rows in set (0.00 sec)
|
||||
*/
|
||||
DB_CreateTable ("CREATE TABLE IF NOT EXISTS tst_questions ("
|
||||
"QstCod INT NOT NULL AUTO_INCREMENT,"
|
||||
|
@ -2433,8 +2435,8 @@ mysql> DESCRIBE tst_questions;
|
|||
"AnsType ENUM ('int','float','true_false','unique_choice','multiple_choice','text') NOT NULL,"
|
||||
"Shuffle ENUM('N','Y') NOT NULL,"
|
||||
"Stem TEXT NOT NULL,"
|
||||
"Image CHAR(43) NOT NULL,"
|
||||
"Feedback TEXT NOT NULL,"
|
||||
"Image VARCHAR(43) NOT NULL,"
|
||||
"NumHits INT NOT NULL DEFAULT 0,"
|
||||
"NumHitsNotBlank INT NOT NULL DEFAULT 0,"
|
||||
"Score DOUBLE PRECISION NOT NULL DEFAULT 0,"
|
||||
|
|
|
@ -321,8 +321,9 @@ void Img_ShowImage (struct Image *Image,const char *ClassImg)
|
|||
FileNameImgPriv);
|
||||
|
||||
/***** Show image *****/
|
||||
fprintf (Gbl.F.Out,"<img src=\"%s\" alt=\"\" class=\"%s\"/>"
|
||||
"<br />",
|
||||
fprintf (Gbl.F.Out,"<div>"
|
||||
"<img src=\"%s\" alt=\"\" class=\"%s\"/>"
|
||||
"</div>",
|
||||
URL,ClassImg);
|
||||
}
|
||||
|
||||
|
|
342
swad_test.c
342
swad_test.c
|
@ -216,11 +216,15 @@ static int Tst_CountNumTagsInList (void);
|
|||
static int Tst_CountNumAnswerTypesInList (void);
|
||||
static void Tst_PutFormEditOneQst (char *Stem,char *Feedback);
|
||||
|
||||
static void Tst_InitImagesOfQuestion (void);
|
||||
|
||||
static void Tst_GetQstDataFromDB (char *Stem,char *Feedback);
|
||||
static void Tst_GetImageNameFromDB (unsigned NumOpt,char *ImageName);
|
||||
|
||||
static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr);
|
||||
static void Tst_GetQstFromForm (char *Stem,char *Feedback);
|
||||
static void Tst_MoveImagesToDefinitiveDirectories (void);
|
||||
|
||||
static long Tst_GetTagCodFromTagTxt (const char *TagTxt);
|
||||
static long Tst_CreateNewTag (long CrsCod,const char *TagTxt);
|
||||
static void Tst_EnableOrDisableTag (long TagCod,bool TagHidden);
|
||||
|
@ -233,6 +237,10 @@ static void Tst_InsertAnswersIntoDB (void);
|
|||
static void Tst_RemAnsFromQst (void);
|
||||
static void Tst_RemTagsFromQst (void);
|
||||
static void Tst_RemoveUnusedTagsFromCurrentCrs (void);
|
||||
|
||||
static void Tst_RemoveImgFilesFromStemOfQsts (long CrsCod,long QstCod);
|
||||
static void Tst_RemoveImgFilesFromAnsOfQsts (long CrsCod,long QstCod,unsigned AnsInd);
|
||||
|
||||
static void Tst_FreeTextChoiceAnswer (unsigned NumOpt);
|
||||
|
||||
static unsigned Tst_GetNumTstQuestions (Sco_Scope_t Scope,Tst_AnswerType_t AnsType,struct Tst_Stats *Stats);
|
||||
|
@ -2728,7 +2736,7 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
|
|||
}
|
||||
fprintf (Gbl.F.Out,"</td>");
|
||||
|
||||
/* Write the stem (row[4]), the feedback (row[6]) and the answers */
|
||||
/* Write the stem (row[4]), the image (row[5],vthe feedback (row[6]) and the answers */
|
||||
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">",
|
||||
Gbl.RowEvenOdd);
|
||||
Tst_WriteQstStem (row[4],"TEST_EDI");
|
||||
|
@ -2834,7 +2842,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"
|
||||
sprintf (Query,"SELECT AnsInd,Answer,Correct,Feedback,Image"
|
||||
" FROM tst_answers"
|
||||
" WHERE QstCod='%ld' ORDER BY %s",
|
||||
QstCod,
|
||||
|
@ -2929,9 +2937,18 @@ static void Tst_WriteAnswersOfAQstEdit (long QstCod)
|
|||
Feedback,LengthFeedback,false);
|
||||
}
|
||||
|
||||
/* Copy image */
|
||||
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';
|
||||
}
|
||||
|
||||
/* Put an icon that indicates whether the answer is correct or wrong */
|
||||
fprintf (Gbl.F.Out,"<tr>"
|
||||
"<td class=\"BT%u\">",Gbl.RowEvenOdd);
|
||||
"<td class=\"BT%u\">",
|
||||
Gbl.RowEvenOdd);
|
||||
if (Str_ConvertToUpperLetter (row[2][0]) == 'Y')
|
||||
fprintf (Gbl.F.Out,"<img src=\"%s/ok_on16x16.gif\""
|
||||
" alt=\"%s\" title=\"%s\""
|
||||
|
@ -2947,17 +2964,21 @@ static void Tst_WriteAnswersOfAQstEdit (long QstCod)
|
|||
"</td>",
|
||||
'a' + (char) NumOpt);
|
||||
|
||||
/* Write the text of the answer */
|
||||
fprintf (Gbl.F.Out,"<td class=\"TEST_EDI LEFT_TOP\">"
|
||||
"%s"
|
||||
"</td>",
|
||||
/* Write the text of the answer and the image (row[4]) */
|
||||
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP\">"
|
||||
"<div class=\"TEST_EDI\">"
|
||||
"%s",
|
||||
Answer);
|
||||
if (Gbl.Test.Answer.Options[NumOpt].Image.Name[0])
|
||||
Img_ShowImage (&Gbl.Test.Answer.Options[NumOpt].Image,"TEST_IMG_EDIT_LIST");
|
||||
fprintf (Gbl.F.Out,"</div>");
|
||||
|
||||
/* Write the text of the feedback */
|
||||
fprintf (Gbl.F.Out,"<td class=\"TEST_EDI_LIGHT LEFT_TOP\">");
|
||||
fprintf (Gbl.F.Out,"<div class=\"TEST_EDI_LIGHT\">");
|
||||
if (LengthFeedback)
|
||||
fprintf (Gbl.F.Out,"%s",Feedback);
|
||||
fprintf (Gbl.F.Out,"</td>"
|
||||
fprintf (Gbl.F.Out,"</div>"
|
||||
"</td>"
|
||||
"</tr>");
|
||||
|
||||
/* Free memory allocated for the answer and the feedback */
|
||||
|
@ -3212,6 +3233,14 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
|
|||
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
|
||||
Gbl.Test.Answer.Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
|
||||
|
||||
/***** Copy image *****/
|
||||
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';
|
||||
}
|
||||
|
||||
/***** Write selectors and letter of this option *****/
|
||||
fprintf (Gbl.F.Out,"<tr>"
|
||||
"<td class=\"LEFT_TOP\">");
|
||||
|
@ -3231,10 +3260,12 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
|
|||
|
||||
/***** Write the option text *****/
|
||||
fprintf (Gbl.F.Out,"<td class=\"TEST_EXA LEFT_TOP\">"
|
||||
"%s"
|
||||
"</td>"
|
||||
"</tr>",
|
||||
"%s",
|
||||
Gbl.Test.Answer.Options[NumOpt].Text);
|
||||
if (Gbl.Test.Answer.Options[NumOpt].Image.Name[0])
|
||||
Img_ShowImage (&Gbl.Test.Answer.Options[NumOpt].Image,"TEST_IMG_SHOW");
|
||||
fprintf (Gbl.F.Out,"</td>"
|
||||
"</tr>");
|
||||
}
|
||||
|
||||
/***** End of table *****/
|
||||
|
@ -3275,6 +3306,7 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
|
|||
row[1] Answer
|
||||
row[2] Correct
|
||||
row[3] Feedback
|
||||
row[4] Image
|
||||
*/
|
||||
for (NumOpt = 0;
|
||||
NumOpt < Gbl.Test.Answer.NumOptions;
|
||||
|
@ -3306,6 +3338,14 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
|
|||
Gbl.Test.Answer.Options[NumOpt].Feedback,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
|
||||
}
|
||||
|
||||
/***** Copy image *****/
|
||||
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';
|
||||
}
|
||||
|
||||
/***** Assign correctness (row[2]) of this answer (this option) *****/
|
||||
Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[2][0]) == 'Y');
|
||||
}
|
||||
|
@ -3394,9 +3434,11 @@ static void Tst_WriteChoiceAnsAssessExam (unsigned NumQst,MYSQL_RES *mysql_res,
|
|||
/* Answer text and feedback */
|
||||
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP\">"
|
||||
"<div class=\"TEST_EXA\">"
|
||||
"%s"
|
||||
"</div>",
|
||||
"%s",
|
||||
Gbl.Test.Answer.Options[Indexes[NumOpt]].Text);
|
||||
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Image.Name[0])
|
||||
Img_ShowImage (&Gbl.Test.Answer.Options[Indexes[NumOpt]].Image,"TEST_IMG_SHOW");
|
||||
fprintf (Gbl.F.Out,"</div>");
|
||||
if (Gbl.Test.Config.FeedbackType == Tst_FEEDBACK_FULL_FEEDBACK)
|
||||
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Feedback)
|
||||
if (Gbl.Test.Answer.Options[Indexes[NumOpt]].Feedback[0])
|
||||
|
@ -4601,9 +4643,6 @@ void Tst_InitQst (void)
|
|||
Gbl.Test.Stem.Length = 0;
|
||||
Gbl.Test.Feedback.Text = NULL;
|
||||
Gbl.Test.Feedback.Length = 0;
|
||||
Gbl.Test.Image.Action = Img_ACTION_NO_IMAGE;
|
||||
Gbl.Test.Image.Status = Img_FILE_NONE;
|
||||
Gbl.Test.Image.Name[0] = '\0';
|
||||
Gbl.Test.Shuffle = false;
|
||||
Gbl.Test.AnswerType = Tst_ANS_UNIQUE_CHOICE;
|
||||
Gbl.Test.Answer.NumOptions = 0;
|
||||
|
@ -4615,13 +4654,33 @@ void Tst_InitQst (void)
|
|||
Gbl.Test.Answer.Options[NumOpt].Correct = false;
|
||||
Gbl.Test.Answer.Options[NumOpt].Text = NULL;
|
||||
Gbl.Test.Answer.Options[NumOpt].Feedback = NULL;
|
||||
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.Integer = 0;
|
||||
Gbl.Test.Answer.FloatingPoint[0] =
|
||||
Gbl.Test.Answer.FloatingPoint[1] = 0.0;
|
||||
|
||||
Tst_InitImagesOfQuestion ();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/***************** Initialize images of a question to zero *******************/
|
||||
/*****************************************************************************/
|
||||
|
||||
static void Tst_InitImagesOfQuestion (void)
|
||||
{
|
||||
unsigned NumOpt;
|
||||
|
||||
Gbl.Test.Image.Action = Img_ACTION_NO_IMAGE;
|
||||
Gbl.Test.Image.Status = Img_FILE_NONE;
|
||||
Gbl.Test.Image.Name[0] = '\0';
|
||||
for (NumOpt = 0;
|
||||
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
|
||||
NumOpt++)
|
||||
{
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -4736,6 +4795,14 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
|
|||
Gbl.Test.Answer.Options[NumOpt].Feedback[Tst_MAX_BYTES_ANSWER_OR_FEEDBACK] = '\0';
|
||||
}
|
||||
|
||||
/* Copy image */
|
||||
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';
|
||||
}
|
||||
|
||||
Gbl.Test.Answer.Options[NumOpt].Correct = (Str_ConvertToUpperLetter (row[2][0]) == 'Y');
|
||||
break;
|
||||
default:
|
||||
|
@ -4840,17 +4907,8 @@ void Tst_ReceiveQst (void)
|
|||
/***** Make sure that tags, text and answer are not empty *****/
|
||||
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions ())
|
||||
{
|
||||
if (Gbl.Test.Image.Action != Img_ACTION_KEEP_IMAGE) // Don't keep the current image
|
||||
/* Remove possible file with the old image
|
||||
(the new image file is already processed
|
||||
and moved to the definitive directory) */
|
||||
Tst_RemoveImageFilesFromQstsInCrs (Gbl.CurrentCrs.Crs.CrsCod,Gbl.Test.QstCod);
|
||||
|
||||
if ((Gbl.Test.Image.Action == Img_ACTION_NEW_IMAGE || // Upload new image
|
||||
Gbl.Test.Image.Action == Img_ACTION_CHANGE_IMAGE) && // Replace existing image by new image
|
||||
Gbl.Test.Image.Status == Img_FILE_PROCESSED) // The new image received has been processed
|
||||
/* Move processed image to definitive directory */
|
||||
Img_MoveImageToDefinitiveDirectory (&Gbl.Test.Image);
|
||||
/***** Move images to definitive directories *****/
|
||||
Tst_MoveImagesToDefinitiveDirectories ();
|
||||
|
||||
/***** Insert or update question, tags and answer in the database *****/
|
||||
Tst_InsertOrUpdateQstTagsAnsIntoDB ();
|
||||
|
@ -4860,11 +4918,8 @@ void Tst_ReceiveQst (void)
|
|||
}
|
||||
else // Question is wrong
|
||||
{
|
||||
/***** Whether an image has been received or not,
|
||||
reset status and image *****/
|
||||
Gbl.Test.Image.Action = Img_ACTION_NO_IMAGE;
|
||||
Gbl.Test.Image.Status = Img_FILE_NONE;
|
||||
Gbl.Test.Image.Name[0] = '\0';
|
||||
/***** Whether images has been received or not, reset images *****/
|
||||
Tst_InitImagesOfQuestion ();
|
||||
|
||||
/***** Put form to edit question again *****/
|
||||
Tst_PutFormEditOneQst (Stem,Feedback);
|
||||
|
@ -5242,6 +5297,51 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void)
|
|||
return true; // Question format without errors
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Move images associates to a test question to their definitive directories */
|
||||
/*****************************************************************************/
|
||||
|
||||
static void Tst_MoveImagesToDefinitiveDirectories (void)
|
||||
{
|
||||
unsigned NumOpt;
|
||||
|
||||
/****** Move image associated to question stem *****/
|
||||
if (Gbl.Test.Image.Action != Img_ACTION_KEEP_IMAGE) // Don't keep the current image
|
||||
/* Remove possible file with the old image
|
||||
(the new image file is already processed
|
||||
and moved to the definitive directory) */
|
||||
Tst_RemoveImgFilesFromStemOfQsts (Gbl.CurrentCrs.Crs.CrsCod,
|
||||
Gbl.Test.QstCod);
|
||||
|
||||
if ((Gbl.Test.Image.Action == Img_ACTION_NEW_IMAGE || // Upload new image
|
||||
Gbl.Test.Image.Action == Img_ACTION_CHANGE_IMAGE) && // Replace existing image by new image
|
||||
Gbl.Test.Image.Status == Img_FILE_PROCESSED) // The new image received has been processed
|
||||
/* Move processed image to definitive directory */
|
||||
Img_MoveImageToDefinitiveDirectory (&Gbl.Test.Image);
|
||||
|
||||
/****** Move images associated to answers *****/
|
||||
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE ||
|
||||
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE)
|
||||
for (NumOpt = 0;
|
||||
NumOpt < Gbl.Test.Answer.NumOptions;
|
||||
NumOpt++)
|
||||
{
|
||||
if (Gbl.Test.Answer.Options[NumOpt].Image.Action != Img_ACTION_KEEP_IMAGE) // Don't keep the current image
|
||||
/* Remove possible file with the old image
|
||||
(the new image file is already processed
|
||||
and moved to the definitive directory) */
|
||||
Tst_RemoveImgFilesFromAnsOfQsts (Gbl.CurrentCrs.Crs.CrsCod,
|
||||
Gbl.Test.QstCod,
|
||||
NumOpt);
|
||||
|
||||
if ((Gbl.Test.Answer.Options[NumOpt].Image.Action == Img_ACTION_NEW_IMAGE || // Upload new image
|
||||
Gbl.Test.Answer.Options[NumOpt].Image.Action == Img_ACTION_CHANGE_IMAGE) && // Replace existing image by new image
|
||||
Gbl.Test.Answer.Options[NumOpt].Image.Status == Img_FILE_PROCESSED) // The new image received has been processed
|
||||
/* Move processed image to definitive directory */
|
||||
Img_MoveImageToDefinitiveDirectory (&Gbl.Test.Answer.Options[NumOpt].Image);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/******************** Get a integer number from a string *********************/
|
||||
/*****************************************************************************/
|
||||
|
@ -5384,8 +5484,12 @@ void Tst_RemoveQst (void)
|
|||
Par_GetParToText ("OnlyThisQst",YN,1);
|
||||
EditingOnlyThisQst = (Str_ConvertToUpperLetter (YN[0]) == 'Y');
|
||||
|
||||
/***** Remove image associated to question *****/
|
||||
Tst_RemoveImageFilesFromQstsInCrs (Gbl.CurrentCrs.Crs.CrsCod,Gbl.Test.QstCod);
|
||||
/***** Remove images associated to question *****/
|
||||
Tst_RemoveImgFilesFromAnsOfQsts (Gbl.CurrentCrs.Crs.CrsCod,
|
||||
Gbl.Test.QstCod,
|
||||
Tst_MAX_OPTIONS_PER_QUESTION); // All answers
|
||||
Tst_RemoveImgFilesFromStemOfQsts (Gbl.CurrentCrs.Crs.CrsCod,
|
||||
Gbl.Test.QstCod);
|
||||
|
||||
/***** Remove the question from all the tables *****/
|
||||
/* Remove answers and tags from this test question */
|
||||
|
@ -5539,11 +5643,11 @@ static void Tst_InsertOrUpdateQstIntoDB (void)
|
|||
Gbl.Test.Image.Name,
|
||||
Gbl.Test.Feedback.Text ? Gbl.Test.Feedback.Text : "",
|
||||
Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod);
|
||||
DB_QueryUPDATE (Query,"can not update question");
|
||||
|
||||
/* Update image status */
|
||||
if (Gbl.Test.Image.Name[0])
|
||||
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
|
||||
DB_QueryUPDATE (Query,"can not update question");
|
||||
|
||||
/* Remove answers and tags from this test question */
|
||||
Tst_RemAnsFromQst ();
|
||||
|
@ -5554,47 +5658,6 @@ static void Tst_InsertOrUpdateQstIntoDB (void)
|
|||
free ((void *) Query);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/******** Remove one or more image files associated to test questions ********/
|
||||
/*****************************************************************************/
|
||||
// Use question code <= 0 to remove all images associated to questions in course
|
||||
|
||||
void Tst_RemoveImageFilesFromQstsInCrs (long CrsCod,
|
||||
long QstCod) // <= 0 ==> all questions in course
|
||||
{
|
||||
char Query[256];
|
||||
MYSQL_RES *mysql_res;
|
||||
MYSQL_ROW row;
|
||||
unsigned NumImages;
|
||||
unsigned NumImg;
|
||||
|
||||
/***** Get names of images associated to test questions from database *****/
|
||||
if (QstCod > 0) // Only one question
|
||||
sprintf (Query,"SELECT Image FROM tst_questions"
|
||||
" WHERE QstCod='%ld' AND CrsCod='%ld'",
|
||||
QstCod,CrsCod);
|
||||
else // All questions in the course
|
||||
sprintf (Query,"SELECT Image FROM tst_questions"
|
||||
" WHERE CrsCod='%ld'",
|
||||
CrsCod);
|
||||
NumImages = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test images");
|
||||
|
||||
/***** Go over result removing image files *****/
|
||||
for (NumImg = 0;
|
||||
NumImg < NumImages;
|
||||
NumImg++)
|
||||
{
|
||||
/***** Get image name (row[0]) *****/
|
||||
row = mysql_fetch_row (mysql_res);
|
||||
|
||||
/***** Remove image file *****/
|
||||
Img_RemoveImageFile (row[0]);
|
||||
}
|
||||
|
||||
/***** Free structure that stores the query result *****/
|
||||
DB_FreeMySQLResult (&mysql_res);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*********************** Insert tags in the tags table ***********************/
|
||||
/*****************************************************************************/
|
||||
|
@ -5680,14 +5743,20 @@ static void Tst_InsertAnswersIntoDB (void)
|
|||
NumOpt++)
|
||||
if (Gbl.Test.Answer.Options[NumOpt].Text[0])
|
||||
{
|
||||
sprintf (Query,"INSERT INTO tst_answers (QstCod,AnsInd,Answer,Feedback,Correct)"
|
||||
" VALUES (%ld,%u,'%s','%s','%c')",
|
||||
sprintf (Query,"INSERT INTO tst_answers"
|
||||
" (QstCod,AnsInd,Answer,Feedback,Image,Correct)"
|
||||
" VALUES (%ld,%u,'%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].Image.Name,
|
||||
Gbl.Test.Answer.Options[NumOpt].Correct ? 'Y' :
|
||||
'N');
|
||||
DB_QueryINSERT (Query,"can not create answer");
|
||||
|
||||
/* Update image status */
|
||||
if (Gbl.Test.Answer.Options[NumOpt].Image.Name[0])
|
||||
Gbl.Test.Answer.Options[NumOpt].Image.Status = Img_NAME_STORED_IN_DB;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -5742,6 +5811,108 @@ static void Tst_RemoveUnusedTagsFromCurrentCrs (void)
|
|||
DB_QueryDELETE (Query,"can not remove unused tags");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/**** Remove one or more image files associated to stems of test questions ***/
|
||||
/*****************************************************************************/
|
||||
// Use question code <= 0 to remove all images associated to stems of questions in course
|
||||
|
||||
static void Tst_RemoveImgFilesFromStemOfQsts (long CrsCod,
|
||||
long QstCod) // <= 0 ==> all questions in course
|
||||
{
|
||||
char Query[256];
|
||||
MYSQL_RES *mysql_res;
|
||||
MYSQL_ROW row;
|
||||
unsigned NumImages;
|
||||
unsigned NumImg;
|
||||
|
||||
/***** 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"
|
||||
" WHERE QstCod='%ld' AND CrsCod='%ld'",
|
||||
QstCod,CrsCod);
|
||||
else // All questions in the course
|
||||
sprintf (Query,"SELECT Image FROM tst_questions"
|
||||
" WHERE CrsCod='%ld'",
|
||||
CrsCod);
|
||||
NumImages = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test images");
|
||||
|
||||
/***** Go over result removing image files *****/
|
||||
for (NumImg = 0;
|
||||
NumImg < NumImages;
|
||||
NumImg++)
|
||||
{
|
||||
/***** Get image name (row[0]) *****/
|
||||
row = mysql_fetch_row (mysql_res);
|
||||
|
||||
/***** Remove image file *****/
|
||||
Img_RemoveImageFile (row[0]);
|
||||
}
|
||||
|
||||
/***** Free structure that stores the query result *****/
|
||||
DB_FreeMySQLResult (&mysql_res);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/** Remove one or more image files associated to answers of test questions ***/
|
||||
/*****************************************************************************/
|
||||
// Use question code <= 0 to remove all images associated to answers of questions in course
|
||||
// Use AnsInd == Tst_MAX_OPTIONS_PER_QUESTION to remove all images associated to answers of a question
|
||||
|
||||
static void Tst_RemoveImgFilesFromAnsOfQsts (long CrsCod,
|
||||
long QstCod, // <= 0 ==> all questions in course
|
||||
unsigned AnsInd) // == Tst_MAX_OPTIONS_PER_QUESTION ==> all answers of a question
|
||||
{
|
||||
char Query[512];
|
||||
MYSQL_RES *mysql_res;
|
||||
MYSQL_ROW row;
|
||||
unsigned NumImages;
|
||||
unsigned NumImg;
|
||||
|
||||
/***** Get names of images associated to answers of test questions from database *****/
|
||||
if (QstCod > 0) // Only one question
|
||||
{
|
||||
if (AnsInd < Tst_MAX_OPTIONS_PER_QUESTION) // Only one answer
|
||||
sprintf (Query,"SELECT tst_answers.Image"
|
||||
" FROM tst_questions,tst_answers"
|
||||
" WHERE tst_questions.CrsCod='%ld'" // Extra check
|
||||
" AND tst_questions.QstCod='%ld'" // Extra check
|
||||
" AND tst_questions.QstCod=tst_answers.QstCod"
|
||||
" AND tst_answers.QstCod='%ld'"
|
||||
" AND tst_answers.AnsInd='%u'",
|
||||
CrsCod,QstCod,QstCod,AnsInd);
|
||||
else // All answers of a question
|
||||
sprintf (Query,"SELECT tst_answers.Image"
|
||||
" FROM tst_questions,tst_answers"
|
||||
" WHERE tst_questions.CrsCod='%ld'" // Extra check
|
||||
" AND tst_questions.QstCod='%ld'" // Extra check
|
||||
" AND tst_questions.QstCod=tst_answers.QstCod"
|
||||
" AND tst_answers.QstCod='%ld'",
|
||||
CrsCod,QstCod,QstCod);
|
||||
}
|
||||
else // All answers of all questions in the course
|
||||
sprintf (Query,"SELECT tst_answers.Image"
|
||||
" FROM tst_questions,tst_answers"
|
||||
" WHERE tst_questions.CrsCod='%ld'"
|
||||
" AND tst_questions.QstCod=tst_answers.QstCod",
|
||||
CrsCod);
|
||||
NumImages = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test images");
|
||||
|
||||
/***** Go over result removing image files *****/
|
||||
for (NumImg = 0;
|
||||
NumImg < NumImages;
|
||||
NumImg++)
|
||||
{
|
||||
/***** Get image name (row[0]) *****/
|
||||
row = mysql_fetch_row (mysql_res);
|
||||
|
||||
/***** Remove image file *****/
|
||||
Img_RemoveImageFile (row[0]);
|
||||
}
|
||||
|
||||
/***** Free structure that stores the query result *****/
|
||||
DB_FreeMySQLResult (&mysql_res);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/******************* Allocate memory for a choice answer *********************/
|
||||
/*****************************************************************************/
|
||||
|
@ -7361,8 +7532,11 @@ void Tst_RemoveCrsTests (long CrsCod)
|
|||
|
||||
/***** Remove files with images associated
|
||||
to test questions in the course *****/
|
||||
Tst_RemoveImageFilesFromQstsInCrs (CrsCod,
|
||||
-1L); // All questions in the course
|
||||
Tst_RemoveImgFilesFromAnsOfQsts (CrsCod,
|
||||
-1L, // All answers of questions in the course
|
||||
Tst_MAX_OPTIONS_PER_QUESTION); // does not matter
|
||||
Tst_RemoveImgFilesFromStemOfQsts (CrsCod,
|
||||
-1L); // All questions in the course
|
||||
|
||||
/***** Remove test questions in the course *****/
|
||||
sprintf (Query,"DELETE FROM tst_questions WHERE CrsCod='%ld'",
|
||||
|
|
|
@ -151,8 +151,6 @@ void Tst_RemoveQst (void);
|
|||
void Tst_ChangeShuffleQst (void);
|
||||
void Tst_InsertOrUpdateQstTagsAnsIntoDB (void);
|
||||
|
||||
void Tst_RemoveImageFilesFromQstsInCrs (long CrsCod,long QstCod);
|
||||
|
||||
int Tst_AllocateTextChoiceAnswer (unsigned NumOpt);
|
||||
void Tst_FreeTextChoiceAnswers (void);
|
||||
void Tst_FreeTagsList (void);
|
||||
|
|
Loading…
Reference in New Issue