Version 15.184.1

This commit is contained in:
Antonio Cañas Vargas 2016-04-06 22:27:33 +02:00
parent 58ccf23b80
commit 27d20b8c63
5 changed files with 67 additions and 70 deletions

View File

@ -132,13 +132,15 @@
/****************************** Public constants *****************************/
/*****************************************************************************/
#define Log_PLATFORM_VERSION "SWAD 15.184 (2016-04-06)"
#define Log_PLATFORM_VERSION "SWAD 15.184.1 (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.184.1: Apr 06, 2016 Fixed bug when removing a test question.
Code refactoring in tests. (198680 lines)
Version 15.184: Apr 06, 2016 Code refactoring in tests and images.
Fixed bugs in test questions. (198682 lines)
Version 15.183.1: Apr 06, 2016 Fix bug in feedback of test question. (198706 lines)

View File

@ -386,6 +386,7 @@ void Gbl_InitializeGlobals (void)
Gbl.Usrs.ClassPhoto.Cols = Usr_CLASS_PHOTO_COLS_DEF;
/* Statistics */
Gbl.Stat.ClicksGroupedBy = Sta_CLICKS_CRS_PER_USR;
Gbl.Stat.CountType = Sta_TOTAL_CLICKS;
Gbl.Stat.Role = Sta_IDENTIFIED_USRS;
@ -397,19 +398,24 @@ void Gbl_InitializeGlobals (void)
Gbl.Usrs.Connected.TimeToRefreshInMs = Con_MAX_TIME_TO_REFRESH_CONNECTED_IN_MS;
/* Tests */
Gbl.Test.Config.Pluggable = Tst_PLUGGABLE_UNKNOWN;
Gbl.Test.NumQsts = Tst_CONFIG_DEFAULT_DEF_QUESTIONS;
Gbl.Test.AllowTeachers = false; // Must the exam be saved?
Gbl.Test.AllTags = Gbl.Test.AllAnsTypes = false;
Gbl.Test.TagsList = NULL;
Gbl.Test.AllAnsTypes = false;
Gbl.Test.ListAnsTypes[0] = '\0';
Gbl.Test.Tags.Num = 0;
Gbl.Test.Tags.All = false;
Gbl.Test.Tags.List = NULL;
/* Forums */
Gbl.Forum.ForumType = (For_ForumType_t) 0;
Gbl.Forum.WhichForums = For_DEFAULT_WHICH_FORUMS;
Gbl.Forum.SelectedOrderType = For_DEFAULT_ORDER;
Gbl.Forum.ThreadToMove = -1L;
/* Related to user nickname */
/* User nickname */
Gbl.Usrs.Me.UsrDat.Nickname[0] = '\0';
/* File browser */
@ -423,7 +429,7 @@ void Gbl_InitializeGlobals (void)
Gbl.ColorRows[0] = "COLOR0"; // Darker
Gbl.ColorRows[1] = "COLOR1"; // Lighter
/* Related to imported data from external site */
/* Imported data from external site */
Gbl.Imported.ExternalUsrId[0] = '\0';
Gbl.Imported.ExternalSesId[0] = '\0';
Gbl.Imported.ExternalRole = Rol_UNKNOWN;

View File

@ -643,17 +643,20 @@ struct Globals
{
struct Tst_Config Config;
long QstCod;
struct
{
unsigned Num;
bool All;
char *List;
char Txt[Tst_MAX_TAGS_PER_QUESTION][Tst_MAX_BYTES_TAG+1];
} Tags;
Tst_AnswerType_t AnswerType;
char TagText[Tst_MAX_TAGS_PER_QUESTION][Tst_MAX_BYTES_TAG+1];
unsigned NumQsts;
long QstCodes[Tst_MAX_QUESTIONS_PER_EXAM]; // Codes of the sent/received questions in a test
char StrIndexesOneQst[Tst_MAX_QUESTIONS_PER_EXAM][Tst_MAX_SIZE_INDEXES_ONE_QST+1]; // 0 1 2 3, 3 0 2 1, etc.
char StrAnswersOneQst[Tst_MAX_QUESTIONS_PER_EXAM][Tst_MAX_SIZE_ANSWERS_ONE_QST+1]; // Answers selected by user
bool AllowTeachers; // Can teachers of this course see the exam?
bool AllTags;
bool AllAnsTypes;
unsigned NumTags;
char *TagsList;
struct
{
char *Text;

View File

@ -1601,7 +1601,7 @@ static void Tst_ShowFormSelTags (unsigned long NumRows,MYSQL_RES *mysql_res,
fprintf (Gbl.F.Out,"<td class=\"%s LEFT_MIDDLE\">"
"<input type=\"checkbox\" name=\"AllTags\" value=\"Y\"",
The_ClassForm[Gbl.Prefs.Theme]);
if (Gbl.Test.AllTags)
if (Gbl.Test.Tags.All)
fprintf (Gbl.F.Out," checked=\"checked\"");
fprintf (Gbl.F.Out," onclick=\"togglecheckChildren(this,'ChkTag')\" />"
" %s"
@ -1636,9 +1636,9 @@ static void Tst_ShowFormSelTags (unsigned long NumRows,MYSQL_RES *mysql_res,
fprintf (Gbl.F.Out,"<td class=\"DAT LEFT_MIDDLE\">"
"<input type=\"checkbox\" name=\"ChkTag\" value=\"%s\"",
row[1]);
if (Gbl.Test.TagsList)
if (Gbl.Test.Tags.List)
{
Ptr = Gbl.Test.TagsList;
Ptr = Gbl.Test.Tags.List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tst_MAX_BYTES_TAG);
@ -2332,7 +2332,7 @@ static unsigned long Tst_GetQuestionsForEdit (MYSQL_RES **mysql_res)
"tst_questions.NumHits,tst_questions.NumHitsNotBlank,"
"tst_questions.Score"
" FROM tst_questions");
if (!Gbl.Test.AllTags)
if (!Gbl.Test.Tags.All)
strcat (Query,",tst_question_tags,tst_tags");
strcat (Query," WHERE tst_questions.CrsCod='");
@ -2347,7 +2347,7 @@ static unsigned long Tst_GetQuestionsForEdit (MYSQL_RES **mysql_res)
strcat (Query,"')");
/* Add the tags selected */
if (!Gbl.Test.AllTags)
if (!Gbl.Test.Tags.All)
{
strcat (Query," AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod"
@ -2356,7 +2356,7 @@ static unsigned long Tst_GetQuestionsForEdit (MYSQL_RES **mysql_res)
strcat (Query,"'");
LengthQuery = strlen (Query);
NumItemInList = 0;
Ptr = Gbl.Test.TagsList;
Ptr = Gbl.Test.Tags.List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tst_MAX_BYTES_TAG);
@ -2487,12 +2487,12 @@ static unsigned long Tst_GetQuestionsForExam (MYSQL_RES **mysql_res)
Gbl.CurrentCrs.Crs.CrsCod,
Gbl.CurrentCrs.Crs.CrsCod);
if (!Gbl.Test.AllTags) // User has not selected all the tags
if (!Gbl.Test.Tags.All) // User has not selected all the tags
{
/* Add selected tags */
LengthQuery = strlen (Query);
NumItemInList = 0;
Ptr = Gbl.Test.TagsList;
Ptr = Gbl.Test.Tags.List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tst_MAX_BYTES_TAG);
@ -2882,10 +2882,10 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
void Tst_WriteParamEditQst (void)
{
Par_PutHiddenParamChar ("AllTags",
Gbl.Test.AllTags ? 'Y' :
Gbl.Test.Tags.All ? 'Y' :
'N');
Par_PutHiddenParamString ("ChkTag",
Gbl.Test.TagsList ? Gbl.Test.TagsList :
Gbl.Test.Tags.List ? Gbl.Test.Tags.List :
"");
Par_PutHiddenParamChar ("AllAnsTypes",
Gbl.Test.AllAnsTypes ? 'Y' :
@ -3099,10 +3099,6 @@ static void Tst_WriteAnswersOfAQstAssessExam (unsigned NumQst,long QstCod,
{
MYSQL_RES *mysql_res;
/***** Create test question *****/
Tst_QstConstructor ();
Gbl.Test.QstCod = QstCod;
/***** Get answers of a question from database *****/
Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct
/*
@ -3138,9 +3134,6 @@ static void Tst_WriteAnswersOfAQstAssessExam (unsigned NumQst,long QstCod,
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
/***** Destroy test question *****/
Tst_QstDestructor ();
}
/*****************************************************************************/
@ -4154,12 +4147,12 @@ static bool Tst_GetParamsTst (void)
/***** Tags *****/
/* Get parameter that indicates whether all tags are selected */
Par_GetParToText ("AllTags",YN,1);
Gbl.Test.AllTags = (Str_ConvertToUpperLetter (YN[0]) == 'Y');
Gbl.Test.Tags.All = (Str_ConvertToUpperLetter (YN[0]) == 'Y');
/* Get the tags */
if ((Gbl.Test.TagsList = malloc (Tst_MAX_BYTES_TAGS_LIST+1)) == NULL)
if ((Gbl.Test.Tags.List = malloc (Tst_MAX_BYTES_TAGS_LIST+1)) == NULL)
Lay_ShowErrorAndExit ("Not enough memory to store tags.");
Par_GetParMultiToText ("ChkTag",Gbl.Test.TagsList,Tst_MAX_BYTES_TAGS_LIST);
Par_GetParMultiToText ("ChkTag",Gbl.Test.Tags.List,Tst_MAX_BYTES_TAGS_LIST);
/* Check number of tags selected */
if (Tst_CountNumTagsInList () == 0) // If no tags selected...
@ -4282,10 +4275,10 @@ static int Tst_CountNumTagsInList (void)
int NumTags = 0;
char TagText[Tst_MAX_BYTES_TAG+1];
/***** Go over the list Gbl.Test.TagsList counting the number of tags *****/
if (Gbl.Test.TagsList)
/***** Go over the list Gbl.Test.Tags.List counting the number of tags *****/
if (Gbl.Test.Tags.List)
{
Ptr = Gbl.Test.TagsList;
Ptr = Gbl.Test.Tags.List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tst_MAX_BYTES_TAG);
@ -4322,10 +4315,11 @@ static int Tst_CountNumAnswerTypesInList (void)
void Tst_FreeTagsList (void)
{
if (Gbl.Test.TagsList)
if (Gbl.Test.Tags.List)
{
free ((void *) Gbl.Test.TagsList);
Gbl.Test.TagsList = NULL;
free ((void *) Gbl.Test.Tags.List);
Gbl.Test.Tags.List = NULL;
Gbl.Test.Tags.Num = 0;
}
}
@ -4453,7 +4447,7 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
row = mysql_fetch_row (mysql_res);
fprintf (Gbl.F.Out,"<option value=\"%s\"",row[1]);
if (!strcasecmp (Gbl.Test.TagText[NumTag],row[1]))
if (!strcasecmp (Gbl.Test.Tags.Txt[NumTag],row[1]))
{
fprintf (Gbl.F.Out," selected=\"selected\"");
TagNotFound = false;
@ -4461,9 +4455,9 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
fprintf (Gbl.F.Out,">%s</option>",row[1]);
}
/* If it's a new tag received from the form */
if (TagNotFound && Gbl.Test.TagText[NumTag][0])
if (TagNotFound && Gbl.Test.Tags.Txt[NumTag][0])
fprintf (Gbl.F.Out,"<option value=\"%s\" selected=\"selected\">%s</option>",
Gbl.Test.TagText[NumTag],Gbl.Test.TagText[NumTag]);
Gbl.Test.Tags.Txt[NumTag],Gbl.Test.Tags.Txt[NumTag]);
fprintf (Gbl.F.Out,"<option value=\"\">[%s]</option>"
"</select>"
"</td>",
@ -4475,7 +4469,7 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
" class=\"TAG_TXT\" maxlength=\"%u\" value=\"%s\""
" onchange=\"changeSelTag('%u')\" />"
"</td>",
NumTag,NumTag,Tst_MAX_TAG_LENGTH,Gbl.Test.TagText[NumTag],NumTag);
NumTag,NumTag,Tst_MAX_TAG_LENGTH,Gbl.Test.Tags.Txt[NumTag],NumTag);
fprintf (Gbl.F.Out,"</tr>");
}
@ -4733,15 +4727,8 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
void Tst_QstConstructor (void)
{
unsigned NumOpt;
unsigned NumTag;
Gbl.Test.QstCod = -1L;
for (NumTag = 0;
NumTag < Tst_MAX_TAGS_PER_QUESTION;
NumTag++)
Gbl.Test.TagText[NumTag][0] = '\0';
Gbl.Test.NumTags = 0;
Gbl.Test.TagsList = NULL;
Gbl.Test.Stem.Text = NULL;
Gbl.Test.Stem.Length = 0;
Gbl.Test.Feedback.Text = NULL;
@ -4933,8 +4920,8 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
NumRow++)
{
row = mysql_fetch_row (mysql_res);
strncpy (Gbl.Test.TagText[NumRow],row[0],Tst_MAX_BYTES_TAG);
Gbl.Test.TagText[NumRow][Tst_MAX_BYTES_TAG] = '\0';
strncpy (Gbl.Test.Tags.Txt[NumRow],row[0],Tst_MAX_BYTES_TAG);
Gbl.Test.Tags.Txt[NumRow][Tst_MAX_BYTES_TAG] = '\0';
}
/* Free structure that stores the query result */
@ -5148,19 +5135,19 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
NumTag++)
{
sprintf (TagStr,"TagTxt%u",NumTag);
Par_GetParToText (TagStr,Gbl.Test.TagText[NumTag],Tst_MAX_BYTES_TAG);
Par_GetParToText (TagStr,Gbl.Test.Tags.Txt[NumTag],Tst_MAX_BYTES_TAG);
if (Gbl.Test.TagText[NumTag][0])
if (Gbl.Test.Tags.Txt[NumTag][0])
{
Str_ChangeFormat (Str_FROM_FORM,Str_TO_TEXT,
Gbl.Test.TagText[NumTag],Tst_MAX_BYTES_TAG,true);
Gbl.Test.Tags.Txt[NumTag],Tst_MAX_BYTES_TAG,true);
/* Check if not repeated */
for (NumTagRead = 0;
NumTagRead < NumTag;
NumTagRead++)
if (!strcmp (Gbl.Test.TagText[NumTagRead],Gbl.Test.TagText[NumTag]))
if (!strcmp (Gbl.Test.Tags.Txt[NumTagRead],Gbl.Test.Tags.Txt[NumTag]))
{
Gbl.Test.TagText[NumTag][0] = '\0';
Gbl.Test.Tags.Txt[NumTag][0] = '\0';
break;
}
}
@ -5282,11 +5269,11 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
}
/***** Adjust global variables related to this test question *****/
for (NumTag = 0, Gbl.Test.NumTags = 0;
for (NumTag = 0, Gbl.Test.Tags.Num = 0;
NumTag < Tst_MAX_TAGS_PER_QUESTION;
NumTag++)
if (Gbl.Test.TagText[NumTag][0])
Gbl.Test.NumTags++;
if (Gbl.Test.Tags.Txt[NumTag][0])
Gbl.Test.Tags.Num++;
Gbl.Test.Stem.Text = Stem;
Gbl.Test.Stem.Length = strlen (Gbl.Test.Stem.Text);
Gbl.Test.Feedback.Text = Feedback;
@ -5330,7 +5317,7 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void)
Gbl.Test.Answer.NumOptions = 0;
/***** A question must have at least one tag *****/
if (!Gbl.Test.NumTags) // There are no tags with text
if (!Gbl.Test.Tags.Num) // There are no tags with text
{
Lay_ShowAlert (Lay_WARNING,Txt_You_must_type_at_least_one_tag_for_the_question);
return false;
@ -5942,14 +5929,14 @@ static void Tst_InsertTagsIntoDB (void)
/***** For each tag... *****/
for (NumTag = 0, TagIdx = 0;
TagIdx < Gbl.Test.NumTags;
TagIdx < Gbl.Test.Tags.Num;
NumTag++)
if (Gbl.Test.TagText[NumTag][0])
if (Gbl.Test.Tags.Txt[NumTag][0])
{
/***** Check if this tag exists for current course *****/
if ((TagCod = Tst_GetTagCodFromTagTxt (Gbl.Test.TagText[NumTag])) < 0)
if ((TagCod = Tst_GetTagCodFromTagTxt (Gbl.Test.Tags.Txt[NumTag])) < 0)
/* This tag is new for current course. Add it to tags table */
TagCod = Tst_CreateNewTag (Gbl.CurrentCrs.Crs.CrsCod,Gbl.Test.TagText[NumTag]);
TagCod = Tst_CreateNewTag (Gbl.CurrentCrs.Crs.CrsCod,Gbl.Test.Tags.Txt[NumTag]);
/***** Insert tag in tst_question_tags *****/
sprintf (Query,"INSERT INTO tst_question_tags (QstCod,TagCod,TagInd)"

View File

@ -551,22 +551,21 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
Lay_ShowErrorAndExit ("Wrong type of answer.");
/* Get tags */
Gbl.Test.NumTags = 0;
for (TagsElem = QuestionElem->FirstChild;
for (TagsElem = QuestionElem->FirstChild, Gbl.Test.Tags.Num = 0;
TagsElem != NULL;
TagsElem = TagsElem->NextBrother)
if (!strcmp (TagsElem->TagName,"tags"))
{
for (TagElem = TagsElem->FirstChild;
TagElem != NULL && Gbl.Test.NumTags < Tst_MAX_TAGS_PER_QUESTION;
TagElem != NULL && Gbl.Test.Tags.Num < Tst_MAX_TAGS_PER_QUESTION;
TagElem = TagElem->NextBrother)
if (!strcmp (TagElem->TagName,"tag"))
{
if (TagElem->Content)
{
strncpy (Gbl.Test.TagText[Gbl.Test.NumTags],TagElem->Content,Tst_MAX_BYTES_TAG);
Gbl.Test.TagText[Gbl.Test.NumTags][Tst_MAX_BYTES_TAG] = '\0';
Gbl.Test.NumTags++;
strncpy (Gbl.Test.Tags.Txt[Gbl.Test.Tags.Num],TagElem->Content,Tst_MAX_BYTES_TAG);
Gbl.Test.Tags.Txt[Gbl.Test.Tags.Num][Tst_MAX_BYTES_TAG] = '\0';
Gbl.Test.Tags.Num++;
}
}
break; // Only first element "tags"
@ -1051,12 +1050,12 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
/***** Write the question tags *****/
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">",
Gbl.RowEvenOdd);
if (Gbl.Test.NumTags)
if (Gbl.Test.Tags.Num)
{
/***** Write the tags *****/
fprintf (Gbl.F.Out,"<table>");
for (NumTag = 0;
NumTag < Gbl.Test.NumTags;
NumTag < Gbl.Test.Tags.Num;
NumTag++)
fprintf (Gbl.F.Out,"<tr>"
"<td class=\"%s LEFT_TOP\">"
@ -1067,7 +1066,7 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
"</td>"
"</tr>",
ClassData,
ClassData,Gbl.Test.TagText[NumTag]);
ClassData,Gbl.Test.Tags.Txt[NumTag]);
fprintf (Gbl.F.Out,"</table>");
}
else // no tags for this question