Version 15.177

This commit is contained in:
Antonio Cañas Vargas 2016-04-04 14:48:12 +02:00
parent 4c2189921f
commit 2b59faa4ef
8 changed files with 214 additions and 142 deletions

View File

@ -139,13 +139,14 @@
/****************************** Public constants *****************************/ /****************************** 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 CSS_FILE "swad15.175.10.css"
#define JS_FILE "swad15.131.3.js" #define JS_FILE "swad15.131.3.js"
// Number of lines (includes comments but not blank lines) has been got with the following command: // 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 // 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.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. 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) Forms to edit image in every unique/multiple answer. (197968 lines)

View File

@ -30,12 +30,27 @@
#include <unistd.h> // For access, lstat, getpid, chdir, symlink #include <unistd.h> // For access, lstat, getpid, chdir, symlink
#include "sha2/sha2.h" // For sha-256 and sha-512 algorithms #include "sha2/sha2.h" // For sha-256 and sha-512 algorithms
#include "swad_constant.h"
#include "swad_cryptography.h" #include "swad_cryptography.h"
#include "swad_global.h"
/*****************************************************************************/
/****************************** Public constants *****************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Internal constants ****************************/
/*****************************************************************************/
/*****************************************************************************/
/****************************** Internal types *******************************/
/*****************************************************************************/
/*****************************************************************************/ /*****************************************************************************/
/************** External global variables from others modules ****************/ /************** External global variables from others modules ****************/
/*****************************************************************************/ /*****************************************************************************/
extern struct Globals Gbl;
extern const char Str_BIN_TO_BASE64URL[64]; 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'; 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
}

View File

@ -45,4 +45,6 @@
void Cry_EncryptSHA256Base64 (const char *PlainText,char EncryptedText[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1]); 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_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 #endif

View File

@ -83,7 +83,6 @@ void Gbl_InitializeGlobals (void)
extern const char *The_ThemeId[The_NUM_THEMES]; extern const char *The_ThemeId[The_NUM_THEMES];
extern const char *Ico_IconSetId[Ico_NUM_ICON_SETS]; extern const char *Ico_IconSetId[Ico_NUM_ICON_SETS];
extern const unsigned Txt_Current_CGI_SWAD_Language; extern const unsigned Txt_Current_CGI_SWAD_Language;
char UniqueNamePlain[Cns_MAX_LENGTH_IP+1+10+1+10+1];
Txt_Language_t Lan; Txt_Language_t Lan;
setlocale (LC_ALL,"es_ES.utf8"); setlocale (LC_ALL,"es_ES.utf8");
@ -98,8 +97,7 @@ void Gbl_InitializeGlobals (void)
Gbl.TimeGenerationInMicroseconds = Gbl.TimeSendInMicroseconds = 0L; Gbl.TimeGenerationInMicroseconds = Gbl.TimeSendInMicroseconds = 0L;
Gbl.PID = getpid (); Gbl.PID = getpid ();
Sta_GetRemoteAddr (); Sta_GetRemoteAddr ();
sprintf (UniqueNamePlain,"%s-%lx-%x",Gbl.IP,Gbl.StartExecutionTimeUTC,Gbl.PID); Cry_CreateUniqueNameEncrypted (Gbl.UniqueNameEncrypted);
Cry_EncryptSHA256Base64 (UniqueNamePlain,Gbl.UniqueNameEncrypted); // Make difficult to guess a unique name
srand ((unsigned int) Gbl.StartExecutionTimeUTC); // Initialize seed for rand() srand ((unsigned int) Gbl.StartExecutionTimeUTC); // Initialize seed for rand()
@ -430,10 +428,6 @@ void Gbl_InitializeGlobals (void)
Gbl.Imported.ExternalSesId[0] = '\0'; Gbl.Imported.ExternalSesId[0] = '\0';
Gbl.Imported.ExternalRole = Rol_UNKNOWN; 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; Gbl.WebService.Function = Svc_unknown;
} }

View File

@ -659,7 +659,7 @@ struct Globals
char *Text; char *Text;
size_t Length; size_t Length;
} Stem, Feedback; } Stem, Feedback;
char Image[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1]; struct Image Image;
bool Shuffle; bool Shuffle;
struct struct
{ {
@ -670,7 +670,7 @@ struct Globals
bool Correct; bool Correct;
char *Text; char *Text;
char *Feedback; char *Feedback;
char Image[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1]; struct Image Image;
} Options[Tst_MAX_OPTIONS_PER_QUESTION]; } Options[Tst_MAX_OPTIONS_PER_QUESTION];
long Integer; long Integer;
double FloatingPoint[2]; double FloatingPoint[2];
@ -720,11 +720,13 @@ struct Globals
float MaxPercent; float MaxPercent;
} DegPhotos; } DegPhotos;
} Stat; } Stat;
/*
struct struct
{ {
Img_Action_t Action; Img_Action_t Action;
Img_FileStatus_t Status; Img_FileStatus_t Status;
} Image; } Image;
*/
}; };
/*****************************************************************************/ /*****************************************************************************/

View File

@ -71,43 +71,44 @@ static void Img_ProcessImage (const char *FileNameImgOriginal,
/***************************** Get image from form ***************************/ /***************************** Get image from form ***************************/
/*****************************************************************************/ /*****************************************************************************/
void Img_GetImageFromForm (char *ImageName,void (*GetImageName) (void), void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image,
const char *ParamFile, void (*GetImageName) (unsigned NumOpt,char *ImageName),
const char *ParamAction,const char *ParamFile,
unsigned Width,unsigned Height,unsigned Quality) unsigned Width,unsigned Height,unsigned Quality)
{ {
Gbl.Image.Action = Img_GetImageActionFromForm ("ImgAct"); Image->Action = Img_GetImageActionFromForm (ParamAction);
switch (Gbl.Image.Action) Image->Status = Img_FILE_NONE;
switch (Image->Action)
{ {
case Img_ACTION_NO_IMAGE: // Do not use image (remove current image if exists) case Img_ACTION_NO_IMAGE: // Do not use image (remove current image if exists)
/***** Reset image name *****/ /***** Reset image name *****/
ImageName[0] = '\0'; Image->Name[0] = '\0';
Gbl.Image.Status = Img_FILE_NONE;
break; break;
case Img_ACTION_KEEP_IMAGE: // Keep current image unchanged case Img_ACTION_KEEP_IMAGE: // Keep current image unchanged
/***** Get image name *****/ /***** Get image name *****/
GetImageName (); GetImageName (NumOpt,Image->Name);
Gbl.Image.Status = (ImageName[0] ? Img_NAME_STORED_IN_DB : if (Image->Name[0])
Img_FILE_NONE); Image->Status = Img_NAME_STORED_IN_DB;
break; break;
case Img_ACTION_NEW_IMAGE: // Upload new image case Img_ACTION_NEW_IMAGE: // Upload new image
/***** Get new image (if present ==> process and create temporary file) *****/ /***** Get new image (if present ==> process and create temporary file) *****/
Img_GetAndProcessImageFileFromForm (ParamFile,Width,Height,Quality); Img_GetAndProcessImageFileFromForm (Image,ParamFile,Width,Height,Quality);
if (Gbl.Image.Status != Img_FILE_PROCESSED) // No new image received-processed successfully if (Image->Status != Img_FILE_PROCESSED) // No new image received-processed successfully
{ {
/* Reset image name */ /* Reset image name */
ImageName[0] = '\0'; Image->Name[0] = '\0';
Gbl.Image.Status = Img_FILE_NONE; Image->Status = Img_FILE_NONE;
} }
break; break;
case Img_ACTION_CHANGE_IMAGE: // Replace old image by new image case Img_ACTION_CHANGE_IMAGE: // Replace old image by new image
/***** Get new image (if present ==> process and create temporary file) *****/ /***** Get new image (if present ==> process and create temporary file) *****/
Img_GetAndProcessImageFileFromForm (ParamFile,Width,Height,Quality); Img_GetAndProcessImageFileFromForm (Image,ParamFile,Width,Height,Quality);
if (Gbl.Image.Status != Img_FILE_PROCESSED) // No new image received-processed successfully if (Image->Status != Img_FILE_PROCESSED) // No new image received-processed successfully
{ {
/* Get image name */ /* Get image name */
GetImageName (); GetImageName (NumOpt,Image->Name);
Gbl.Image.Status = (ImageName[0] ? Img_NAME_STORED_IN_DB : Image->Status = (Image->Name[0] ? Img_NAME_STORED_IN_DB :
Img_FILE_NONE); Img_FILE_NONE);
} }
break; break;
} }
@ -117,12 +118,12 @@ void Img_GetImageFromForm (char *ImageName,void (*GetImageName) (void),
/************************* Get image action from form ************************/ /************************* 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]; char UnsignedStr[10+1];
unsigned UnsignedNum; unsigned UnsignedNum;
Par_GetParToText (ParamRadio,UnsignedStr,10); Par_GetParToText (ParamAction,UnsignedStr,10);
if (sscanf (UnsignedStr,"%u",&UnsignedNum) != 1) if (sscanf (UnsignedStr,"%u",&UnsignedNum) != 1)
Lay_ShowErrorAndExit ("Wrong action to perform on image."); Lay_ShowErrorAndExit ("Wrong action to perform on image.");
if (UnsignedNum >= Img_NUM_ACTIONS) if (UnsignedNum >= Img_NUM_ACTIONS)
@ -135,7 +136,8 @@ Img_Action_t Img_GetImageActionFromForm (const char *ParamRadio)
/*****************************************************************************/ /*****************************************************************************/
// Return true if image is created // 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 Width,unsigned Height,
unsigned Quality) unsigned Quality)
{ {
@ -149,8 +151,8 @@ void Img_GetAndProcessImageFileFromForm (const char *ParamFile,
char FileNameImgTmp[PATH_MAX+1]; // Full name of temporary processed file char FileNameImgTmp[PATH_MAX+1]; // Full name of temporary processed file
bool WrongType = false; bool WrongType = false;
/***** Reset image status *****/ /***** Rest image file status *****/
Gbl.Image.Status = Img_FILE_NONE; Image->Status = Img_FILE_NONE;
/***** Get filename and MIME type *****/ /***** Get filename and MIME type *****/
Param = Fil_StartReceptionOfFile (ParamFile,FileNameImgSrc,MIMEType); Param = Fil_StartReceptionOfFile (ParamFile,FileNameImgSrc,MIMEType);
@ -176,7 +178,7 @@ void Img_GetAndProcessImageFileFromForm (const char *ParamFile,
return; return;
/***** Assign a unique name for the image *****/ /***** 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 directories if not exist *****/
/* Create private directory for images if it does 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 /***** End the reception of original not processed image
(it can be very big) into a temporary file *****/ (it can be very big) into a temporary file *****/
Image->Status = Img_FILE_NONE;
sprintf (FileNameImgOrig,"%s/%s/%s/%s_original.%s", sprintf (FileNameImgOrig,"%s/%s/%s/%s_original.%s",
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,Cfg_FOLDER_IMG_TMP, Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,Cfg_FOLDER_IMG_TMP,
Gbl.Test.Image,PtrExtension); Image->Name,PtrExtension);
if (Fil_EndReceptionOfFile (FileNameImgOrig,Param)) // Success 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", sprintf (FileNameImgTmp,"%s/%s/%s/%s.jpg",
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,Cfg_FOLDER_IMG_TMP, Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,Cfg_FOLDER_IMG_TMP,
Gbl.Test.Image); Image->Name);
/* Call to program that makes the conversion */
Img_ProcessImage (FileNameImgOrig,FileNameImgTmp,Width,Height,Quality); 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); unlink (FileNameImgOrig);
} }
} }
@ -246,7 +248,7 @@ static void Img_ProcessImage (const char *FileNameImgOriginal,
/**** Move temporary processed image file to definitive private directory ****/ /**** 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 PathImgPriv[PATH_MAX+1];
char FileNameImgTmp[PATH_MAX+1]; // Full name of temporary processed file 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 *****/ /***** Create subdirectory if it does not exist *****/
sprintf (PathImgPriv,"%s/%s/%c%c", sprintf (PathImgPriv,"%s/%s/%c%c",
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG, Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,
Gbl.Test.Image[0], Image->Name[0],
Gbl.Test.Image[1]); Image->Name[1]);
Fil_CreateDirIfNotExists (PathImgPriv); Fil_CreateDirIfNotExists (PathImgPriv);
/***** Temporary processed file *****/ /***** Temporary processed file *****/
sprintf (FileNameImgTmp,"%s/%s/%s/%s.jpg", sprintf (FileNameImgTmp,"%s/%s/%s/%s.jpg",
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,Cfg_FOLDER_IMG_TMP, Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,Cfg_FOLDER_IMG_TMP,
Gbl.Test.Image); Image->Name);
/***** Definitive processed file *****/ /***** Definitive processed file *****/
sprintf (FileNameImg,"%s/%s/%c%c/%s.jpg", sprintf (FileNameImg,"%s/%s/%c%c/%s.jpg",
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG, Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,
Gbl.Test.Image[0], Image->Name[0],
Gbl.Test.Image[1], Image->Name[1],
Gbl.Test.Image); Image->Name);
/***** Move file *****/ /***** Move file *****/
if (rename (FileNameImgTmp,FileNameImg)) // Fail if (rename (FileNameImgTmp,FileNameImg)) // Fail
Lay_ShowAlert (Lay_ERROR,"Can not move file."); Lay_ShowAlert (Lay_ERROR,"Can not move file.");
else // Success else // Success
Gbl.Image.Status = Img_FILE_MOVED; Image->Status = Img_FILE_MOVED;
} }
/*****************************************************************************/ /*****************************************************************************/
/******************** Write the image of a test question *********************/ /******************** 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 FileNameImgPriv[PATH_MAX+1];
char FullPathImgPriv[PATH_MAX+1]; char FullPathImgPriv[PATH_MAX+1];
char URL[PATH_MAX+1]; char URL[PATH_MAX+1];
/***** If no image to show ==> nothing to do *****/ /***** If no image to show ==> nothing to do *****/
if (!ImageName) if (!Image->Name)
return; return;
if (!ImageName[0]) if (!Image->Name[0])
return; return;
if (Gbl.Image.Status != Img_NAME_STORED_IN_DB) if (Image->Status != Img_NAME_STORED_IN_DB)
return; return;
/***** Create a temporary public directory /***** Create a temporary public directory
@ -301,11 +303,11 @@ void Img_ShowImage (const char *ImageName,const char *ClassImg)
Brw_CreateDirDownloadTmp (); Brw_CreateDirDownloadTmp ();
/***** Build private path to image *****/ /***** Build private path to image *****/
sprintf (FileNameImgPriv,"%s.jpg",ImageName); sprintf (FileNameImgPriv,"%s.jpg",Image->Name);
sprintf (FullPathImgPriv,"%s/%s/%c%c/%s", sprintf (FullPathImgPriv,"%s/%s/%c%c/%s",
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG, Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_IMG,
ImageName[0], Image->Name[0],
ImageName[1], Image->Name[1],
FileNameImgPriv); FileNameImgPriv);
/***** Create symbolic link from temporary public directory to private file /***** Create symbolic link from temporary public directory to private file

View File

@ -34,11 +34,23 @@
/*****************************************************************************/ /*****************************************************************************/
/******************************* Public types ********************************/ /******************************* 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 No image Original file Temporary Definitive Name of the image
uploaded uploaded by user processed image processed image stored in database 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 -> -> upload-file -> -> process-file -> b -> move-file -> -> insert-name ->
--------- --------------------------- ------------------ ------------------ --------------------- --------- --------------------------- ------------------ ------------------ ---------------------
@ -67,30 +79,30 @@ typedef enum
Img_NAME_STORED_IN_DB, Img_NAME_STORED_IN_DB,
} Img_FileStatus_t; } Img_FileStatus_t;
/***** Action to perform when editing a form with an image *****/ /***** Struct used to get images from forms *****/
#define Img_NUM_ACTIONS 4 struct Image
typedef enum
{ {
Img_ACTION_NO_IMAGE, // Do not use image (remove current image if exists) Img_Action_t Action;
Img_ACTION_KEEP_IMAGE, // Keep current image unchanged Img_FileStatus_t Status;
Img_ACTION_NEW_IMAGE, // Upload new image char Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64+1];
Img_ACTION_CHANGE_IMAGE, // Change existing image by a new image };
} Img_Action_t;
/*****************************************************************************/ /*****************************************************************************/
/***************************** Public prototypes *****************************/ /***************************** Public prototypes *****************************/
/*****************************************************************************/ /*****************************************************************************/
void Img_GetImageFromForm (char *ImageName,void (*GetImageName) (void), void Img_GetImageFromForm (unsigned NumOpt,struct Image *Image,
const char *ParamFile, void (*GetImageName) (unsigned NumOpt,char *ImageName),
const char *ParamAction,const char *ParamFile,
unsigned Width,unsigned Height,unsigned Quality); unsigned Width,unsigned Height,unsigned Quality);
Img_Action_t Img_GetImageActionFromForm (const char *ParamRadio); Img_Action_t Img_GetImageActionFromForm (const char *ParamAction);
void Img_GetAndProcessImageFileFromForm (const char *ParamFile, void Img_GetAndProcessImageFileFromForm (struct Image *Image,
const char *ParamFile,
unsigned Width,unsigned Height, unsigned Width,unsigned Height,
unsigned Quality); unsigned Quality);
void Img_MoveImageToDefinitiveDirectory (void); void Img_MoveImageToDefinitiveDirectory (struct Image *Image);
void Img_ShowImage (const char *ImageName,const char *ClassImg); void Img_ShowImage (struct Image *Image,const char *ClassImg);
void Img_RemoveImageFile (const char *ImageName); void Img_RemoveImageFile (const char *ImageName);
#endif #endif

View File

@ -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_ShowTstResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank,double *TotalScore);
static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row, static void Tst_WriteQstAndAnsExam (unsigned NumQst,long QstCod,MYSQL_ROW row,
double *ScoreThisQst,bool *AnswerIsNotBlank); double *ScoreThisQst,bool *AnswerIsNotBlank);
static void Tst_PutFormToEditQstImage (const char *ImageName, static void Tst_PutFormToEditQstImage (struct Image *Image,
const char *ParamRadio, const char *ParamAction,
const char *ParamFile); const char *ParamFile);
static void Tst_UpdateScoreQst (long QstCod,float ScoreThisQst,bool AnswerIsNotBlank); static void Tst_UpdateScoreQst (long QstCod,float ScoreThisQst,bool AnswerIsNotBlank);
static void Tst_UpdateMyNumAccessTst (unsigned NumAccessesTst); 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_PutFormEditOneQst (char *Stem,char *Feedback);
static void Tst_GetQstDataFromDB (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 Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr);
static void Tst_GetQstFromForm (char *Stem,char *Feedback); 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"); Tst_WriteQstStem (row[4],"TEST_EXA");
if (row[5][0]) if (row[5][0])
{ {
Gbl.Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
Img_ShowImage (row[5],"TEST_IMG_SHOW"); 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) if (Gbl.Action.Act == ActSeeTst)
Tst_WriteAnswersOfAQstSeeExam (NumQst,QstCod,(Str_ConvertToUpperLetter (row[3][0]) == 'Y')); 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 ************/ /************* Put form to upload a new image for a test question ************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_PutFormToEditQstImage (const char *ImageName, static void Tst_PutFormToEditQstImage (struct Image *Image,
const char *ParamRadio, const char *ParamAction,
const char *ParamFile) const char *ParamFile)
{ {
extern const char *The_ClassForm[The_NUM_THEMES]; extern const char *The_ClassForm[The_NUM_THEMES];
@ -1042,8 +1044,8 @@ static void Tst_PutFormToEditQstImage (const char *ImageName,
/***** No image *****/ /***** No image *****/
fprintf (Gbl.F.Out,"<input type=\"radio\" name=\"%s\" value=\"%u\"", fprintf (Gbl.F.Out,"<input type=\"radio\" name=\"%s\" value=\"%u\"",
ParamRadio,Img_ACTION_NO_IMAGE); ParamAction,Img_ACTION_NO_IMAGE);
if (!ImageName[0]) if (!Image->Name[0])
fprintf (Gbl.F.Out," checked=\"checked\""); fprintf (Gbl.F.Out," checked=\"checked\"");
fprintf (Gbl.F.Out," />" fprintf (Gbl.F.Out," />"
"<label class=\"%s\">" "<label class=\"%s\">"
@ -1053,43 +1055,38 @@ static void Tst_PutFormToEditQstImage (const char *ImageName,
Txt_No_image); Txt_No_image);
/***** Current image *****/ /***** Current image *****/
if (ImageName[0]) if (Image->Name[0])
{ {
fprintf (Gbl.F.Out,"<input type=\"radio\" name=\"%s\" value=\"%u\" checked=\"checked\" />" fprintf (Gbl.F.Out,"<input type=\"radio\" name=\"%s\" value=\"%u\" checked=\"checked\" />"
"<label class=\"%s\">" "<label class=\"%s\">"
"%s" "%s"
"</label><br />", "</label><br />",
ParamRadio,Img_ACTION_KEEP_IMAGE, ParamAction,Img_ACTION_KEEP_IMAGE,
The_ClassForm[Gbl.Prefs.Theme], The_ClassForm[Gbl.Prefs.Theme],
Txt_Current_image); Txt_Current_image);
Img_ShowImage (ImageName,"TEST_IMG_EDIT_ONE"); Img_ShowImage (Image,"TEST_IMG_EDIT_ONE");
} }
/***** Change/new image *****/ /***** Change/new image *****/
UniqueId++; UniqueId++;
if (ImageName[0]) // Image exists if (Image->Name[0]) // Image exists
{
/***** Change image *****/ /***** Change image *****/
fprintf (Gbl.F.Out,"<input type=\"radio\" id=\"chg_img_%u\" name=\"%s\"" fprintf (Gbl.F.Out,"<input type=\"radio\" id=\"chg_img_%u\" name=\"%s\""
" value=\"%u\">", " value=\"%u\">"
UniqueId,ParamRadio,Img_ACTION_CHANGE_IMAGE); // Replace existing image by new image "<label class=\"%s\">"
fprintf (Gbl.F.Out,"<label class=\"%s\">"
"%s: " "%s: "
"</label>", "</label>",
UniqueId,ParamAction,Img_ACTION_CHANGE_IMAGE, // Replace existing image by new image
The_ClassForm[Gbl.Prefs.Theme],Txt_Change_image); The_ClassForm[Gbl.Prefs.Theme],Txt_Change_image);
}
else // Image does not exist else // Image does not exist
{
/***** New image *****/ /***** New image *****/
fprintf (Gbl.F.Out,"<input type=\"radio\" id=\"chg_img_%u\" name=\"%s\"" fprintf (Gbl.F.Out,"<input type=\"radio\" id=\"chg_img_%u\" name=\"%s\""
" value=\"%u\">", " value=\"%u\">"
UniqueId,ParamRadio,Img_ACTION_NEW_IMAGE); // Upload new image "<label class=\"%s\">"
fprintf (Gbl.F.Out,"<label class=\"%s\">"
"%s: " "%s: "
"</label>", "</label>",
UniqueId,ParamAction,Img_ACTION_NEW_IMAGE, // Upload new image
The_ClassForm[Gbl.Prefs.Theme],Txt_New_image); The_ClassForm[Gbl.Prefs.Theme],Txt_New_image);
}
fprintf (Gbl.F.Out,"<input type=\"file\" name=\"%s\"" fprintf (Gbl.F.Out,"<input type=\"file\" name=\"%s\""
" size=\"40\" maxlength=\"100\" value=\"\"" " size=\"40\" maxlength=\"100\" value=\"\""
" onchange=\"document.getElementById('chg_img_%u').checked = true;\" />", " 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\">", fprintf (Gbl.F.Out,"<td class=\"LEFT_TOP COLOR%u\">",
Gbl.RowEvenOdd); Gbl.RowEvenOdd);
Tst_WriteQstStem (row[4],"TEST_EDI"); Tst_WriteQstStem (row[4],"TEST_EDI");
Gbl.Image.Status = Img_NAME_STORED_IN_DB;
if (row[5][0]) if (row[5][0])
{ {
Gbl.Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
Img_ShowImage (row[5],"TEST_IMG_EDIT_LIST"); 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_WriteQstFeedback (row[6],"TEST_EDI_LIGHT");
Tst_WriteAnswersOfAQstEdit (QstCod); Tst_WriteAnswersOfAQstEdit (QstCod);
@ -4243,7 +4241,7 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
unsigned NumTag; unsigned NumTag;
bool TagNotFound; bool TagNotFound;
bool OptionsDisabled; bool OptionsDisabled;
char ParamRadio[32]; char ParamAction[32];
char ParamFile[32]; char ParamFile[32];
/***** If no receiving the question, but editing a new or existing question /***** 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], The_ClassForm[Gbl.Prefs.Theme],
Txt_Stem, Txt_Stem,
Stem); Stem);
Tst_PutFormToEditQstImage (Gbl.Test.Image, Tst_PutFormToEditQstImage (&Gbl.Test.Image,
"ImgAct",Fil_NAME_OF_PARAM_FILENAME_ORG); "ImgAct","FileImg");
fprintf (Gbl.F.Out,"</td>" fprintf (Gbl.F.Out,"</td>"
"</tr>"); "</tr>");
@ -4558,9 +4556,9 @@ static void Tst_PutFormEditOneQst (char *Stem,char *Feedback)
/* Image */ /* Image */
fprintf (Gbl.F.Out,"<tr>" fprintf (Gbl.F.Out,"<tr>"
"<td colspan=\"2\" class=\"LEFT_TOP\">"); "<td colspan=\"2\" class=\"LEFT_TOP\">");
sprintf (ParamRadio,"ImgAct%u",NumOpt); sprintf (ParamAction,"ImgAct%u",NumOpt);
sprintf (ParamFile,"FileImg%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) // if (OptionsDisabled)
// fprintf (Gbl.F.Out," disabled=\"disabled\""); // fprintf (Gbl.F.Out," disabled=\"disabled\"");
fprintf (Gbl.F.Out,"</td>" fprintf (Gbl.F.Out,"</td>"
@ -4603,7 +4601,9 @@ void Tst_InitQst (void)
Gbl.Test.Stem.Length = 0; Gbl.Test.Stem.Length = 0;
Gbl.Test.Feedback.Text = NULL; Gbl.Test.Feedback.Text = NULL;
Gbl.Test.Feedback.Length = 0; 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.Shuffle = false;
Gbl.Test.AnswerType = Tst_ANS_UNIQUE_CHOICE; Gbl.Test.AnswerType = Tst_ANS_UNIQUE_CHOICE;
Gbl.Test.Answer.NumOptions = 0; 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].Correct = false;
Gbl.Test.Answer.Options[NumOpt].Text = NULL; Gbl.Test.Answer.Options[NumOpt].Text = NULL;
Gbl.Test.Answer.Options[NumOpt].Feedback = 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.Integer = 0;
Gbl.Test.Answer.FloatingPoint[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]) */ /* Get the image of the question from the database (row[3]) */
if (row[3][0]) if (row[3][0])
{ {
Gbl.Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
strncpy (Gbl.Test.Image,row[3],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64); strncpy (Gbl.Test.Image.Name,row[3],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
Gbl.Test.Image[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0'; Gbl.Test.Image.Name[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
} }
else 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]) */ /* Get the feedback of the question from the database (row[4]) */
Feedback[0] = '\0'; 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 ******/ /***** 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]; char Query[256];
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
/***** Get possible image associated with a test question from database *****/ /***** Build query depending on NumOpt *****/
sprintf (Query,"SELECT Image FROM tst_questions" if (NumOpt < Tst_MAX_OPTIONS_PER_QUESTION)
" WHERE QstCod='%ld' AND CrsCod='%ld'", // Get image associated to answer
Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod); sprintf (Query,"SELECT Image FROM tst_answers"
DB_QuerySELECT (Query,&mysql_res,"can not get a question"); " 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); 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 if (row[0][0]) // Image name stored in database
{ {
Gbl.Image.Status = Img_NAME_STORED_IN_DB; strncpy (ImageName,row[0],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64);
strncpy (Gbl.Test.Image,row[0],Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64); ImageName[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
Gbl.Test.Image[Cry_LENGTH_ENCRYPTED_STR_SHA256_BASE64] = '\0';
} }
else // No image in this question 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); DB_FreeMySQLResult (&mysql_res);
} }
@ -4828,17 +4840,17 @@ void Tst_ReceiveQst (void)
/***** Make sure that tags, text and answer are not empty *****/ /***** Make sure that tags, text and answer are not empty *****/
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions ()) 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 /* Remove possible file with the old image
(the new image file is already processed (the new image file is already processed
and moved to the definitive directory) */ and moved to the definitive directory) */
Tst_RemoveImageFilesFromQstsInCrs (Gbl.CurrentCrs.Crs.CrsCod,Gbl.Test.QstCod); Tst_RemoveImageFilesFromQstsInCrs (Gbl.CurrentCrs.Crs.CrsCod,Gbl.Test.QstCod);
if ((Gbl.Image.Action == Img_ACTION_NEW_IMAGE || // Upload new image if ((Gbl.Test.Image.Action == Img_ACTION_NEW_IMAGE || // Upload new image
Gbl.Image.Action == Img_ACTION_CHANGE_IMAGE) && // Replace existing image by new image Gbl.Test.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 Gbl.Test.Image.Status == Img_FILE_PROCESSED) // The new image received has been processed
/* Move processed image to definitive directory */ /* Move processed image to definitive directory */
Img_MoveImageToDefinitiveDirectory (); Img_MoveImageToDefinitiveDirectory (&Gbl.Test.Image);
/***** Insert or update question, tags and answer in the database *****/ /***** Insert or update question, tags and answer in the database *****/
Tst_InsertOrUpdateQstTagsAnsIntoDB (); Tst_InsertOrUpdateQstTagsAnsIntoDB ();
@ -4850,9 +4862,9 @@ void Tst_ReceiveQst (void)
{ {
/***** Whether an image has been received or not, /***** Whether an image has been received or not,
reset status and image *****/ reset status and image *****/
Gbl.Image.Action = Img_ACTION_NO_IMAGE; Gbl.Test.Image.Action = Img_ACTION_NO_IMAGE;
Gbl.Image.Status = Img_FILE_NONE; Gbl.Test.Image.Status = Img_FILE_NONE;
Gbl.Test.Image[0] = '\0'; Gbl.Test.Image.Name[0] = '\0';
/***** Put form to edit question again *****/ /***** Put form to edit question again *****/
Tst_PutFormEditOneQst (Stem,Feedback); 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]; char StrMultiAns[Tst_MAX_SIZE_ANSWERS_ONE_QST+1];
const char *Ptr; const char *Ptr;
unsigned NumCorrectAns; unsigned NumCorrectAns;
char ParamAction[32];
char ParamFile[32];
/***** Get question code *****/ /***** Get question code *****/
Tst_GetQstCod (); Tst_GetQstCod ();
@ -4914,9 +4928,10 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
/***** Get question stem *****/ /***** Get question stem *****/
Par_GetParToHTML ("Stem",Stem,Cns_MAX_BYTES_TEXT); Par_GetParToHTML ("Stem",Stem,Cns_MAX_BYTES_TEXT);
/***** Get image associated to stem *****/ /***** Get image associated to the stem *****/
Img_GetImageFromForm (Gbl.Test.Image,Tst_GetImageNameFromDB, Img_GetImageFromForm (Tst_MAX_OPTIONS_PER_QUESTION,&Gbl.Test.Image,
Fil_NAME_OF_PARAM_FILENAME_ORG, Tst_GetImageNameFromDB,
"ImgAct","FileImg",
Tst_PHOTO_SAVED_MAX_WIDTH, Tst_PHOTO_SAVED_MAX_WIDTH,
Tst_PHOTO_SAVED_MAX_HEIGHT, Tst_PHOTO_SAVED_MAX_HEIGHT,
Tst_PHOTO_SAVED_QUALITY); Tst_PHOTO_SAVED_QUALITY);
@ -4970,6 +4985,20 @@ static void Tst_GetQstFromForm (char *Stem,char *Feedback)
/* Get feedback */ /* Get feedback */
sprintf (FbStr,"FbStr%u",NumOpt); sprintf (FbStr,"FbStr%u",NumOpt);
Par_GetParToHTML (FbStr,Gbl.Test.Answer.Options[NumOpt].Feedback,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK); 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 */ /* Get the numbers of correct answers */
@ -5047,9 +5076,9 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void)
bool ThereIsEndOfAnswers; bool ThereIsEndOfAnswers;
unsigned i; unsigned i;
if ((Gbl.Image.Action == Img_ACTION_NEW_IMAGE || // Upload new image if ((Gbl.Test.Image.Action == Img_ACTION_NEW_IMAGE || // Upload new image
Gbl.Image.Action == Img_ACTION_CHANGE_IMAGE) && // Replace existing image by new image Gbl.Test.Image.Action == Img_ACTION_CHANGE_IMAGE) && // Replace existing image by new image
Gbl.Image.Status != Img_FILE_PROCESSED) Gbl.Test.Image.Status != Img_FILE_PROCESSED)
{ {
Lay_ShowAlert (Lay_WARNING,Txt_Error_receiving_or_processing_image); Lay_ShowAlert (Lay_WARNING,Txt_Error_receiving_or_processing_image);
return false; return false;
@ -5487,13 +5516,13 @@ static void Tst_InsertOrUpdateQstIntoDB (void)
Gbl.Test.Shuffle ? 'Y' : Gbl.Test.Shuffle ? 'Y' :
'N', 'N',
Gbl.Test.Stem.Text, Gbl.Test.Stem.Text,
Gbl.Test.Image, Gbl.Test.Image.Name,
Gbl.Test.Feedback.Text ? Gbl.Test.Feedback.Text : ""); Gbl.Test.Feedback.Text ? Gbl.Test.Feedback.Text : "");
Gbl.Test.QstCod = DB_QueryINSERTandReturnCode (Query,"can not create question"); Gbl.Test.QstCod = DB_QueryINSERTandReturnCode (Query,"can not create question");
/* Update image status */ /* Update image status */
if (Gbl.Test.Image[0]) if (Gbl.Test.Image.Name[0])
Gbl.Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
} }
else // It's an existing question else // It's an existing question
{ {
@ -5507,13 +5536,13 @@ static void Tst_InsertOrUpdateQstIntoDB (void)
Gbl.Test.Shuffle ? 'Y' : Gbl.Test.Shuffle ? 'Y' :
'N', 'N',
Gbl.Test.Stem.Text, Gbl.Test.Stem.Text,
Gbl.Test.Image, Gbl.Test.Image.Name,
Gbl.Test.Feedback.Text ? Gbl.Test.Feedback.Text : "", Gbl.Test.Feedback.Text ? Gbl.Test.Feedback.Text : "",
Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod); Gbl.Test.QstCod,Gbl.CurrentCrs.Crs.CrsCod);
/* Update image status */ /* Update image status */
if (Gbl.Test.Image[0]) if (Gbl.Test.Image.Name[0])
Gbl.Image.Status = Img_NAME_STORED_IN_DB; Gbl.Test.Image.Status = Img_NAME_STORED_IN_DB;
DB_QueryUPDATE (Query,"can not update question"); DB_QueryUPDATE (Query,"can not update question");
/* Remove answers and tags from this test question */ /* Remove answers and tags from this test question */