mirror of https://github.com/acanas/swad-core.git
1744 lines
59 KiB
C
1744 lines
59 KiB
C
// swad_exam_event.c: exam events (each ocurrence of an exam)
|
|
|
|
/*
|
|
SWAD (Shared Workspace At a Distance),
|
|
is a web platform developed at the University of Granada (Spain),
|
|
and used to support university teaching.
|
|
|
|
This file is part of SWAD core.
|
|
Copyright (C) 1999-2020 Antonio Cañas Vargas
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
/*****************************************************************************/
|
|
/********************************* Headers ***********************************/
|
|
/*****************************************************************************/
|
|
|
|
#define _GNU_SOURCE // For asprintf
|
|
#include <linux/limits.h> // For PATH_MAX
|
|
#include <stddef.h> // For NULL
|
|
#include <stdio.h> // For asprintf
|
|
#include <stdlib.h> // For calloc
|
|
#include <string.h> // For string functions
|
|
|
|
#include "swad_database.h"
|
|
#include "swad_date.h"
|
|
#include "swad_exam.h"
|
|
#include "swad_exam_event.h"
|
|
#include "swad_exam_print.h"
|
|
#include "swad_exam_result.h"
|
|
#include "swad_exam_set.h"
|
|
#include "swad_exam_type.h"
|
|
#include "swad_form.h"
|
|
#include "swad_global.h"
|
|
#include "swad_HTML.h"
|
|
#include "swad_role.h"
|
|
#include "swad_setting.h"
|
|
#include "swad_test.h"
|
|
|
|
/*****************************************************************************/
|
|
/************** External global variables from others modules ****************/
|
|
/*****************************************************************************/
|
|
|
|
extern struct Globals Gbl;
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private constants *****************************/
|
|
/*****************************************************************************/
|
|
|
|
#define ExaEvt_ICON_CLOSE "fas fa-times"
|
|
#define ExaEvt_ICON_PLAY "fas fa-play"
|
|
#define ExaEvt_ICON_PAUSE "fas fa-pause"
|
|
#define ExaEvt_ICON_PREVIOUS "fas fa-step-backward"
|
|
#define ExaEvt_ICON_NEXT "fas fa-step-forward"
|
|
#define ExaEvt_ICON_RESULTS "fas fa-chart-bar"
|
|
|
|
#define ExaEvt_COUNTDOWN_SECONDS_LARGE 60
|
|
#define ExaEvt_COUNTDOWN_SECONDS_MEDIUM 30
|
|
#define ExaEvt_COUNTDOWN_SECONDS_SMALL 10
|
|
|
|
/*****************************************************************************/
|
|
/******************************* Private types *******************************/
|
|
/*****************************************************************************/
|
|
|
|
typedef enum
|
|
{
|
|
ExaEvt_CHANGE_STATUS_BY_STUDENT,
|
|
ExaEvt_REFRESH_STATUS_BY_SERVER,
|
|
} ExaEvt_Update_t;
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private constants *****************************/
|
|
/*****************************************************************************/
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private variables *****************************/
|
|
/*****************************************************************************/
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private prototypes ****************************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_PutIconsInListOfEvents (void *Exams);
|
|
static void ExaEvt_PutIconToCreateNewEvent (struct Exa_Exams *Exams);
|
|
|
|
static void ExaEvt_ListOneOrMoreEvents (struct Exa_Exams *Exams,
|
|
const struct Exa_Exam *Exam,
|
|
long EvtCodToBeEdited,
|
|
unsigned NumEvents,
|
|
MYSQL_RES *mysql_res);
|
|
static void ExaEvt_ListOneOrMoreEventsHeading (bool ICanEditEvents);
|
|
static bool ExaEvt_CheckIfICanEditEvents (void);
|
|
static bool ExaEvt_CheckIfICanEditThisEvent (const struct ExaEvt_Event *Event);
|
|
static void ExaEvt_ListOneOrMoreEventsIcons (struct Exa_Exams *Exams,
|
|
const struct ExaEvt_Event *Event,
|
|
const char *Anchor);
|
|
static void ExaEvt_ListOneOrMoreEventsAuthor (const struct ExaEvt_Event *Event);
|
|
static void ExaEvt_ListOneOrMoreEventsTimes (const struct ExaEvt_Event *Event,unsigned UniqueId);
|
|
static void ExaEvt_ListOneOrMoreEventsTitleGrps (struct Exa_Exams *Exams,
|
|
const struct ExaEvt_Event *Event,
|
|
const char *Anchor);
|
|
static void ExaEvt_GetAndWriteNamesOfGrpsAssociatedToEvent (const struct ExaEvt_Event *Event);
|
|
static void ExaEvt_ListOneOrMoreEventsResult (struct Exa_Exams *Exams,
|
|
const struct ExaEvt_Event *Event);
|
|
static void ExaEvt_ListOneOrMoreEventsResultStd (struct Exa_Exams *Exams,
|
|
const struct ExaEvt_Event *Event);
|
|
static void ExaEvt_ListOneOrMoreEventsResultTch (struct Exa_Exams *Exams,
|
|
const struct ExaEvt_Event *Event);
|
|
|
|
static void ExaEvt_GetEventDataFromRow (MYSQL_RES *mysql_res,
|
|
struct ExaEvt_Event *Event);
|
|
|
|
static void ExaEvt_RemoveEventFromAllTables (long EvtCod);
|
|
static void ExaEvt_RemoveEventFromTable (long EvtCod,const char *TableName);
|
|
static void ExaEvt_RemoveEventsInExamFromTable (long ExaCod,const char *TableName);
|
|
static void ExaEvt_RemoveEventInCourseFromTable (long CrsCod,const char *TableName);
|
|
static void ExaEvt_RemoveUsrEvtResultsInCrs (long UsrCod,long CrsCod,const char *TableName);
|
|
|
|
static void ExaEvt_PutParamEvtCod (long EvtCod);
|
|
|
|
static void ExaEvt_PutFormEvent (const struct ExaEvt_Event *Event);
|
|
static void ExaEvt_ShowLstGrpsToCreateEvent (long EvtCod);
|
|
|
|
static void ExaEvt_CreateEvent (struct ExaEvt_Event *Event);
|
|
static void ExaEvt_UpdateEvent (struct ExaEvt_Event *Event);
|
|
|
|
static void ExaEvt_CreateGrps (long EvtCod);
|
|
static void ExaEvt_RemoveGroups (long EvtCod);
|
|
|
|
/*****************************************************************************/
|
|
/****************************** Reset exam event *****************************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_ResetEvent (struct ExaEvt_Event *Event)
|
|
{
|
|
Dat_StartEndTime_t StartEndTime;
|
|
|
|
/***** Initialize to empty match *****/
|
|
Event->EvtCod = -1L;
|
|
Event->ExaCod = -1L;
|
|
Event->UsrCod = -1L;
|
|
for (StartEndTime = (Dat_StartEndTime_t) 0;
|
|
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
|
|
StartEndTime++)
|
|
Event->TimeUTC[StartEndTime] = (time_t) 0;
|
|
Event->Title[0] = '\0';
|
|
Event->Hidden = false;
|
|
Event->Open = false;
|
|
Event->ShowUsrResults = false;
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/************************* List the events of an exam ************************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_ListEvents (struct Exa_Exams *Exams,
|
|
struct Exa_Exam *Exam,
|
|
struct ExaEvt_Event *Event,
|
|
bool PutFormEvent)
|
|
{
|
|
extern const char *Hlp_ASSESSMENT_Exams_events;
|
|
extern const char *Txt_Events;
|
|
char *SubQuery;
|
|
MYSQL_RES *mysql_res;
|
|
unsigned NumEvents;
|
|
long EvtCodToBeEdited;
|
|
bool PutFormNewEvent;
|
|
|
|
/***** Get data of events from database *****/
|
|
/* Fill subquery for exam */
|
|
if (Gbl.Crs.Grps.WhichGrps == Grp_MY_GROUPS)
|
|
{
|
|
if (asprintf (&SubQuery," AND"
|
|
"(EvtCod NOT IN"
|
|
" (SELECT EvtCod FROM exa_groups)"
|
|
" OR"
|
|
" EvtCod IN"
|
|
" (SELECT exa_groups.EvtCod"
|
|
" FROM exa_groups,crs_grp_usr"
|
|
" WHERE crs_grp_usr.UsrCod=%ld"
|
|
" AND exa_groups.GrpCod=crs_grp_usr.GrpCod))",
|
|
Gbl.Usrs.Me.UsrDat.UsrCod) < 0)
|
|
Lay_NotEnoughMemoryExit ();
|
|
}
|
|
else // Gbl.Crs.Grps.WhichGrps == Grp_ALL_GROUPS
|
|
if (asprintf (&SubQuery,"%s","") < 0)
|
|
Lay_NotEnoughMemoryExit ();
|
|
|
|
/* Make query */
|
|
NumEvents = (unsigned)
|
|
DB_QuerySELECT (&mysql_res,"can not get events",
|
|
"SELECT EvtCod," // row[0]
|
|
"ExaCod," // row[1]
|
|
"Hidden," // row[2]
|
|
"UsrCod," // row[3]
|
|
"UNIX_TIMESTAMP(StartTime)," // row[4]
|
|
"UNIX_TIMESTAMP(EndTime)," // row[5]
|
|
"NOW() BETWEEN StartTime AND EndTime," // row[6]
|
|
"Title," // row[7]
|
|
"ShowUsrResults" // row[8]
|
|
" FROM exa_events"
|
|
" WHERE ExaCod=%ld%s"
|
|
" ORDER BY EvtCod",
|
|
Exam->ExaCod,
|
|
SubQuery);
|
|
|
|
/* Free allocated memory for subquery */
|
|
free (SubQuery);
|
|
|
|
/***** Begin box *****/
|
|
Exams->ExaCod = Exam->ExaCod;
|
|
Box_BoxBegin ("100%",Txt_Events,
|
|
ExaEvt_PutIconsInListOfEvents,Exams,
|
|
Hlp_ASSESSMENT_Exams_events,Box_NOT_CLOSABLE);
|
|
|
|
/***** Select whether show only my groups or all groups *****/
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
{
|
|
case Rol_NET:
|
|
case Rol_TCH:
|
|
case Rol_SYS_ADM:
|
|
if (Gbl.Crs.Grps.NumGrps)
|
|
{
|
|
Set_StartSettingsHead ();
|
|
Grp_ShowFormToSelWhichGrps (ActSeeExa,
|
|
Exa_PutParams,Exams);
|
|
Set_EndSettingsHead ();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/***** Show the table with the events *****/
|
|
if (NumEvents)
|
|
{
|
|
EvtCodToBeEdited = PutFormEvent && Event->EvtCod > 0 ? Event->EvtCod :
|
|
-1L;
|
|
ExaEvt_ListOneOrMoreEvents (Exams,Exam,EvtCodToBeEdited,NumEvents,mysql_res);
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
/***** Put button to create a new exam event in this exam *****/
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
{
|
|
case Rol_NET:
|
|
case Rol_TCH:
|
|
case Rol_SYS_ADM:
|
|
PutFormNewEvent = PutFormEvent && Event->EvtCod <= 0;
|
|
if (PutFormNewEvent)
|
|
{
|
|
/* Reset event */
|
|
ExaEvt_ResetEvent (Event);
|
|
Event->ExaCod = Exam->ExaCod;
|
|
Event->TimeUTC[Dat_START_TIME] = Gbl.StartExecutionTimeUTC; // Now
|
|
Event->TimeUTC[Dat_END_TIME ] = Gbl.StartExecutionTimeUTC + (1 * 60 * 60); // Now + 1 hour
|
|
Str_Copy (Event->Title,Exam->Title,
|
|
ExaEvt_MAX_BYTES_TITLE);
|
|
|
|
/* Put form to create new event */
|
|
ExaEvt_PutFormEvent (Event); // Form to create event
|
|
}
|
|
else
|
|
ExaEvt_PutButtonNewEvent (Exams,Exam->ExaCod); // Button to create a new exam event
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/***** End box *****/
|
|
Box_BoxEnd ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************** Get exam event data using its code *********************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_GetDataOfEventByCod (struct ExaEvt_Event *Event)
|
|
{
|
|
MYSQL_RES *mysql_res;
|
|
unsigned long NumRows;
|
|
|
|
/***** Trivial check *****/
|
|
if (Event->EvtCod <= 0)
|
|
{
|
|
/* Initialize to empty exam event */
|
|
ExaEvt_ResetEvent (Event);
|
|
return;
|
|
}
|
|
|
|
/***** Get exam data event from database *****/
|
|
NumRows = (unsigned)
|
|
DB_QuerySELECT (&mysql_res,"can not get events",
|
|
"SELECT EvtCod," // row[0]
|
|
"ExaCod," // row[1]
|
|
"Hidden," // row[2]
|
|
"UsrCod," // row[3]
|
|
"UNIX_TIMESTAMP(StartTime)," // row[4]
|
|
"UNIX_TIMESTAMP(EndTime)," // row[5]
|
|
"NOW() BETWEEN StartTime AND EndTime," // row[6]
|
|
"Title," // row[7]
|
|
"ShowUsrResults" // row[8]
|
|
" FROM exa_events"
|
|
" WHERE EvtCod=%ld"
|
|
" AND ExaCod IN" // Extra check
|
|
" (SELECT ExaCod FROM exa_exams"
|
|
" WHERE CrsCod='%ld')",
|
|
Event->EvtCod,
|
|
Gbl.Hierarchy.Crs.CrsCod);
|
|
if (NumRows) // Event found...
|
|
/* Get exam event data from row */
|
|
ExaEvt_GetEventDataFromRow (mysql_res,Event);
|
|
else
|
|
/* Initialize to empty exam event */
|
|
ExaEvt_ResetEvent (Event);
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************** Check if exam event is visible and open *******************/
|
|
/*****************************************************************************/
|
|
|
|
bool ExaEvt_CheckIfEventIsVisibleAndOpen (long EvtCod)
|
|
{
|
|
/***** Trivial check *****/
|
|
if (EvtCod < 0) // A non-existing event...
|
|
return false; // ...is not visible or open
|
|
|
|
/***** Check if exam event is visible and open from database *****/
|
|
return (DB_QueryCOUNT ("can not check if event is visible and open",
|
|
"SELECT COUNT(*) FROM exa_events"
|
|
" WHERE EvtCod=%ld"
|
|
" AND Hidden='N'" // Visible
|
|
" AND NOW() BETWEEN StartTime AND EndTime", // Open
|
|
EvtCod) != 0);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************** Put icons in list of events of an exam *******************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_PutIconsInListOfEvents (void *Exams)
|
|
{
|
|
bool ICanEditEvents;
|
|
|
|
if (Exams)
|
|
{
|
|
/***** Put icon to create a new exam event in current exam *****/
|
|
ICanEditEvents = ExaEvt_CheckIfICanEditEvents ();
|
|
if (ICanEditEvents)
|
|
ExaEvt_PutIconToCreateNewEvent ((struct Exa_Exams *) Exams);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************* Put icon to create a new exam event *********************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_PutIconToCreateNewEvent (struct Exa_Exams *Exams)
|
|
{
|
|
extern const char *Txt_New_event;
|
|
|
|
/***** Put form to create a new exam event *****/
|
|
Ico_PutContextualIconToAdd (ActReqNewExaEvt,ExaEvt_NEW_EVENT_SECTION_ID,
|
|
Exa_PutParams,Exams,
|
|
Txt_New_event);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********************** List exam events for edition ************************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_ListOneOrMoreEvents (struct Exa_Exams *Exams,
|
|
const struct Exa_Exam *Exam,
|
|
long EvtCodToBeEdited,
|
|
unsigned NumEvents,
|
|
MYSQL_RES *mysql_res)
|
|
{
|
|
unsigned NumEvent;
|
|
unsigned UniqueId;
|
|
char *Anchor;
|
|
struct ExaEvt_Event Event;
|
|
bool ICanEditEvents = ExaEvt_CheckIfICanEditEvents ();
|
|
|
|
/***** Trivial check *****/
|
|
if (!NumEvents)
|
|
return;
|
|
|
|
/***** Reset event *****/
|
|
ExaEvt_ResetEvent (&Event);
|
|
|
|
/***** Write the heading *****/
|
|
HTM_TABLE_BeginWidePadding (2);
|
|
ExaEvt_ListOneOrMoreEventsHeading (ICanEditEvents);
|
|
|
|
/***** Write rows *****/
|
|
for (NumEvent = 0, UniqueId = 1;
|
|
NumEvent < NumEvents;
|
|
NumEvent++, UniqueId++)
|
|
{
|
|
Gbl.RowEvenOdd = NumEvent % 2;
|
|
|
|
/***** Get exam event data from row *****/
|
|
ExaEvt_GetEventDataFromRow (mysql_res,&Event);
|
|
|
|
if (ExaEvt_CheckIfICanListThisEventBasedOnGrps (&Event))
|
|
{
|
|
/***** Build anchor string *****/
|
|
if (asprintf (&Anchor,"evt_%ld_%ld",Exam->ExaCod,Event.EvtCod) < 0)
|
|
Lay_NotEnoughMemoryExit ();
|
|
|
|
/***** Begin row for this exam event ****/
|
|
HTM_TR_Begin (NULL);
|
|
|
|
/* Icons */
|
|
if (ICanEditEvents)
|
|
if (ExaEvt_CheckIfICanEditThisEvent (&Event))
|
|
ExaEvt_ListOneOrMoreEventsIcons (Exams,&Event,Anchor);
|
|
|
|
/* Event participant */
|
|
ExaEvt_ListOneOrMoreEventsAuthor (&Event);
|
|
|
|
/* Start/end date/time */
|
|
ExaEvt_ListOneOrMoreEventsTimes (&Event,UniqueId);
|
|
|
|
/* Title and groups */
|
|
ExaEvt_ListOneOrMoreEventsTitleGrps (Exams,&Event,Anchor);
|
|
|
|
/* Event result visible? */
|
|
ExaEvt_ListOneOrMoreEventsResult (Exams,&Event);
|
|
|
|
/***** End row for this event ****/
|
|
HTM_TR_End ();
|
|
|
|
/***** For to edit this event ****/
|
|
if (Event.EvtCod == EvtCodToBeEdited)
|
|
{
|
|
HTM_TR_Begin (NULL);
|
|
HTM_TD_Begin ("colspan=\"6\" class=\"CT COLOR%u\"",Gbl.RowEvenOdd);
|
|
ExaEvt_PutFormEvent (&Event); // Form to edit existing event
|
|
HTM_TD_End ();
|
|
HTM_TR_End ();
|
|
}
|
|
|
|
/***** Free anchor string *****/
|
|
free (Anchor);
|
|
}
|
|
}
|
|
|
|
/***** End table *****/
|
|
HTM_TABLE_End ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************** Put a column for exam event start and end times **************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_ListOneOrMoreEventsHeading (bool ICanEditEvents)
|
|
{
|
|
extern const char *Txt_ROLES_SINGUL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
|
|
extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME];
|
|
extern const char *Txt_Event;
|
|
extern const char *Txt_Results;
|
|
|
|
/***** Start row *****/
|
|
HTM_TR_Begin (NULL);
|
|
|
|
/***** Column for icons *****/
|
|
if (ICanEditEvents)
|
|
HTM_TH_Empty (1);
|
|
|
|
/***** The rest of columns *****/
|
|
HTM_TH (1,1,"LT",Txt_ROLES_SINGUL_Abc[Rol_TCH][Usr_SEX_UNKNOWN]);
|
|
HTM_TH (1,1,"LT",Txt_START_END_TIME[Exa_ORDER_BY_START_DATE]);
|
|
HTM_TH (1,1,"LT",Txt_START_END_TIME[Exa_ORDER_BY_END_DATE ]);
|
|
HTM_TH (1,1,"LT",Txt_Event);
|
|
HTM_TH (1,1,"CT",Txt_Results);
|
|
|
|
/***** End row *****/
|
|
HTM_TR_End ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********************** Check if I can edit events **************************/
|
|
/*****************************************************************************/
|
|
|
|
static bool ExaEvt_CheckIfICanEditEvents (void)
|
|
{
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
{
|
|
case Rol_NET:
|
|
case Rol_TCH:
|
|
case Rol_SYS_ADM:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************** Check if I can edit (remove/resume) an exam event ************/
|
|
/*****************************************************************************/
|
|
|
|
static bool ExaEvt_CheckIfICanEditThisEvent (const struct ExaEvt_Event *Event)
|
|
{
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
{
|
|
case Rol_NET:
|
|
return (Event->UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod); // Only if I am the creator
|
|
case Rol_TCH:
|
|
case Rol_SYS_ADM:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************* Put a column for icons ****************************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_ListOneOrMoreEventsIcons (struct Exa_Exams *Exams,
|
|
const struct ExaEvt_Event *Event,
|
|
const char *Anchor)
|
|
{
|
|
/***** Begin cell *****/
|
|
HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd);
|
|
|
|
Exams->ExaCod = Event->ExaCod;
|
|
Exams->EvtCod = Event->EvtCod;
|
|
|
|
/***** Icon to remove the exam event *****/
|
|
Frm_StartForm (ActReqRemExaEvt);
|
|
ExaEvt_PutParamsEdit (Exams);
|
|
Ico_PutIconRemove ();
|
|
Frm_EndForm ();
|
|
|
|
/***** Icon to hide/unhide the exam event *****/
|
|
if (Event->Hidden)
|
|
Ico_PutContextualIconToUnhide (ActShoExaEvt,Anchor,
|
|
ExaEvt_PutParamsEdit,Exams);
|
|
else
|
|
Ico_PutContextualIconToHide (ActHidExaEvt,Anchor,
|
|
ExaEvt_PutParamsEdit,Exams);
|
|
|
|
/***** Icon to edit the exam event *****/
|
|
Ico_PutContextualIconToEdit (ActEdiOneExaEvt,Anchor,
|
|
ExaEvt_PutParamsEdit,Exams);
|
|
|
|
/***** End cell *****/
|
|
HTM_TD_End ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********** Put a column for teacher who created the exam event *************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_ListOneOrMoreEventsAuthor (const struct ExaEvt_Event *Event)
|
|
{
|
|
/***** Event author (teacher) *****/
|
|
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
|
|
Usr_WriteAuthor1Line (Event->UsrCod,Event->Hidden);
|
|
HTM_TD_End ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*************** Put a column for exam event start and end times *************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_ListOneOrMoreEventsTimes (const struct ExaEvt_Event *Event,unsigned UniqueId)
|
|
{
|
|
Dat_StartEndTime_t StartEndTime;
|
|
const char *Color;
|
|
char *Id;
|
|
|
|
for (StartEndTime = (Dat_StartEndTime_t) 0;
|
|
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
|
|
StartEndTime++)
|
|
{
|
|
Color = Event->Open ? (Event->Hidden ? "DATE_GREEN_LIGHT":
|
|
"DATE_GREEN") :
|
|
(Event->Hidden ? "DATE_RED_LIGHT":
|
|
"DATE_RED");
|
|
|
|
if (asprintf (&Id,"exa_time_%u_%u",(unsigned) StartEndTime,UniqueId) < 0)
|
|
Lay_NotEnoughMemoryExit ();
|
|
HTM_TD_Begin ("id=\"%s\" class=\"%s LT COLOR%u\"",
|
|
Id,Color,Gbl.RowEvenOdd);
|
|
Dat_WriteLocalDateHMSFromUTC (Id,Event->TimeUTC[StartEndTime],
|
|
Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK,
|
|
true,true,true,0x6);
|
|
HTM_TD_End ();
|
|
free (Id);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*************** Put a column for exam event title and grous *****************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_ListOneOrMoreEventsTitleGrps (struct Exa_Exams *Exams,
|
|
const struct ExaEvt_Event *Event,
|
|
const char *Anchor)
|
|
{
|
|
extern const char *Txt_Play;
|
|
extern const char *Txt_Resume;
|
|
|
|
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
|
|
|
|
/***** Event title *****/
|
|
HTM_ARTICLE_Begin (Anchor);
|
|
if (ExaEvt_CheckIfICanAnswerThisEvent (Event))
|
|
{
|
|
Frm_StartForm (ActSeeExaPrn);
|
|
Exa_PutParams (Exams);
|
|
ExaEvt_PutParamEvtCod (Event->EvtCod);
|
|
HTM_BUTTON_SUBMIT_Begin (Gbl.Usrs.Me.Role.Logged == Rol_STD ? Txt_Play :
|
|
Txt_Resume,
|
|
Event->Hidden ? "BT_LINK LT ASG_TITLE_LIGHT":
|
|
"BT_LINK LT ASG_TITLE",
|
|
NULL);
|
|
HTM_Txt (Event->Title);
|
|
HTM_BUTTON_End ();
|
|
Frm_EndForm ();
|
|
}
|
|
else
|
|
{
|
|
HTM_SPAN_Begin ("class=\"%s\"",Event->Hidden ? "LT ASG_TITLE_LIGHT":
|
|
"LT ASG_TITLE");
|
|
HTM_Txt (Event->Title);
|
|
HTM_SPAN_End ();
|
|
}
|
|
HTM_ARTICLE_End ();
|
|
|
|
/***** Groups whose students can answer this exam event *****/
|
|
if (Gbl.Crs.Grps.NumGrps)
|
|
ExaEvt_GetAndWriteNamesOfGrpsAssociatedToEvent (Event);
|
|
|
|
HTM_TD_End ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********** Get and write the names of the groups of an exam event ***********/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_GetAndWriteNamesOfGrpsAssociatedToEvent (const struct ExaEvt_Event *Event)
|
|
{
|
|
extern const char *Txt_Group;
|
|
extern const char *Txt_Groups;
|
|
extern const char *Txt_and;
|
|
extern const char *Txt_The_whole_course;
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned long NumRow;
|
|
unsigned long NumRows;
|
|
|
|
/***** Get groups associated to an exam event from database *****/
|
|
NumRows = DB_QuerySELECT (&mysql_res,"can not get groups of an exam event",
|
|
"SELECT crs_grp_types.GrpTypName,crs_grp.GrpName"
|
|
" FROM exa_groups,crs_grp,crs_grp_types"
|
|
" WHERE exa_groups.EvtCod=%ld"
|
|
" AND exa_groups.GrpCod=crs_grp.GrpCod"
|
|
" AND crs_grp.GrpTypCod=crs_grp_types.GrpTypCod"
|
|
" ORDER BY crs_grp_types.GrpTypName,crs_grp.GrpName",
|
|
Event->EvtCod);
|
|
|
|
/***** Write heading *****/
|
|
HTM_DIV_Begin ("class=\"%s\"",Event->Hidden ? "ASG_GRP_LIGHT":
|
|
"ASG_GRP");
|
|
HTM_TxtColonNBSP (NumRows == 1 ? Txt_Group :
|
|
Txt_Groups);
|
|
|
|
/***** Write groups *****/
|
|
if (NumRows) // Groups found...
|
|
{
|
|
/* Get and write the group types and names */
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next group */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Write group type name and group name */
|
|
HTM_TxtF ("%s %s",row[0],row[1]);
|
|
|
|
if (NumRows >= 2)
|
|
{
|
|
if (NumRow == NumRows-2)
|
|
HTM_TxtF (" %s ",Txt_and);
|
|
if (NumRows >= 3)
|
|
if (NumRow < NumRows-2)
|
|
HTM_Txt (", ");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
HTM_TxtF ("%s %s",Txt_The_whole_course,Gbl.Hierarchy.Crs.ShrtName);
|
|
|
|
HTM_DIV_End ();
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************* Put a column for visibility of exam event result **************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_ListOneOrMoreEventsResult (struct Exa_Exams *Exams,
|
|
const struct ExaEvt_Event *Event)
|
|
{
|
|
HTM_TD_Begin ("class=\"DAT CT COLOR%u\"",Gbl.RowEvenOdd);
|
|
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
{
|
|
case Rol_STD:
|
|
ExaEvt_ListOneOrMoreEventsResultStd (Exams,Event);
|
|
break;
|
|
case Rol_NET:
|
|
case Rol_TCH:
|
|
case Rol_SYS_ADM:
|
|
ExaEvt_ListOneOrMoreEventsResultTch (Exams,Event);
|
|
break;
|
|
default:
|
|
Rol_WrongRoleExit ();
|
|
break;
|
|
}
|
|
|
|
HTM_TD_End ();
|
|
}
|
|
|
|
static void ExaEvt_ListOneOrMoreEventsResultStd (struct Exa_Exams *Exams,
|
|
const struct ExaEvt_Event *Event)
|
|
{
|
|
extern const char *Txt_Results;
|
|
|
|
/***** Is exam event result visible or hidden? *****/
|
|
if (Event->ShowUsrResults)
|
|
{
|
|
/* Result is visible by me */
|
|
Exams->ExaCod = Event->ExaCod;
|
|
Exams->EvtCod = Event->EvtCod;
|
|
Lay_PutContextualLinkOnlyIcon (ActSeeMyExaEvtResEvt,ExaRes_RESULTS_BOX_ID,
|
|
ExaEvt_PutParamsEdit,Exams,
|
|
"trophy.svg",
|
|
Txt_Results);
|
|
}
|
|
else
|
|
/* Result is forbidden to me */
|
|
Ico_PutIconNotVisible ();
|
|
}
|
|
|
|
static void ExaEvt_ListOneOrMoreEventsResultTch (struct Exa_Exams *Exams,
|
|
const struct ExaEvt_Event *Event)
|
|
{
|
|
extern const char *Txt_Visible_results;
|
|
extern const char *Txt_Hidden_results;
|
|
extern const char *Txt_Results;
|
|
|
|
/***** Can I edit exam event vivibility? *****/
|
|
if (ExaEvt_CheckIfICanEditThisEvent (Event))
|
|
{
|
|
Exams->ExaCod = Event->ExaCod;
|
|
Exams->EvtCod = Event->EvtCod;
|
|
|
|
/* Show exam event results */
|
|
Lay_PutContextualLinkOnlyIcon (ActSeeAllExaEvtResEvt,ExaRes_RESULTS_BOX_ID,
|
|
ExaEvt_PutParamsEdit,Exams,
|
|
"trophy.svg",
|
|
Txt_Results);
|
|
|
|
/* I can edit visibility */
|
|
Lay_PutContextualLinkOnlyIcon (ActChgVisResExaEvtUsr,NULL,
|
|
ExaEvt_PutParamsEdit,Exams,
|
|
Event->ShowUsrResults ? "eye-green.svg" :
|
|
"eye-slash-red.svg",
|
|
Event->ShowUsrResults ? Txt_Visible_results :
|
|
Txt_Hidden_results);
|
|
}
|
|
else
|
|
/* I can not edit visibility */
|
|
Ico_PutIconOff (Event->ShowUsrResults ? "eye-green.svg" :
|
|
"eye-slash-red.svg",
|
|
Event->ShowUsrResults ? Txt_Visible_results :
|
|
Txt_Hidden_results);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************** Toggle visibility of exam event results ******************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_ToggleVisibilResultsEvtUsr (void)
|
|
{
|
|
struct Exa_Exams Exams;
|
|
struct Exa_Exam Exam;
|
|
struct ExaEvt_Event Event;
|
|
|
|
/***** Reset exams context *****/
|
|
Exa_ResetExams (&Exams);
|
|
Exa_ResetExam (&Exam);
|
|
ExaEvt_ResetEvent (&Event);
|
|
|
|
/***** Get and check parameters *****/
|
|
ExaEvt_GetAndCheckParameters (&Exams,&Exam,&Event);
|
|
|
|
/***** Check if I have permission to change visibility *****/
|
|
if (!ExaEvt_CheckIfICanEditThisEvent (&Event))
|
|
Lay_NoPermissionExit ();
|
|
|
|
/***** Toggle visibility of exam event results *****/
|
|
Event.ShowUsrResults = !Event.ShowUsrResults;
|
|
DB_QueryUPDATE ("can not toggle visibility of exam event results",
|
|
"UPDATE exa_events"
|
|
" SET ShowUsrResults='%c'"
|
|
" WHERE EvtCod=%ld",
|
|
Event.ShowUsrResults ? 'Y' :
|
|
'N',
|
|
Event.EvtCod);
|
|
|
|
/***** Show current exam *****/
|
|
Exa_ShowOnlyOneExam (&Exams,&Exam,&Event,
|
|
false); // Do not put form for event
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************** Get exam data from a database row **********************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_GetEventDataFromRow (MYSQL_RES *mysql_res,
|
|
struct ExaEvt_Event *Event)
|
|
{
|
|
MYSQL_ROW row;
|
|
Dat_StartEndTime_t StartEndTime;
|
|
|
|
/***** Get exam event data *****/
|
|
row = mysql_fetch_row (mysql_res);
|
|
/*
|
|
row[0] EvtCod
|
|
row[1] ExaCod
|
|
row[2] Hidden
|
|
row[3] UsrCod
|
|
row[4] UNIX_TIMESTAMP(StartTime)
|
|
row[5] UNIX_TIMESTAMP(EndTime)
|
|
row[6] Open = NOW() BETWEEN StartTime AND EndTime
|
|
row[7] Title
|
|
row[8] ShowUsrResults
|
|
*/
|
|
/***** Get event data *****/
|
|
/* Code of the event (row[0]) */
|
|
if ((Event->EvtCod = Str_ConvertStrCodToLongCod (row[0])) <= 0)
|
|
Lay_ShowErrorAndExit ("Wrong code of exam event.");
|
|
|
|
/* Code of the exam (row[1]) */
|
|
if ((Event->ExaCod = Str_ConvertStrCodToLongCod (row[1])) <= 0)
|
|
Lay_ShowErrorAndExit ("Wrong code of exam.");
|
|
|
|
/* Get whether the event is hidden (row[2]) */
|
|
Event->Hidden = (row[2][0] == 'Y');
|
|
|
|
/* Get event teacher (row[3]) */
|
|
Event->UsrCod = Str_ConvertStrCodToLongCod (row[3]);
|
|
|
|
/* Get start/end times (row[4], row[5] hold start/end UTC times) */
|
|
for (StartEndTime = (Dat_StartEndTime_t) 0;
|
|
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
|
|
StartEndTime++)
|
|
Event->TimeUTC[StartEndTime] = Dat_GetUNIXTimeFromStr (row[4 + StartEndTime]);
|
|
|
|
/* Get whether the event is open or closed (row(6)) */
|
|
Event->Open = (row[6][0] == '1');
|
|
|
|
/* Get the title of the event (row[7]) */
|
|
if (row[7])
|
|
Str_Copy (Event->Title,row[7],
|
|
ExaEvt_MAX_BYTES_TITLE);
|
|
else
|
|
Event->Title[0] = '\0';
|
|
|
|
/* Get whether to show user results or not (row(8)) */
|
|
Event->ShowUsrResults = (row[8][0] == 'Y');
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********** Request the removal of an exam event (exam instance) ************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_RequestRemoveEvent (void)
|
|
{
|
|
extern const char *Txt_Do_you_really_want_to_remove_the_event_X;
|
|
extern const char *Txt_Remove_event;
|
|
struct Exa_Exams Exams;
|
|
struct Exa_Exam Exam;
|
|
struct ExaEvt_Event Event;
|
|
|
|
/***** Reset exams context *****/
|
|
Exa_ResetExams (&Exams);
|
|
Exa_ResetExam (&Exam);
|
|
ExaEvt_ResetEvent (&Event);
|
|
|
|
/***** Get and check parameters *****/
|
|
ExaEvt_GetAndCheckParameters (&Exams,&Exam,&Event);
|
|
|
|
/***** Show question and button to remove question *****/
|
|
Exams.ExaCod = Event.ExaCod;
|
|
Exams.EvtCod = Event.EvtCod;
|
|
Ale_ShowAlertAndButton (ActRemExaEvt,NULL,NULL,
|
|
ExaEvt_PutParamsEdit,&Exams,
|
|
Btn_REMOVE_BUTTON,Txt_Remove_event,
|
|
Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_event_X,
|
|
Event.Title);
|
|
|
|
/***** Show current exam *****/
|
|
Exa_ShowOnlyOneExam (&Exams,&Exam,&Event,
|
|
false); // Do not put form for event
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************* Remove an exam event (exam instance) ********************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_RemoveEvent (void)
|
|
{
|
|
extern const char *Txt_Event_X_removed;
|
|
struct Exa_Exams Exams;
|
|
struct Exa_Exam Exam;
|
|
struct ExaEvt_Event Event;
|
|
|
|
/***** Reset exams context *****/
|
|
Exa_ResetExams (&Exams);
|
|
Exa_ResetExam (&Exam);
|
|
ExaEvt_ResetEvent (&Event);
|
|
|
|
/***** Get and check parameters *****/
|
|
ExaEvt_GetAndCheckParameters (&Exams,&Exam,&Event);
|
|
|
|
/***** Check if I can remove this exam event *****/
|
|
if (!ExaEvt_CheckIfICanEditThisEvent (&Event))
|
|
Lay_NoPermissionExit ();
|
|
|
|
/***** Remove the exam event from all database tables *****/
|
|
ExaEvt_RemoveEventFromAllTables (Event.EvtCod);
|
|
|
|
/***** Write message *****/
|
|
Ale_ShowAlert (Ale_SUCCESS,Txt_Event_X_removed,
|
|
Event.Title);
|
|
|
|
/***** Get exam data again to update it after changes in event *****/
|
|
Exa_GetDataOfExamByCod (&Exam);
|
|
|
|
/***** Show current exam *****/
|
|
Exa_ShowOnlyOneExam (&Exams,&Exam,&Event,
|
|
false); // Do not put form for event
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************** Remove exam event from all tables **********************/
|
|
/*****************************************************************************/
|
|
/*
|
|
mysql> SELECT table_name FROM information_schema.tables WHERE table_name LIKE 'exa%';
|
|
*/
|
|
static void ExaEvt_RemoveEventFromAllTables (long EvtCod)
|
|
{
|
|
/***** Remove exam event from secondary tables *****/
|
|
ExaEvt_RemoveEventFromTable (EvtCod,"exa_groups");
|
|
|
|
/***** Remove exam event from main table *****/
|
|
DB_QueryDELETE ("can not remove exam event",
|
|
"DELETE FROM exa_events WHERE EvtCod=%ld",
|
|
EvtCod);
|
|
}
|
|
|
|
static void ExaEvt_RemoveEventFromTable (long EvtCod,const char *TableName)
|
|
{
|
|
/***** Remove exam event from secondary table *****/
|
|
DB_QueryDELETE ("can not remove exam event from table",
|
|
"DELETE FROM %s WHERE EvtCod=%ld",
|
|
TableName,
|
|
EvtCod);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************** Remove exam event in exam from all tables ****************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_RemoveEventsInExamFromAllTables (long ExaCod)
|
|
{
|
|
/***** Remove events from secondary tables *****/
|
|
ExaEvt_RemoveEventsInExamFromTable (ExaCod,"exa_groups");
|
|
|
|
/***** Remove events from main table *****/
|
|
DB_QueryDELETE ("can not remove events of an exam",
|
|
"DELETE FROM exa_events WHERE ExaCod=%ld",
|
|
ExaCod);
|
|
}
|
|
|
|
static void ExaEvt_RemoveEventsInExamFromTable (long ExaCod,const char *TableName)
|
|
{
|
|
/***** Remove events in exam from secondary table *****/
|
|
DB_QueryDELETE ("can not remove events of an exam from table",
|
|
"DELETE FROM %s"
|
|
" USING exa_events,%s"
|
|
" WHERE exa_events.ExaCod=%ld"
|
|
" AND exa_events.EvtCod=%s.EvtCod",
|
|
TableName,
|
|
TableName,
|
|
ExaCod,
|
|
TableName);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************** Remove exam event in course from all tables ***************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_RemoveEventInCourseFromAllTables (long CrsCod)
|
|
{
|
|
/***** Remove events from secondary tables *****/
|
|
ExaEvt_RemoveEventInCourseFromTable (CrsCod,"exa_groups");
|
|
|
|
/***** Remove events from main table *****/
|
|
DB_QueryDELETE ("can not remove events of a course",
|
|
"DELETE FROM exa_events"
|
|
" USING exa_exams,exa_events"
|
|
" WHERE exa_exams.CrsCod=%ld"
|
|
" AND exa_exams.ExaCod=exa_events.ExaCod",
|
|
CrsCod);
|
|
}
|
|
|
|
static void ExaEvt_RemoveEventInCourseFromTable (long CrsCod,const char *TableName)
|
|
{
|
|
/***** Remove events in course from secondary table *****/
|
|
DB_QueryDELETE ("can not remove events of a course from table",
|
|
"DELETE FROM %s"
|
|
" USING exa_exams,exa_events,%s"
|
|
" WHERE exa_exams.CrsCod=%ld"
|
|
" AND exa_exams.ExaCod=exa_events.ExaCod"
|
|
" AND exa_events.EvtCod=%s.EvtCod",
|
|
TableName,
|
|
TableName,
|
|
CrsCod,
|
|
TableName);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************** Remove user from secondary exam event tables *****************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_RemoveUsrFromEventTablesInCrs (long UsrCod,long CrsCod)
|
|
{
|
|
/***** Remove student from secondary tables *****/
|
|
ExaEvt_RemoveUsrEvtResultsInCrs (UsrCod,CrsCod,"exa_prints");
|
|
}
|
|
|
|
static void ExaEvt_RemoveUsrEvtResultsInCrs (long UsrCod,long CrsCod,const char *TableName)
|
|
{
|
|
/***** Remove events in course from secondary table *****/
|
|
DB_QueryDELETE ("can not remove events of a user from table",
|
|
"DELETE FROM %s"
|
|
" USING exa_exams,exa_events,%s"
|
|
" WHERE exa_exams.CrsCod=%ld"
|
|
" AND exa_exams.ExaCod=exa_events.ExaCod"
|
|
" AND exa_events.EvtCod=%s.EvtCod"
|
|
" AND %s.UsrCod=%ld",
|
|
TableName,
|
|
TableName,
|
|
CrsCod,
|
|
TableName,
|
|
TableName,
|
|
UsrCod);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************************** Hide an event ******************************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_HideEvent (void)
|
|
{
|
|
struct Exa_Exams Exams;
|
|
struct Exa_Exam Exam;
|
|
struct ExaEvt_Event Event;
|
|
|
|
/***** Reset exams context *****/
|
|
Exa_ResetExams (&Exams);
|
|
Exa_ResetExam (&Exam);
|
|
ExaEvt_ResetEvent (&Event);
|
|
|
|
/***** Get and check parameters *****/
|
|
ExaEvt_GetAndCheckParameters (&Exams,&Exam,&Event);
|
|
|
|
/***** Check if I can remove this exam event *****/
|
|
if (!ExaEvt_CheckIfICanEditThisEvent (&Event))
|
|
Lay_NoPermissionExit ();
|
|
|
|
/***** Hide event *****/
|
|
DB_QueryUPDATE ("can not hide exam event",
|
|
"UPDATE exa_events SET Hidden='Y'"
|
|
" WHERE EvtCod=%ld"
|
|
" AND ExaCod=%ld", // Extra check
|
|
Event.EvtCod,Event.ExaCod);
|
|
|
|
/***** Show current exam *****/
|
|
Exa_ShowOnlyOneExam (&Exams,&Exam,&Event,
|
|
false); // Do not put form for event
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************************** Unhide an event ******************************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_UnhideEvent (void)
|
|
{
|
|
struct Exa_Exams Exams;
|
|
struct Exa_Exam Exam;
|
|
struct ExaEvt_Event Event;
|
|
|
|
/***** Reset exams context *****/
|
|
Exa_ResetExams (&Exams);
|
|
Exa_ResetExam (&Exam);
|
|
ExaEvt_ResetEvent (&Event);
|
|
|
|
/***** Get and check parameters *****/
|
|
ExaEvt_GetAndCheckParameters (&Exams,&Exam,&Event);
|
|
|
|
/***** Check if I can remove this exam event *****/
|
|
if (!ExaEvt_CheckIfICanEditThisEvent (&Event))
|
|
Lay_NoPermissionExit ();
|
|
|
|
/***** Unhide event *****/
|
|
DB_QueryUPDATE ("can not unhide exam event",
|
|
"UPDATE exa_events SET Hidden='N'"
|
|
" WHERE EvtCod=%ld"
|
|
" AND ExaCod=%ld", // Extra check
|
|
Event.EvtCod,Event.ExaCod);
|
|
|
|
/***** Show current exam *****/
|
|
Exa_ShowOnlyOneExam (&Exams,&Exam,&Event,
|
|
false); // Do not put form for event
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************** Params used to edit an exam event **********************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_PutParamsEdit (void *Exams)
|
|
{
|
|
if (Exams)
|
|
{
|
|
Exa_PutParams (Exams);
|
|
ExaEvt_PutParamEvtCod (((struct Exa_Exams *) Exams)->EvtCod);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************** Write parameter with code of exam event *******************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_PutParamEvtCod (long EvtCod)
|
|
{
|
|
Par_PutHiddenParamLong (NULL,"EvtCod",EvtCod);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************** Get and check parameters *************************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_GetAndCheckParameters (struct Exa_Exams *Exams,
|
|
struct Exa_Exam *Exam,
|
|
struct ExaEvt_Event *Event)
|
|
{
|
|
/***** Get parameters *****/
|
|
Exa_GetParams (Exams);
|
|
if (Exams->ExaCod <= 0)
|
|
Lay_WrongExamExit ();
|
|
Exam->ExaCod = Exams->ExaCod;
|
|
Grp_GetParamWhichGroups ();
|
|
if ((Event->EvtCod = ExaEvt_GetParamEvtCod ()) <= 0)
|
|
Lay_WrongEventExit ();
|
|
|
|
/***** Get exam data from database *****/
|
|
Exa_GetDataOfExamByCod (Exam);
|
|
if (Exam->CrsCod != Gbl.Hierarchy.Crs.CrsCod)
|
|
Lay_WrongExamExit ();
|
|
Exams->ExaCod = Exam->ExaCod;
|
|
|
|
/***** Get set data from database *****/
|
|
ExaEvt_GetDataOfEventByCod (Event);
|
|
if (Event->ExaCod != Exam->ExaCod)
|
|
Lay_WrongSetExit ();
|
|
Exams->EvtCod = Event->EvtCod;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************** Get parameter with code of exam event *********************/
|
|
/*****************************************************************************/
|
|
|
|
long ExaEvt_GetParamEvtCod (void)
|
|
{
|
|
/***** Get code of exam event *****/
|
|
return Par_GetParToLong ("EvtCod");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Put a big button to play exam event (start a new exam event) as a teacher */
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_PutFormEvent (const struct ExaEvt_Event *Event)
|
|
{
|
|
extern const char *Hlp_ASSESSMENT_Exams_events;
|
|
extern const char *Txt_New_event;
|
|
extern const char *Txt_Title;
|
|
extern const char *Txt_Create_event;
|
|
extern const char *Txt_Save_changes;
|
|
static const Dat_SetHMS SetHMS[Dat_NUM_START_END_TIME] =
|
|
{
|
|
[Dat_START_TIME] = Dat_HMS_DO_NOT_SET,
|
|
[Dat_END_TIME ] = Dat_HMS_DO_NOT_SET
|
|
};
|
|
bool ItsANewEvent = Event->EvtCod <= 0;
|
|
|
|
/***** Start section for a new exam event *****/
|
|
HTM_SECTION_Begin (ExaEvt_NEW_EVENT_SECTION_ID);
|
|
|
|
/***** Begin form *****/
|
|
Frm_StartForm (ItsANewEvent ? ActNewExaEvt : // New event
|
|
ActChgExaEvt); // Existing event
|
|
Exa_PutParamExamCod (Event->ExaCod);
|
|
if (!ItsANewEvent) // Existing event
|
|
ExaEvt_PutParamEvtCod (Event->EvtCod);
|
|
|
|
/***** Begin box and table *****/
|
|
Box_BoxTableBegin (NULL,ItsANewEvent ? Txt_New_event :
|
|
Event->Title,
|
|
NULL,NULL,
|
|
Hlp_ASSESSMENT_Exams_events,Box_NOT_CLOSABLE,2);
|
|
|
|
/***** Event title *****/
|
|
HTM_TR_Begin (NULL);
|
|
|
|
/* Label */
|
|
Frm_LabelColumn ("RT","Title",Txt_Title);
|
|
|
|
/* Data */
|
|
HTM_TD_Begin ("class=\"LT\"");
|
|
HTM_INPUT_TEXT ("Title",ExaEvt_MAX_CHARS_TITLE,Event->Title,
|
|
HTM_DONT_SUBMIT_ON_CHANGE,
|
|
"id=\"Title\" size=\"45\" required=\"required\"");
|
|
HTM_TD_End ();
|
|
|
|
HTM_TR_End ();
|
|
|
|
/***** Start and end dates *****/
|
|
Dat_PutFormStartEndClientLocalDateTimes (Event->TimeUTC,
|
|
Dat_FORM_SECONDS_OFF,
|
|
SetHMS);
|
|
|
|
/***** Groups *****/
|
|
ExaEvt_ShowLstGrpsToCreateEvent (Event->EvtCod);
|
|
|
|
/***** End table, send button and end box *****/
|
|
if (ItsANewEvent)
|
|
Box_BoxTableWithButtonEnd (Btn_CREATE_BUTTON,Txt_Create_event);
|
|
else
|
|
Box_BoxTableWithButtonEnd (Btn_CONFIRM_BUTTON,Txt_Save_changes);
|
|
|
|
/***** End form *****/
|
|
Frm_EndForm ();
|
|
|
|
/***** End section for a new exam event *****/
|
|
HTM_SECTION_End ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************** Show list of groups to create a new exam event ***************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_ShowLstGrpsToCreateEvent (long EvtCod)
|
|
{
|
|
extern const char *The_ClassFormInBox[The_NUM_THEMES];
|
|
extern const char *Txt_Groups;
|
|
extern const char *Txt_The_whole_course;
|
|
unsigned NumGrpTyp;
|
|
|
|
/***** Get list of groups types and groups in this course *****/
|
|
Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
|
|
|
|
if (Gbl.Crs.Grps.GrpTypes.Num)
|
|
{
|
|
/***** Begin box and table *****/
|
|
HTM_TR_Begin (NULL);
|
|
|
|
HTM_TD_Begin ("class=\"%s RT\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
|
|
HTM_TxtF ("%s:",Txt_Groups);
|
|
HTM_TD_End ();
|
|
|
|
HTM_TD_Begin ("class=\"LT\"");
|
|
Box_BoxTableBegin ("95%",NULL,
|
|
NULL,NULL,
|
|
NULL,Box_NOT_CLOSABLE,0);
|
|
|
|
/***** First row: checkbox to select the whole course *****/
|
|
HTM_TR_Begin (NULL);
|
|
|
|
HTM_TD_Begin ("colspan=\"7\" class=\"DAT LM\"");
|
|
HTM_LABEL_Begin (NULL);
|
|
HTM_INPUT_CHECKBOX ("WholeCrs",HTM_DONT_SUBMIT_ON_CHANGE,
|
|
"id=\"WholeCrs\" value=\"Y\"%s"
|
|
" onclick=\"uncheckChildren(this,'GrpCods')\"",
|
|
Grp_CheckIfAssociatedToGrps ("exa_groups","EvtCod",EvtCod) ? "" :
|
|
" checked=\"checked\"");
|
|
HTM_TxtF ("%s %s",Txt_The_whole_course,Gbl.Hierarchy.Crs.ShrtName);
|
|
HTM_LABEL_End ();
|
|
HTM_TD_End ();
|
|
|
|
HTM_TR_End ();
|
|
|
|
/***** List the groups for each group type *****/
|
|
for (NumGrpTyp = 0;
|
|
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
|
|
NumGrpTyp++)
|
|
if (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps)
|
|
Grp_ListGrpsToEditAsgAttSvyEvtMch (&Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp],
|
|
EvtCod,
|
|
Grp_EXA_EVENT);
|
|
|
|
/***** End table and box *****/
|
|
Box_BoxTableEnd ();
|
|
HTM_TD_End ();
|
|
HTM_TR_End ();
|
|
}
|
|
|
|
/***** Free list of groups types and groups in this course *****/
|
|
Grp_FreeListGrpTypesAndGrps ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************* Put button to create a new event **********************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_PutButtonNewEvent (struct Exa_Exams *Exams,long ExaCod)
|
|
{
|
|
extern const char *Txt_New_event;
|
|
|
|
Exams->ExaCod = ExaCod;
|
|
Frm_StartFormAnchor (ActReqNewExaEvt,ExaEvt_NEW_EVENT_SECTION_ID);
|
|
Exa_PutParams (Exams);
|
|
Btn_PutConfirmButton (Txt_New_event);
|
|
Frm_EndForm ();
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************* Request the creation of a new event *********************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_RequestCreatOrEditEvent (void)
|
|
{
|
|
struct Exa_Exams Exams;
|
|
struct Exa_Exam Exam;
|
|
struct ExaEvt_Event Event;
|
|
bool ItsANewEvent;
|
|
|
|
/***** Reset exams context *****/
|
|
Exa_ResetExams (&Exams);
|
|
Exa_ResetExam (&Exam);
|
|
ExaEvt_ResetEvent (&Event);
|
|
|
|
/***** Get parameters *****/
|
|
Exa_GetParams (&Exams);
|
|
if (Exams.ExaCod <= 0)
|
|
Lay_WrongExamExit ();
|
|
Exam.ExaCod = Exams.ExaCod;
|
|
Grp_GetParamWhichGroups ();
|
|
Event.EvtCod = ExaEvt_GetParamEvtCod ();
|
|
ItsANewEvent = (Event.EvtCod <= 0);
|
|
|
|
/***** Get exam data from database *****/
|
|
Exa_GetDataOfExamByCod (&Exam);
|
|
if (Exam.CrsCod != Gbl.Hierarchy.Crs.CrsCod)
|
|
Lay_WrongExamExit ();
|
|
Exams.ExaCod = Exam.ExaCod;
|
|
|
|
/***** Get event data *****/
|
|
if (ItsANewEvent)
|
|
/* Initialize to empty event */
|
|
ExaEvt_ResetEvent (&Event);
|
|
else
|
|
{
|
|
/* Get event data from database */
|
|
ExaEvt_GetDataOfEventByCod (&Event);
|
|
if (Exam.ExaCod != Event.ExaCod)
|
|
Lay_WrongExamExit ();
|
|
Exams.EvtCod = Event.EvtCod;
|
|
}
|
|
|
|
/***** Show exam *****/
|
|
Exa_ShowOnlyOneExam (&Exams,&Exam,&Event,
|
|
true); // Put form for event
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************* Create a new exam event (by a teacher) ******************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_ReceiveFormEvent (void)
|
|
{
|
|
extern const char *Txt_Created_new_event_X;
|
|
extern const char *Txt_The_event_has_been_modified;
|
|
struct Exa_Exams Exams;
|
|
struct Exa_Exam Exam;
|
|
struct ExaEvt_Event Event;
|
|
bool ItsANewEvent;
|
|
|
|
/***** Reset exams context *****/
|
|
Exa_ResetExams (&Exams);
|
|
Exa_ResetExam (&Exam);
|
|
ExaEvt_ResetEvent (&Event);
|
|
|
|
/***** Get main parameters *****/
|
|
Exa_GetParams (&Exams);
|
|
if (Exams.ExaCod <= 0)
|
|
Lay_WrongExamExit ();
|
|
Exam.ExaCod = Exams.ExaCod;
|
|
Grp_GetParamWhichGroups ();
|
|
Event.EvtCod = ExaEvt_GetParamEvtCod ();
|
|
ItsANewEvent = (Event.EvtCod <= 0);
|
|
|
|
/***** Get exam data from database *****/
|
|
Exa_GetDataOfExamByCod (&Exam);
|
|
if (Exam.CrsCod != Gbl.Hierarchy.Crs.CrsCod)
|
|
Lay_WrongExamExit ();
|
|
Exams.ExaCod = Exam.ExaCod;
|
|
|
|
/***** Get event data from database *****/
|
|
if (ItsANewEvent)
|
|
{
|
|
/* Initialize to empty event */
|
|
ExaEvt_ResetEvent (&Event);
|
|
Event.ExaCod = Exam.ExaCod;
|
|
}
|
|
else
|
|
{
|
|
/* Get event data from database */
|
|
ExaEvt_GetDataOfEventByCod (&Event);
|
|
if (Event.ExaCod != Exam.ExaCod)
|
|
Lay_WrongExamExit ();
|
|
Exams.EvtCod = Event.EvtCod;
|
|
}
|
|
|
|
/***** Get parameters from form *****/
|
|
/* Get event title */
|
|
Par_GetParToText ("Title",Event.Title,ExaEvt_MAX_BYTES_TITLE);
|
|
|
|
/* Get start/end date-times */
|
|
Event.TimeUTC[Dat_START_TIME] = Dat_GetTimeUTCFromForm ("StartTimeUTC");
|
|
Event.TimeUTC[Dat_END_TIME ] = Dat_GetTimeUTCFromForm ("EndTimeUTC" );
|
|
|
|
/* Get groups associated to the event */
|
|
Grp_GetParCodsSeveralGrps ();
|
|
|
|
/***** Create/update event *****/
|
|
if (ItsANewEvent)
|
|
ExaEvt_CreateEvent (&Event);
|
|
else
|
|
ExaEvt_UpdateEvent (&Event);
|
|
|
|
/***** Free memory for list of selected groups *****/
|
|
Grp_FreeListCodSelectedGrps ();
|
|
|
|
/***** Write success message *****/
|
|
if (ItsANewEvent)
|
|
Ale_ShowAlert (Ale_SUCCESS,Txt_Created_new_event_X,
|
|
Event.Title);
|
|
else
|
|
Ale_ShowAlert (Ale_SUCCESS,Txt_The_event_has_been_modified);
|
|
|
|
/***** Get exam data again to update it after changes in event *****/
|
|
Exa_GetDataOfExamByCod (&Exam);
|
|
|
|
/***** Show current exam *****/
|
|
Exa_ShowOnlyOneExam (&Exams,&Exam,&Event,
|
|
false); // Do not put form for event
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**************************** Create a new event *****************************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_CreateEvent (struct ExaEvt_Event *Event)
|
|
{
|
|
/***** Insert this new exam event into database *****/
|
|
Event->EvtCod =
|
|
DB_QueryINSERTandReturnCode ("can not create exam event",
|
|
"INSERT exa_events "
|
|
"(ExaCod,Hidden,UsrCod,StartTime,EndTime,Title,ShowUsrResults)"
|
|
" VALUES "
|
|
"(%ld," // ExaCod
|
|
"'%c'," // Hidden
|
|
"%ld," // UsrCod
|
|
"FROM_UNIXTIME(%ld)," // Start time
|
|
"FROM_UNIXTIME(%ld)," // End time
|
|
"'%s'," // Title
|
|
"'N')", // ShowUsrResults: Don't show user results initially
|
|
Event->ExaCod,
|
|
Event->Hidden ? 'Y' :
|
|
'N',
|
|
Gbl.Usrs.Me.UsrDat.UsrCod, // Event creator
|
|
Event->TimeUTC[Dat_START_TIME], // Start time
|
|
Event->TimeUTC[Dat_END_TIME ], // End time
|
|
Event->Title);
|
|
|
|
/***** Create indexes for answers *****/
|
|
// ExaEvt_CreateIndexes (ExaCod,EvtCod);
|
|
|
|
/***** Create groups associated to the exam event *****/
|
|
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps)
|
|
ExaEvt_CreateGrps (Event->EvtCod);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************* Update an existing event **************************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_UpdateEvent (struct ExaEvt_Event *Event)
|
|
{
|
|
/***** Insert this new exam event into database *****/
|
|
DB_QueryUPDATE ("can not update exam event",
|
|
"UPDATE exa_events,exa_exams"
|
|
" SET exa_events.StartTime=FROM_UNIXTIME(%ld),"
|
|
"exa_events.EndTime=FROM_UNIXTIME(%ld),"
|
|
"exa_events.Title='%s',"
|
|
"exa_events.Hidden='%c'"
|
|
" WHERE exa_events.EvtCod=%ld"
|
|
" AND exa_events.ExaCod=exa_exams.ExaCod"
|
|
" AND exa_exams.CrsCod=%ld", // Extra check
|
|
Event->TimeUTC[Dat_START_TIME], // Start time
|
|
Event->TimeUTC[Dat_END_TIME ], // End time
|
|
Event->Title,
|
|
Event->Hidden ? 'Y' :
|
|
'N',
|
|
Event->EvtCod,Gbl.Hierarchy.Crs.CrsCod);
|
|
|
|
/***** Update groups associated to the exam event *****/
|
|
ExaEvt_RemoveGroups (Event->EvtCod); // Remove all groups associated to this event
|
|
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps)
|
|
ExaEvt_CreateGrps (Event->EvtCod); // Associate new groups
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**************** Create groups associated to an exam event ******************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_CreateGrps (long EvtCod)
|
|
{
|
|
unsigned NumGrpSel;
|
|
|
|
/***** Create groups associated to the exam event *****/
|
|
for (NumGrpSel = 0;
|
|
NumGrpSel < Gbl.Crs.Grps.LstGrpsSel.NumGrps;
|
|
NumGrpSel++)
|
|
/* Create group */
|
|
DB_QueryINSERT ("can not associate a group to an exam event",
|
|
"INSERT INTO exa_groups"
|
|
" (EvtCod,GrpCod)"
|
|
" VALUES"
|
|
" (%ld,%ld)",
|
|
EvtCod,Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrpSel]);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************* Remove all groups from one event **********************/
|
|
/*****************************************************************************/
|
|
|
|
static void ExaEvt_RemoveGroups (long EvtCod)
|
|
{
|
|
/***** Remove all groups from one event *****/
|
|
DB_QueryDELETE ("can not remove groups associated to and event",
|
|
"DELETE FROM exa_groups WHERE EvtCod=%ld",
|
|
EvtCod);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************* Remove one group from all events **********************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_RemoveGroup (long GrpCod)
|
|
{
|
|
/***** Remove group from all the events *****/
|
|
DB_QueryDELETE ("can not remove group"
|
|
" from the associations between events and groups",
|
|
"DELETE FROM exa_groups WHERE GrpCod=%ld",
|
|
GrpCod);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************** Remove groups of one type from all events *****************/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_RemoveGroupsOfType (long GrpTypCod)
|
|
{
|
|
/***** Remove group from all the events *****/
|
|
DB_QueryDELETE ("can not remove groups of a type"
|
|
" from the associations between events and groups",
|
|
"DELETE FROM exa_groups"
|
|
" USING crs_grp,exa_groups"
|
|
" WHERE crs_grp.GrpTypCod=%ld"
|
|
" AND crs_grp.GrpCod=exa_groups.GrpCod",
|
|
GrpTypCod);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************** Get number of events in an exam **********************/
|
|
/*****************************************************************************/
|
|
|
|
unsigned ExaEvt_GetNumEventsInExam (long ExaCod)
|
|
{
|
|
/***** Trivial check *****/
|
|
if (ExaCod < 0) // A non-existing exam...
|
|
return 0; // ...has no events
|
|
|
|
/***** Get number of events in an exam from database *****/
|
|
return
|
|
(unsigned) DB_QueryCOUNT ("can not get number of events of an exam",
|
|
"SELECT COUNT(*) FROM exa_events"
|
|
" WHERE ExaCod=%ld",
|
|
ExaCod);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************** Get number of open events in an exam *********************/
|
|
/*****************************************************************************/
|
|
|
|
unsigned ExaEvt_GetNumOpenEventsInExam (long ExaCod)
|
|
{
|
|
/***** Trivial check *****/
|
|
if (ExaCod < 0) // A non-existing exam...
|
|
return 0; // ...has no events
|
|
|
|
/***** Get number of open events in an exam from database *****/
|
|
return
|
|
(unsigned) DB_QueryCOUNT ("can not get number of open events of an exam",
|
|
"SELECT COUNT(*) FROM exa_events"
|
|
" WHERE ExaCod=%ld"
|
|
" AND NOW() BETWEEN StartTime AND EndTime",
|
|
ExaCod);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********* Check if I belong to any of the groups of an exam event ***********/
|
|
/*****************************************************************************/
|
|
|
|
bool ExaEvt_CheckIfICanAnswerThisEvent (const struct ExaEvt_Event *Event)
|
|
{
|
|
/***** Hidden or closed events are not accesible *****/
|
|
if (Event->Hidden || !Event->Open)
|
|
return false;
|
|
|
|
return ExaEvt_CheckIfICanListThisEventBasedOnGrps (Event);
|
|
}
|
|
|
|
bool ExaEvt_CheckIfICanListThisEventBasedOnGrps (const struct ExaEvt_Event *Event)
|
|
{
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
{
|
|
case Rol_STD:
|
|
/***** Check if I belong to any of the groups
|
|
associated to the exam event *****/
|
|
return (DB_QueryCOUNT ("can not check if I can play an exam event",
|
|
"SELECT COUNT(*) FROM exa_events"
|
|
" WHERE EvtCod=%ld"
|
|
" AND"
|
|
"(EvtCod NOT IN"
|
|
" (SELECT EvtCod FROM exa_groups)"
|
|
" OR"
|
|
" EvtCod IN"
|
|
" (SELECT exa_groups.EvtCod"
|
|
" FROM exa_groups,crs_grp_usr"
|
|
" WHERE crs_grp_usr.UsrCod=%ld"
|
|
" AND exa_groups.GrpCod=crs_grp_usr.GrpCod))",
|
|
Event->EvtCod,Gbl.Usrs.Me.UsrDat.UsrCod) != 0);
|
|
break;
|
|
case Rol_NET:
|
|
case Rol_TCH:
|
|
case Rol_SYS_ADM:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**** Receive previous question answer in an exam event question from database *****/
|
|
/*****************************************************************************/
|
|
|
|
void ExaEvt_GetQstAnsFromDB (long EvtCod,long UsrCod,unsigned QstInd,
|
|
struct ExaEvt_UsrAnswer *UsrAnswer)
|
|
{
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRows;
|
|
|
|
/***** Set default values for number of option and answer index *****/
|
|
UsrAnswer->NumOpt = -1; // < 0 ==> no answer selected
|
|
UsrAnswer->AnsInd = -1; // < 0 ==> no answer selected
|
|
|
|
/***** Get student's answer *****/
|
|
NumRows = (unsigned) DB_QuerySELECT (&mysql_res,"can not get user's answer to an exam event question",
|
|
"SELECT Indexes," // row[0] // TODO: Get correctly
|
|
"Answers" // row[1] // TODO: Get correctly
|
|
" FROM exa_prints,exa_print_questions"
|
|
" WHERE exa_prints.EvtCod=%ld"
|
|
" AND exa_prints.UsrCod=%ld"
|
|
" AND exa_prints.PrnCod=exa_print_questions.PrnCod"
|
|
" AND exa_print_questions.QstInd=%u",
|
|
EvtCod,UsrCod,QstInd);
|
|
if (NumRows) // Answer found...
|
|
{
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/***** Get number of option index (row[0]) *****/
|
|
if (sscanf (row[0],"%d",&(UsrAnswer->NumOpt)) != 1)
|
|
Lay_ShowErrorAndExit ("Error when getting student's answer to an exam event question.");
|
|
|
|
/***** Get answer index (row[1]) *****/
|
|
if (sscanf (row[1],"%d",&(UsrAnswer->AnsInd)) != 1)
|
|
Lay_ShowErrorAndExit ("Error when getting student's answer to an exam event question.");
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
}
|