diff --git a/sql/swad.sql b/sql/swad.sql
index 6bacf22ee..d6bb1e9a4 100644
--- a/sql/swad.sql
+++ b/sql/swad.sql
@@ -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,
diff --git a/swad_changelog.h b/swad_changelog.h
index 2ebc59370..7ac432d5c 100644
--- a/swad_changelog.h
+++ b/swad_changelog.h
@@ -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.
diff --git a/swad_database.c b/swad_database.c
index 5d187730d..542581b65 100644
--- a/swad_database.c
+++ b/swad_database.c
@@ -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,"
diff --git a/swad_image.c b/swad_image.c
index d25763f88..9deae8826 100644
--- a/swad_image.c
+++ b/swad_image.c
@@ -321,8 +321,9 @@ void Img_ShowImage (struct Image *Image,const char *ClassImg)
FileNameImgPriv);
/***** Show image *****/
- fprintf (Gbl.F.Out,""
- "
",
+ fprintf (Gbl.F.Out,"
"
+ "
"
+ "
",
URL,ClassImg);
}
diff --git a/swad_test.c b/swad_test.c
index a1fab49c9..6f9a96b18 100644
--- a/swad_test.c
+++ b/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,"");
- /* 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,"",
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," | "
- "",Gbl.RowEvenOdd);
+ " | ",
+ Gbl.RowEvenOdd);
if (Str_ConvertToUpperLetter (row[2][0]) == 'Y')
fprintf (Gbl.F.Out,"",
'a' + (char) NumOpt);
- /* Write the text of the answer */
- fprintf (Gbl.F.Out," | "
- "%s"
- " | ",
+ /* Write the text of the answer and the image (row[4]) */
+ fprintf (Gbl.F.Out,""
+ " "
+ "%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," ");
/* Write the text of the feedback */
- fprintf (Gbl.F.Out," | ");
+ fprintf (Gbl.F.Out," ");
if (LengthFeedback)
fprintf (Gbl.F.Out,"%s",Feedback);
- fprintf (Gbl.F.Out," | "
+ fprintf (Gbl.F.Out,""
+ ""
"
");
/* 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,""
"");
@@ -3231,10 +3260,12 @@ static void Tst_WriteChoiceAnsSeeExam (unsigned NumQst,long QstCod,bool Shuffle)
/***** Write the option text *****/
fprintf (Gbl.F.Out," | "
- "%s"
- " | "
- "
",
+ "%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,""
+ "");
}
/***** 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,""
" "
- "%s"
- " ",
+ "%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,"");
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'",
diff --git a/swad_test.h b/swad_test.h
index 1d2cb1472..f2911ce9d 100644
--- a/swad_test.h
+++ b/swad_test.h
@@ -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);
|