mirror of https://github.com/acanas/swad-core.git
Version 15.177
This commit is contained in:
parent
4c2189921f
commit
2b59faa4ef
|
@ -139,13 +139,14 @@
|
|||
/****************************** Public constants *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
#define Log_PLATFORM_VERSION "SWAD 15.176 (2016-04-04)"
|
||||
#define Log_PLATFORM_VERSION "SWAD 15.177 (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.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.
|
||||
Forms to edit image in every unique/multiple answer. (197968 lines)
|
||||
|
|
|
@ -30,12 +30,27 @@
|
|||
#include <unistd.h> // For access, lstat, getpid, chdir, symlink
|
||||
|
||||
#include "sha2/sha2.h" // For sha-256 and sha-512 algorithms
|
||||
#include "swad_constant.h"
|
||||
#include "swad_cryptography.h"
|
||||
#include "swad_global.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************** Public constants *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/***************************** Internal constants ****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************** Internal types *******************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/************** External global variables from others modules ****************/
|
||||
/*****************************************************************************/
|
||||
|
||||
extern struct Globals Gbl;
|
||||
extern const char Str_BIN_TO_BASE64URL[64];
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -120,3 +135,18 @@ void Cry_EncryptSHA512Base64 (const char *PlainText,char EncryptedText[Cry_LENGT
|
|||
}
|
||||
EncryptedText[Cry_LENGTH_ENCRYPTED_STR_SHA512_BASE64] = '\0';
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*** Create a unique name encrypted, different each time function is called **/
|
||||
/*****************************************************************************/
|
||||
|
||||
void Cry_CreateUniqueNameEncrypted (char UniqueNameEncrypted[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1])
|
||||
{
|
||||
static unsigned NumCall = 0; // When this function is called several times in the same execution of the program, each time a new name is created
|
||||
char UniqueNamePlain[Cns_MAX_LENGTH_IP+1+10+1+10+1+10+1];
|
||||
|
||||
NumCall++;
|
||||
sprintf (UniqueNamePlain,"%s-%lx-%x-%x",
|
||||
Gbl.IP,Gbl.StartExecutionTimeUTC,Gbl.PID,NumCall);
|
||||
Cry_EncryptSHA256Base64 (UniqueNamePlain,UniqueNameEncrypted); // Make difficult to guess a unique name
|
||||
}
|
||||
|
|
|
@ -45,4 +45,6 @@
|
|||
void Cry_EncryptSHA256Base64 (const char *PlainText,char EncryptedText[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1]);
|
||||
void Cry_EncryptSHA512Base64 (const char *PlainText,char EncryptedText[Cry_LENGTH_ENCRYPTED_STR_SHA512_BASE64+1]);
|
||||
|
||||
void Cry_CreateUniqueNameEncrypted (char UniqueNameEncrypted[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1]);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -83,7 +83,6 @@ void Gbl_InitializeGlobals (void)
|
|||
extern const char *The_ThemeId[The_NUM_THEMES];
|
||||
extern const char *Ico_IconSetId[Ico_NUM_ICON_SETS];
|
||||
extern const unsigned Txt_Current_CGI_SWAD_Language;
|
||||
char UniqueNamePlain[Cns_MAX_LENGTH_IP+1+10+1+10+1];
|
||||
Txt_Language_t Lan;
|
||||
|
||||
setlocale (LC_ALL,"es_ES.utf8");
|
||||
|
@ -98,8 +97,7 @@ void Gbl_InitializeGlobals (void)
|
|||
Gbl.TimeGenerationInMicroseconds = Gbl.TimeSendInMicroseconds = 0L;
|
||||
Gbl.PID = getpid ();
|
||||
Sta_GetRemoteAddr ();
|
||||
sprintf (UniqueNamePlain,"%s-%lx-%x",Gbl.IP,Gbl.StartExecutionTimeUTC,Gbl.PID);
|
||||
Cry_EncryptSHA256Base64 (UniqueNamePlain,Gbl.UniqueNameEncrypted); // Make difficult to guess a unique name
|
||||
Cry_CreateUniqueNameEncrypted (Gbl.UniqueNameEncrypted);
|
||||
|
||||
srand ((unsigned int) Gbl.StartExecutionTimeUTC); // Initialize seed for rand()
|
||||
|
||||
|
@ -430,10 +428,6 @@ void Gbl_InitializeGlobals (void)
|
|||
Gbl.Imported.ExternalSesId[0] = '\0';
|
||||
Gbl.Imported.ExternalRole = Rol_UNKNOWN;
|
||||
|
||||
/* Related to images uploaded in a form */
|
||||
Gbl.Image.Action = Img_ACTION_NO_IMAGE;
|
||||
Gbl.Image.Status = Img_FILE_NONE;
|
||||
|
||||
Gbl.WebService.Function = Svc_unknown;
|
||||
}
|
||||
|
||||
|
|
|
@ -659,7 +659,7 @@ struct Globals
|
|||
char *Text;
|
||||
size_t Length;
|
||||
} Stem, Feedback;
|
||||
char Image[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1];
|
||||
struct Image Image;
|
||||
bool Shuffle;
|
||||
struct
|
||||
{
|
||||
|
@ -670,7 +670,7 @@ struct Globals
|
|||
bool Correct;
|
||||
char *Text;
|
||||
char *Feedback;
|
||||
char Image[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1];
|
||||
struct Image Image;
|
||||
} Options[Tst_MAX_OPTIONS_PER_QUESTION];
|
||||
long Integer;
|
||||
double FloatingPoint[2];
|
||||
|
@ -720,11 +720,13 @@ struct Globals
|
|||
float MaxPercent;
|
||||
} DegPhotos;
|
||||
} Stat;
|
||||
/*
|
||||
struct
|
||||
{
|
||||
Img_Action_t Action;
|
||||
Img_FileStatus_t Status;
|
||||
} Image;
|
||||
*/
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
96
swad_image.c
96
swad_image.c
|
@ -71,43 +71,44 @@ static void Img_ProcessImage (const char *FileNameImgOriginal,
|
|||
/***************************** Get image from form ***************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
void Img_GetImageFromForm (char *ImageName,void (*GetImageName) (void),
|
||||
const char *ParamFile,
|
||||
void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image,
|
||||
void (*GetImageName) (unsigned NumOpt,char *ImageName),
|
||||
const char *ParamAction,const char *ParamFile,
|
||||
unsigned Width,unsigned Height,unsigned Quality)
|
||||
{
|
||||
Gbl.Image.Action = Img_GetImageActionFromForm ("ImgAct");
|
||||
switch (Gbl.Image.Action)
|
||||
Image->Action = Img_GetImageActionFromForm (ParamAction);
|
||||
Image->Status = Img_FILE_NONE;
|
||||
switch (Image->Action)
|
||||
{
|
||||
case Img_ACTION_NO_IMAGE: // Do not use image (remove current image if exists)
|
||||
/***** Reset image name *****/
|
||||
ImageName[0] = '\0';
|
||||
Gbl.Image.Status = Img_FILE_NONE;
|
||||
Image->Name[0] = '\0';
|
||||
break;
|
||||
case Img_ACTION_KEEP_IMAGE: // Keep current image unchanged
|
||||
/***** Get image name *****/
|
||||
GetImageName ();
|
||||
Gbl.Image.Status = (ImageName[0] ? Img_NAME_STORED_IN_DB :
|
||||
Img_FILE_NONE);
|
||||
GetImageName (NumOpt,Image->Name);
|
||||
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 (ParamFile,Width,Height,Quality);
|
||||
if (Gbl.Image.Status != Img_FILE_PROCESSED) // No new image received-processed successfully
|
||||
Img_GetAndProcessImageFileFromForm (Image,ParamFile,Width,Height,Quality);
|
||||
if (Image->Status != Img_FILE_PROCESSED) // No new image received-processed successfully
|
||||
{
|
||||
/* Reset image name */
|
||||
ImageName[0] = '\0';
|
||||
Gbl.Image.Status = Img_FILE_NONE;
|
||||
Image->Name[0] = '\0';
|
||||
Image->Status = Img_FILE_NONE;
|
||||
}
|
||||
break;
|
||||
case Img_ACTION_CHANGE_IMAGE: // Replace old image by new image
|
||||
/***** Get new image (if present ==> process and create temporary file) *****/
|
||||
Img_GetAndProcessImageFileFromForm (ParamFile,Width,Height,Quality);
|
||||
if (Gbl.Image.Status != Img_FILE_PROCESSED) // No new image received-processed successfully
|
||||
Img_GetAndProcessImageFileFromForm (Image,ParamFile,Width,Height,Quality);
|
||||
if (Image->Status != Img_FILE_PROCESSED) // No new image received-processed successfully
|
||||
{
|
||||
/* Get image name */
|
||||
GetImageName ();
|
||||
Gbl.Image.Status = (ImageName[0] ? Img_NAME_STORED_IN_DB :
|
||||
Img_FILE_NONE);
|
||||
GetImageName (NumOpt,Image->Name);
|
||||
Image->Status = (Image->Name[0] ? Img_NAME_STORED_IN_DB :
|
||||
Img_FILE_NONE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -117,12 +118,12 @@ void Img_GetImageFromForm (char *ImageName,void (*GetImageName) (void),
|
|||
/************************* Get image action from form ************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
Img_Action_t Img_GetImageActionFromForm (const char *ParamRadio)
|
||||
Img_Action_t Img_GetImageActionFromForm (const char *ParamAction)
|
||||
{
|
||||
char UnsignedStr[10+1];
|
||||
unsigned UnsignedNum;
|
||||
|
||||
Par_GetParToText (ParamRadio,UnsignedStr,10);
|
||||
Par_GetParToText (ParamAction,UnsignedStr,10);
|
||||
if (sscanf (UnsignedStr,"%u",&UnsignedNum) != 1)
|
||||
Lay_ShowErrorAndExit ("Wrong action to perform on image.");
|
||||
if (UnsignedNum >= Img_NUM_ACTIONS)
|
||||
|
@ -135,7 +136,8 @@ Img_Action_t Img_GetImageActionFromForm (const char *ParamRadio)
|
|||
/*****************************************************************************/
|
||||
// Return true if image is created
|
||||
|
||||
void Img_GetAndProcessImageFileFromForm (const char *ParamFile,
|
||||
void Img_GetAndProcessImageFileFromForm (struct Image *Image,
|
||||
const char *ParamFile,
|
||||
unsigned Width,unsigned Height,
|
||||
unsigned Quality)
|
||||
{
|
||||
|
@ -149,8 +151,8 @@ void Img_GetAndProcessImageFileFromForm (const char *ParamFile,
|
|||
char FileNameImgTmp[PATH_MAX+1]; // Full name of temporary processed file
|
||||
bool WrongType = false;
|
||||
|
||||
/***** Reset image status *****/
|
||||
Gbl.Image.Status = Img_FILE_NONE;
|
||||
/***** Rest image file status *****/
|
||||
Image->Status = Img_FILE_NONE;
|
||||
|
||||
/***** Get filename and MIME type *****/
|
||||
Param = Fil_StartReceptionOfFile (ParamFile,FileNameImgSrc,MIMEType);
|
||||
|
@ -176,7 +178,7 @@ void Img_GetAndProcessImageFileFromForm (const char *ParamFile,
|
|||
return;
|
||||
|
||||
/***** Assign a unique name for the image *****/
|
||||
strcpy (Gbl.Test.Image,Gbl.UniqueNameEncrypted);
|
||||
Cry_CreateUniqueNameEncrypted (Image->Name);
|
||||
|
||||
/***** Create private directories if not exist *****/
|
||||
/* Create private directory for images if it does not exist */
|
||||
|
@ -191,23 +193,23 @@ void Img_GetAndProcessImageFileFromForm (const char *ParamFile,
|
|||
|
||||
/***** End the reception of original not processed image
|
||||
(it can be very big) into a temporary file *****/
|
||||
Image->Status = Img_FILE_NONE;
|
||||
sprintf (FileNameImgOrig,"%s/%s/%s/%s_original.%s",
|
||||
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,Cfg_FOLDER_IMG_TMP,
|
||||
Gbl.Test.Image,PtrExtension);
|
||||
Image->Name,PtrExtension);
|
||||
if (Fil_EndReceptionOfFile (FileNameImgOrig,Param)) // Success
|
||||
{
|
||||
Gbl.Image.Status = Img_FILE_RECEIVED;
|
||||
Image->Status = Img_FILE_RECEIVED;
|
||||
|
||||
/***** Convert original image to temporary JPEG processed file *****/
|
||||
/***** Convert original image to temporary JPEG processed file
|
||||
by calling to program that makes the conversion *****/
|
||||
sprintf (FileNameImgTmp,"%s/%s/%s/%s.jpg",
|
||||
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,Cfg_FOLDER_IMG_TMP,
|
||||
Gbl.Test.Image);
|
||||
|
||||
/* Call to program that makes the conversion */
|
||||
Image->Name);
|
||||
Img_ProcessImage (FileNameImgOrig,FileNameImgTmp,Width,Height,Quality);
|
||||
Gbl.Image.Status = Img_FILE_PROCESSED;
|
||||
Image->Status = Img_FILE_PROCESSED;
|
||||
|
||||
/***** Remove temporary file *****/
|
||||
/***** Remove temporary original file *****/
|
||||
unlink (FileNameImgOrig);
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +248,7 @@ static void Img_ProcessImage (const char *FileNameImgOriginal,
|
|||
/**** Move temporary processed image file to definitive private directory ****/
|
||||
/*****************************************************************************/
|
||||
|
||||
void Img_MoveImageToDefinitiveDirectory (void)
|
||||
void Img_MoveImageToDefinitiveDirectory (struct Image *Image)
|
||||
{
|
||||
char PathImgPriv[PATH_MAX+1];
|
||||
char FileNameImgTmp[PATH_MAX+1]; // Full name of temporary processed file
|
||||
|
@ -255,45 +257,45 @@ void Img_MoveImageToDefinitiveDirectory (void)
|
|||
/***** Create subdirectory if it does not exist *****/
|
||||
sprintf (PathImgPriv,"%s/%s/%c%c",
|
||||
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,
|
||||
Gbl.Test.Image[0],
|
||||
Gbl.Test.Image[1]);
|
||||
Image->Name[0],
|
||||
Image->Name[1]);
|
||||
Fil_CreateDirIfNotExists (PathImgPriv);
|
||||
|
||||
/***** Temporary processed file *****/
|
||||
sprintf (FileNameImgTmp,"%s/%s/%s/%s.jpg",
|
||||
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,Cfg_FOLDER_IMG_TMP,
|
||||
Gbl.Test.Image);
|
||||
Image->Name);
|
||||
|
||||
/***** Definitive processed file *****/
|
||||
sprintf (FileNameImg,"%s/%s/%c%c/%s.jpg",
|
||||
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,
|
||||
Gbl.Test.Image[0],
|
||||
Gbl.Test.Image[1],
|
||||
Gbl.Test.Image);
|
||||
Image->Name[0],
|
||||
Image->Name[1],
|
||||
Image->Name);
|
||||
|
||||
/***** Move file *****/
|
||||
if (rename (FileNameImgTmp,FileNameImg)) // Fail
|
||||
Lay_ShowAlert (Lay_ERROR,"Can not move file.");
|
||||
else // Success
|
||||
Gbl.Image.Status = Img_FILE_MOVED;
|
||||
Image->Status = Img_FILE_MOVED;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/******************** Write the image of a test question *********************/
|
||||
/*****************************************************************************/
|
||||
|
||||
void Img_ShowImage (const char *ImageName,const char *ClassImg)
|
||||
void Img_ShowImage (struct Image *Image,const char *ClassImg)
|
||||
{
|
||||
char FileNameImgPriv[PATH_MAX+1];
|
||||
char FullPathImgPriv[PATH_MAX+1];
|
||||
char URL[PATH_MAX+1];
|
||||
|
||||
/***** If no image to show ==> nothing to do *****/
|
||||
if (!ImageName)
|
||||
if (!Image->Name)
|
||||
return;
|
||||
if (!ImageName[0])
|
||||
if (!Image->Name[0])
|
||||
return;
|
||||
if (Gbl.Image.Status != Img_NAME_STORED_IN_DB)
|
||||
if (Image->Status != Img_NAME_STORED_IN_DB)
|
||||
return;
|
||||
|
||||
/***** Create a temporary public directory
|
||||
|
@ -301,11 +303,11 @@ void Img_ShowImage (const char *ImageName,const char *ClassImg)
|
|||
Brw_CreateDirDownloadTmp ();
|
||||
|
||||
/***** Build private path to image *****/
|
||||
sprintf (FileNameImgPriv,"%s.jpg",ImageName);
|
||||
sprintf (FileNameImgPriv,"%s.jpg",Image->Name);
|
||||
sprintf (FullPathImgPriv,"%s/%s/%c%c/%s",
|
||||
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,
|
||||
ImageName[0],
|
||||
ImageName[1],
|
||||
Image->Name[0],
|
||||
Image->Name[1],
|
||||
FileNameImgPriv);
|
||||
|
||||
/***** Create symbolic link from temporary public directory to private file
|
||||
|
|
42
swad_image.h
42
swad_image.h
|
@ -34,11 +34,23 @@
|
|||
/*****************************************************************************/
|
||||
/******************************* Public types ********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/***** Action to perform when editing a form with an image *****/
|
||||
#define Img_NUM_ACTIONS 4
|
||||
typedef enum
|
||||
{
|
||||
Img_ACTION_NO_IMAGE, // Do not use image (remove current image if exists)
|
||||
Img_ACTION_KEEP_IMAGE, // Keep current image unchanged
|
||||
Img_ACTION_NEW_IMAGE, // Upload new image
|
||||
Img_ACTION_CHANGE_IMAGE, // Change existing image by a new image
|
||||
} Img_Action_t;
|
||||
|
||||
/***** Status of an image file *****/
|
||||
/*
|
||||
No image Original file Temporary Definitive Name of the image
|
||||
uploaded uploaded by user processed image processed image stored in database
|
||||
--------- --------------------------- ------------------ ------------------ ---------------------
|
||||
Img_NONE Img_NONE Img_FILE_PROCESSED Img_FILE_MOVED Img_NAME_STORED_IN_DB
|
||||
Img_NONE Img_FILE_RECEIVED Img_FILE_PROCESSED Img_FILE_MOVED Img_NAME_STORED_IN_DB
|
||||
--------- --------------------------- ------------------ ------------------ ---------------------
|
||||
-> upload-file -> -> process-file -> b -> move-file -> -> insert-name ->
|
||||
--------- --------------------------- ------------------ ------------------ ---------------------
|
||||
|
@ -67,30 +79,30 @@ typedef enum
|
|||
Img_NAME_STORED_IN_DB,
|
||||
} Img_FileStatus_t;
|
||||
|
||||
/***** Action to perform when editing a form with an image *****/
|
||||
#define Img_NUM_ACTIONS 4
|
||||
typedef enum
|
||||
/***** Struct used to get images from forms *****/
|
||||
struct Image
|
||||
{
|
||||
Img_ACTION_NO_IMAGE, // Do not use image (remove current image if exists)
|
||||
Img_ACTION_KEEP_IMAGE, // Keep current image unchanged
|
||||
Img_ACTION_NEW_IMAGE, // Upload new image
|
||||
Img_ACTION_CHANGE_IMAGE, // Change existing image by a new image
|
||||
} Img_Action_t;
|
||||
Img_Action_t Action;
|
||||
Img_FileStatus_t Status;
|
||||
char Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1];
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/***************************** Public prototypes *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
void Img_GetImageFromForm (char *ImageName,void (*GetImageName) (void),
|
||||
const char *ParamFile,
|
||||
void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image,
|
||||
void (*GetImageName) (unsigned NumOpt,char *ImageName),
|
||||
const char *ParamAction,const char *ParamFile,
|
||||
unsigned Width,unsigned Height,unsigned Quality);
|
||||
Img_Action_t Img_GetImageActionFromForm (const char *ParamRadio);
|
||||
void Img_GetAndProcessImageFileFromForm (const char *ParamFile,
|
||||
Img_Action_t Img_GetImageActionFromForm (const char *ParamAction);
|
||||
void Img_GetAndProcessImageFileFromForm (struct Image *Image,
|
||||
const char *ParamFile,
|
||||
unsigned Width,unsigned Height,
|
||||
unsigned Quality);
|
||||
|
||||
void Img_MoveImageToDefinitiveDirectory (void);
|
||||
void Img_ShowImage (const char *ImageName,const char *ClassImg);
|
||||
void Img_MoveImageToDefinitiveDirectory (struct Image *Image);
|
||||
void Img_ShowImage (struct Image *Image,const char *ClassImg);
|
||||
void Img_RemoveImageFile (const char *ImageName);
|
||||
|
||||
#endif
|
||||
|
|
169
swad_test.c
169
swad_test.c
|
@ -155,8 +155,8 @@ static void Tst_ShowTestQuestionsWhenSeeing (MYSQL_RES *mysql_res);
|
|||
static void Tst_ShowTstResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank,double *TotalScore);
|
||||
static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
|
||||
double *ScoreThisQst,bool *AnswerIsNotBlank);
|
||||
static void Tst_PutFormToEditQstImage (const char *ImageName,
|
||||
const char *ParamRadio,
|
||||
static void Tst_PutFormToEditQstImage (struct Image *Image,
|
||||
const char *ParamAction,
|
||||
const char *ParamFile);
|
||||
static void Tst_UpdateScoreQst (long QstCod,float ScoreThisQst,bool AnswerIsNotBlank);
|
||||
static void Tst_UpdateMyNumAccessTst (unsigned NumAccessesTst);
|
||||
|
@ -217,7 +217,7 @@ static int Tst_CountNumAnswerTypesInList (void);
|
|||
static void Tst_PutFormEditOneQst (char *Stem,char *Feedback);
|
||||
|
||||
static void Tst_GetQstDataFromDB (char *Stem,char *Feedback);
|
||||
static void Tst_GetImageNameFromDB (void);
|
||||
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);
|
||||
|
@ -982,8 +982,10 @@ static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
|
|||
Tst_WriteQstStem (row[4],"TEST_EXA");
|
||||
if (row[5][0])
|
||||
{
|
||||
Gbl.Image.Status = Img_NAME_STORED_IN_DB;
|
||||
Img_ShowImage (row[5],"TEST_IMG_SHOW");
|
||||
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_ShowImage (&Gbl.Test.Image,"TEST_IMG_SHOW");
|
||||
}
|
||||
if (Gbl.Action.Act == ActSeeTst)
|
||||
Tst_WriteAnswersOfAQstSeeExam (NumQst,QstCod,(Str_ConvertToUpperLetter (row[3][0]) == 'Y'));
|
||||
|
@ -1029,8 +1031,8 @@ void Tst_WriteQstStem (const char *Stem,const char *ClassStem)
|
|||
/************* Put form to upload a new image for a test question ************/
|
||||
/*****************************************************************************/
|
||||
|
||||
static void Tst_PutFormToEditQstImage (const char *ImageName,
|
||||
const char *ParamRadio,
|
||||
static void Tst_PutFormToEditQstImage (struct Image *Image,
|
||||
const char *ParamAction,
|
||||
const char *ParamFile)
|
||||
{
|
||||
extern const char *The_ClassForm[The_NUM_THEMES];
|
||||
|
@ -1042,8 +1044,8 @@ static void Tst_PutFormToEditQstImage (const char *ImageName,
|
|||
|
||||
/***** No image *****/
|
||||
fprintf (Gbl.F.Out,"<input type=\"radio\" name=\"%s\" value=\"%u\"",
|
||||
ParamRadio,Img_ACTION_NO_IMAGE);
|
||||
if (!ImageName[0])
|
||||
ParamAction,Img_ACTION_NO_IMAGE);
|
||||
if (!Image->Name[0])
|
||||
fprintf (Gbl.F.Out," checked=\"checked\"");
|
||||
fprintf (Gbl.F.Out," />"
|
||||
"<label class=\"%s\">"
|
||||
|
@ -1053,43 +1055,38 @@ static void Tst_PutFormToEditQstImage (const char *ImageName,
|
|||
Txt_No_image);
|
||||
|
||||
/***** Current image *****/
|
||||
if (ImageName[0])
|
||||
if (Image->Name[0])
|
||||
{
|
||||
fprintf (Gbl.F.Out,"<input type=\"radio\" name=\"%s\" value=\"%u\" checked=\"checked\" />"
|
||||
"<label class=\"%s\">"
|
||||
"%s"
|
||||
"</label><br />",
|
||||
ParamRadio,Img_ACTION_KEEP_IMAGE,
|
||||
ParamAction,Img_ACTION_KEEP_IMAGE,
|
||||
The_ClassForm[Gbl.Prefs.Theme],
|
||||
Txt_Current_image);
|
||||
Img_ShowImage (ImageName,"TEST_IMG_EDIT_ONE");
|
||||
Img_ShowImage (Image,"TEST_IMG_EDIT_ONE");
|
||||
}
|
||||
|
||||
/***** Change/new image *****/
|
||||
UniqueId++;
|
||||
if (ImageName[0]) // Image exists
|
||||
{
|
||||
if (Image->Name[0]) // Image exists
|
||||
/***** Change image *****/
|
||||
fprintf (Gbl.F.Out,"<input type=\"radio\" id=\"chg_img_%u\" name=\"%s\""
|
||||
" value=\"%u\">",
|
||||
UniqueId,ParamRadio,Img_ACTION_CHANGE_IMAGE); // Replace existing image by new image
|
||||
fprintf (Gbl.F.Out,"<label class=\"%s\">"
|
||||
" value=\"%u\">"
|
||||
"<label class=\"%s\">"
|
||||
"%s: "
|
||||
"</label>",
|
||||
UniqueId,ParamAction,Img_ACTION_CHANGE_IMAGE, // Replace existing image by new image
|
||||
The_ClassForm[Gbl.Prefs.Theme],Txt_Change_image);
|
||||
|
||||
}
|
||||
else // Image does not exist
|
||||
{
|
||||
/***** New image *****/
|
||||
fprintf (Gbl.F.Out,"<input type=\"radio\" id=\"chg_img_%u\" name=\"%s\""
|
||||
" value=\"%u\">",
|
||||
UniqueId,ParamRadio,Img_ACTION_NEW_IMAGE); // Upload new image
|
||||
fprintf (Gbl.F.Out,"<label class=\"%s\">"
|
||||
" value=\"%u\">"
|
||||
"<label class=\"%s\">"
|
||||
"%s: "
|
||||
"</label>",
|
||||
UniqueId,ParamAction,Img_ACTION_NEW_IMAGE, // Upload new image
|
||||
The_ClassForm[Gbl.Prefs.Theme],Txt_New_image);
|
||||
}
|
||||
fprintf (Gbl.F.Out,"<input type=\"file\" name=\"%s\""
|
||||
" size=\"40\" maxlength=\"100\" value=\"\""
|
||||
" onchange=\"document.getElementById('chg_img_%u').checked = true;\" />",
|
||||
|
@ -2735,11 +2732,12 @@ static void Tst_ListOneOrMoreQuestionsToEdit (unsigned long NumRows,MYSQL_RES *m
|
|||
fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">",
|
||||
Gbl.RowEvenOdd);
|
||||
Tst_WriteQstStem (row[4],"TEST_EDI");
|
||||
Gbl.Image.Status = Img_NAME_STORED_IN_DB;
|
||||
if (row[5][0])
|
||||
{
|
||||
Gbl.Image.Status = Img_NAME_STORED_IN_DB;
|
||||
Img_ShowImage (row[5],"TEST_IMG_EDIT_LIST");
|
||||
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_ShowImage (&Gbl.Test.Image,"TEST_IMG_EDIT_LIST");
|
||||
}
|
||||
Tst_WriteQstFeedback (row[6],"TEST_EDI_LIGHT");
|
||||
Tst_WriteAnswersOfAQstEdit (QstCod);
|
||||
|
@ -4243,7 +4241,7 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
|
|||
unsigned NumTag;
|
||||
bool TagNotFound;
|
||||
bool OptionsDisabled;
|
||||
char ParamRadio[32];
|
||||
char ParamAction[32];
|
||||
char ParamFile[32];
|
||||
|
||||
/***** If no receiving the question, but editing a new or existing question
|
||||
|
@ -4356,8 +4354,8 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
|
|||
The_ClassForm[Gbl.Prefs.Theme],
|
||||
Txt_Stem,
|
||||
Stem);
|
||||
Tst_PutFormToEditQstImage (Gbl.Test.Image,
|
||||
"ImgAct",Fil_NAME_OF_PARAM_FILENAME_ORG);
|
||||
Tst_PutFormToEditQstImage (&Gbl.Test.Image,
|
||||
"ImgAct","FileImg");
|
||||
fprintf (Gbl.F.Out,"</td>"
|
||||
"</tr>");
|
||||
|
||||
|
@ -4558,9 +4556,9 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
|
|||
/* Image */
|
||||
fprintf (Gbl.F.Out,"<tr>"
|
||||
"<td colspan=\"2\" class=\"LEFT_TOP\">");
|
||||
sprintf (ParamRadio,"ImgAct%u",NumOpt);
|
||||
sprintf (ParamAction,"ImgAct%u",NumOpt);
|
||||
sprintf (ParamFile,"FileImg%u",NumOpt);
|
||||
Tst_PutFormToEditQstImage (Gbl.Test.Answer.Options[NumOpt].Image,ParamRadio,ParamFile);
|
||||
Tst_PutFormToEditQstImage (&Gbl.Test.Answer.Options[NumOpt].Image,ParamAction,ParamFile);
|
||||
// if (OptionsDisabled)
|
||||
// fprintf (Gbl.F.Out," disabled=\"disabled\"");
|
||||
fprintf (Gbl.F.Out,"</td>"
|
||||
|
@ -4603,7 +4601,9 @@ void Tst_InitQst (void)
|
|||
Gbl.Test.Stem.Length = 0;
|
||||
Gbl.Test.Feedback.Text = NULL;
|
||||
Gbl.Test.Feedback.Length = 0;
|
||||
Gbl.Test.Image[0] = '\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,7 +4615,9 @@ 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[0] = '\0';
|
||||
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] =
|
||||
|
@ -4658,12 +4660,12 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
|
|||
/* Get the image of the question from the database (row[3]) */
|
||||
if (row[3][0])
|
||||
{
|
||||
Gbl.Image.Status = Img_NAME_STORED_IN_DB;
|
||||
strncpy (Gbl.Test.Image,row[3],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
|
||||
Gbl.Test.Image[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\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.Image.Status = Img_FILE_NONE;
|
||||
Gbl.Test.Image.Status = Img_FILE_NONE;
|
||||
|
||||
/* Get the feedback of the question from the database (row[4]) */
|
||||
Feedback[0] = '\0';
|
||||
|
@ -4747,31 +4749,41 @@ static void Tst_GetQstDataFromDB (char *Stem,char *Feedback)
|
|||
/*****************************************************************************/
|
||||
/***** Get possible image associated with a test question from database ******/
|
||||
/*****************************************************************************/
|
||||
// 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 (void)
|
||||
static void Tst_GetImageNameFromDB (unsigned NumOpt,char *ImageName)
|
||||
{
|
||||
char Query[256];
|
||||
MYSQL_RES *mysql_res;
|
||||
MYSQL_ROW row;
|
||||
|
||||
/***** Get possible image associated with a test question from database *****/
|
||||
sprintf (Query,"SELECT Image FROM tst_questions"
|
||||
" WHERE QstCod='%ld' AND CrsCod='%ld'",
|
||||
Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod);
|
||||
DB_QuerySELECT (Query,&mysql_res,"can not get a question");
|
||||
/***** Build query depending on NumOpt *****/
|
||||
if (NumOpt < Tst_MAX_OPTIONS_PER_QUESTION)
|
||||
// Get image associated to answer
|
||||
sprintf (Query,"SELECT Image 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"
|
||||
" WHERE QstCod='%ld' AND CrsCod='%ld'",
|
||||
Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod);
|
||||
|
||||
/***** Query database *****/
|
||||
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]) */
|
||||
/***** Get the image of the question from the database (row[0]) *****/
|
||||
if (row[0][0]) // Image name stored in database
|
||||
{
|
||||
Gbl.Image.Status = Img_NAME_STORED_IN_DB;
|
||||
strncpy (Gbl.Test.Image,row[0],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
|
||||
Gbl.Test.Image[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
|
||||
strncpy (ImageName,row[0],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
|
||||
ImageName[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
|
||||
}
|
||||
else // No image in this question
|
||||
Gbl.Image.Status = Img_FILE_NONE;
|
||||
ImageName[0] = '\0';
|
||||
|
||||
/* Free structure that stores the query result */
|
||||
/***** Free structure that stores the query result *****/
|
||||
DB_FreeMySQLResult (&mysql_res);
|
||||
}
|
||||
|
||||
|
@ -4828,17 +4840,17 @@ void Tst_ReceiveQst (void)
|
|||
/***** Make sure that tags, text and answer are not empty *****/
|
||||
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions ())
|
||||
{
|
||||
if (Gbl.Image.Action != Img_ACTION_KEEP_IMAGE) // Don't keep the current image
|
||||
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.Image.Action == Img_ACTION_NEW_IMAGE || // Upload new image
|
||||
Gbl.Image.Action == Img_ACTION_CHANGE_IMAGE) && // Replace existing image by new image
|
||||
Gbl.Image.Status == Img_FILE_PROCESSED) // The new image received has been processed
|
||||
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 ();
|
||||
Img_MoveImageToDefinitiveDirectory (&Gbl.Test.Image);
|
||||
|
||||
/***** Insert or update question, tags and answer in the database *****/
|
||||
Tst_InsertOrUpdateQstTagsAnsIntoDB ();
|
||||
|
@ -4850,9 +4862,9 @@ void Tst_ReceiveQst (void)
|
|||
{
|
||||
/***** Whether an image has been received or not,
|
||||
reset status and image *****/
|
||||
Gbl.Image.Action = Img_ACTION_NO_IMAGE;
|
||||
Gbl.Image.Status = Img_FILE_NONE;
|
||||
Gbl.Test.Image[0] = '\0';
|
||||
Gbl.Test.Image.Action = Img_ACTION_NO_IMAGE;
|
||||
Gbl.Test.Image.Status = Img_FILE_NONE;
|
||||
Gbl.Test.Image.Name[0] = '\0';
|
||||
|
||||
/***** Put form to edit question again *****/
|
||||
Tst_PutFormEditOneQst (Stem,Feedback);
|
||||
|
@ -4879,6 +4891,8 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
|
|||
char StrMultiAns[Tst_MAX_SIZE_ANSWERS_ONE_QST+1];
|
||||
const char *Ptr;
|
||||
unsigned NumCorrectAns;
|
||||
char ParamAction[32];
|
||||
char ParamFile[32];
|
||||
|
||||
/***** Get question code *****/
|
||||
Tst_GetQstCod ();
|
||||
|
@ -4914,9 +4928,10 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
|
|||
/***** Get question stem *****/
|
||||
Par_GetParToHTML ("Stem",Stem,Cns_MAX_BYTES_TEXT);
|
||||
|
||||
/***** Get image associated to stem *****/
|
||||
Img_GetImageFromForm (Gbl.Test.Image,Tst_GetImageNameFromDB,
|
||||
Fil_NAME_OF_PARAM_FILENAME_ORG,
|
||||
/***** Get image associated to the stem *****/
|
||||
Img_GetImageFromForm (Tst_MAX_OPTIONS_PER_QUESTION,&Gbl.Test.Image,
|
||||
Tst_GetImageNameFromDB,
|
||||
"ImgAct","FileImg",
|
||||
Tst_PHOTO_SAVED_MAX_WIDTH,
|
||||
Tst_PHOTO_SAVED_MAX_HEIGHT,
|
||||
Tst_PHOTO_SAVED_QUALITY);
|
||||
|
@ -4970,6 +4985,20 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
|
|||
/* Get feedback */
|
||||
sprintf (FbStr,"FbStr%u",NumOpt);
|
||||
Par_GetParToHTML (FbStr,Gbl.Test.Answer.Options[NumOpt].Feedback,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
||||
|
||||
/* Get image associated to the answer */
|
||||
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE ||
|
||||
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE)
|
||||
{
|
||||
sprintf (ParamAction,"ImgAct%u",NumOpt);
|
||||
sprintf (ParamFile,"FileImg%u",NumOpt);
|
||||
Img_GetImageFromForm (NumOpt,&Gbl.Test.Answer.Options[NumOpt].Image,
|
||||
Tst_GetImageNameFromDB,
|
||||
ParamAction,ParamFile,
|
||||
Tst_PHOTO_SAVED_MAX_WIDTH,
|
||||
Tst_PHOTO_SAVED_MAX_HEIGHT,
|
||||
Tst_PHOTO_SAVED_QUALITY);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the numbers of correct answers */
|
||||
|
@ -5047,9 +5076,9 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void)
|
|||
bool ThereIsEndOfAnswers;
|
||||
unsigned i;
|
||||
|
||||
if ((Gbl.Image.Action == Img_ACTION_NEW_IMAGE || // Upload new image
|
||||
Gbl.Image.Action == Img_ACTION_CHANGE_IMAGE) && // Replace existing image by new image
|
||||
Gbl.Image.Status != Img_FILE_PROCESSED)
|
||||
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)
|
||||
{
|
||||
Lay_ShowAlert (Lay_WARNING,Txt_Error_receiving_or_processing_image);
|
||||
return false;
|
||||
|
@ -5487,13 +5516,13 @@ static void Tst_InsertOrUpdateQstIntoDB (void)
|
|||
Gbl.Test.Shuffle ? 'Y' :
|
||||
'N',
|
||||
Gbl.Test.Stem.Text,
|
||||
Gbl.Test.Image,
|
||||
Gbl.Test.Image.Name,
|
||||
Gbl.Test.Feedback.Text ? Gbl.Test.Feedback.Text : "");
|
||||
Gbl.Test.QstCod = DB_QueryINSERTandReturnCode (Query,"can not create question");
|
||||
|
||||
/* Update image status */
|
||||
if (Gbl.Test.Image[0])
|
||||
Gbl.Image.Status = Img_NAME_STORED_IN_DB;
|
||||
if (Gbl.Test.Image.Name[0])
|
||||
Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
|
||||
}
|
||||
else // It's an existing question
|
||||
{
|
||||
|
@ -5507,13 +5536,13 @@ static void Tst_InsertOrUpdateQstIntoDB (void)
|
|||
Gbl.Test.Shuffle ? 'Y' :
|
||||
'N',
|
||||
Gbl.Test.Stem.Text,
|
||||
Gbl.Test.Image,
|
||||
Gbl.Test.Image.Name,
|
||||
Gbl.Test.Feedback.Text ? Gbl.Test.Feedback.Text : "",
|
||||
Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod);
|
||||
|
||||
/* Update image status */
|
||||
if (Gbl.Test.Image[0])
|
||||
Gbl.Image.Status = Img_NAME_STORED_IN_DB;
|
||||
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 */
|
||||
|
|
Loading…
Reference in New Issue