mirror of
https://github.com/acanas/swad-core.git
synced 2024-06-05 08:15:25 +02:00
Version 21.54.4: Nov 09, 2021 Queries moved from API module to database modules.
This commit is contained in:
parent
0385edbf57
commit
eaad863026
626
swad_API.c
626
swad_API.c
|
@ -112,6 +112,7 @@ cp -f /home/acanas/swad/swad/swad /var/www/cgi-bin/
|
||||||
#include "swad_enrolment_database.h"
|
#include "swad_enrolment_database.h"
|
||||||
#include "swad_error.h"
|
#include "swad_error.h"
|
||||||
#include "swad_forum.h"
|
#include "swad_forum.h"
|
||||||
|
#include "swad_game_database.h"
|
||||||
#include "swad_global.h"
|
#include "swad_global.h"
|
||||||
#include "swad_group_database.h"
|
#include "swad_group_database.h"
|
||||||
#include "swad_hierarchy.h"
|
#include "swad_hierarchy.h"
|
||||||
|
@ -120,9 +121,11 @@ cp -f /home/acanas/swad/swad/swad /var/www/cgi-bin/
|
||||||
#include "swad_mail_database.h"
|
#include "swad_mail_database.h"
|
||||||
#include "swad_match.h"
|
#include "swad_match.h"
|
||||||
#include "swad_match_database.h"
|
#include "swad_match_database.h"
|
||||||
|
#include "swad_message_database.h"
|
||||||
#include "swad_nickname_database.h"
|
#include "swad_nickname_database.h"
|
||||||
#include "swad_notice.h"
|
#include "swad_notice.h"
|
||||||
#include "swad_notification.h"
|
#include "swad_notification.h"
|
||||||
|
#include "swad_notification_database.h"
|
||||||
#include "swad_password.h"
|
#include "swad_password.h"
|
||||||
#include "swad_plugin_database.h"
|
#include "swad_plugin_database.h"
|
||||||
#include "swad_question_database.h"
|
#include "swad_question_database.h"
|
||||||
|
@ -132,6 +135,7 @@ cp -f /home/acanas/swad/swad/swad /var/www/cgi-bin/
|
||||||
#include "swad_search.h"
|
#include "swad_search.h"
|
||||||
#include "swad_session_database.h"
|
#include "swad_session_database.h"
|
||||||
#include "swad_setting_database.h"
|
#include "swad_setting_database.h"
|
||||||
|
#include "swad_tag_database.h"
|
||||||
#include "swad_test_config.h"
|
#include "swad_test_config.h"
|
||||||
#include "swad_test_visibility.h"
|
#include "swad_test_visibility.h"
|
||||||
#include "swad_user.h"
|
#include "swad_user.h"
|
||||||
|
@ -267,17 +271,16 @@ static int API_GetMyLanguage (struct soap *soap);
|
||||||
|
|
||||||
static int API_SendMessageToUsr (long OriginalMsgCod,long SenderUsrCod,long ReplyUsrCod,long RecipientUsrCod,bool NotifyByEmail,const char *Subject,const char *Content);
|
static int API_SendMessageToUsr (long OriginalMsgCod,long SenderUsrCod,long ReplyUsrCod,long RecipientUsrCod,bool NotifyByEmail,const char *Subject,const char *Content);
|
||||||
|
|
||||||
static unsigned API_GetNumTestQuestionsInCrs (long CrsCod);
|
|
||||||
static int API_GetTstTags (struct soap *soap,
|
static int API_GetTstTags (struct soap *soap,
|
||||||
long CrsCod,struct swad__getTestsOutput *getTestsOut);
|
long CrsCod,struct swad__getTestsOutput *getTestsOut);
|
||||||
static int API_GetTstQuestions (struct soap *soap,
|
static int API_GetTstQuestions (struct soap *soap,
|
||||||
long CrsCod,long BeginTime,
|
long CrsCod,time_t BeginTime,
|
||||||
struct swad__getTestsOutput *getTestsOut);
|
struct swad__getTestsOutput *getTestsOut);
|
||||||
static int API_GetTstAnswers (struct soap *soap,
|
static int API_GetTstAnswers (struct soap *soap,
|
||||||
long CrsCod,long BeginTime,
|
long CrsCod,time_t BeginTime,
|
||||||
struct swad__getTestsOutput *getTestsOut);
|
struct swad__getTestsOutput *getTestsOut);
|
||||||
static int API_GetTstQuestionTags (struct soap *soap,
|
static int API_GetTstQuestionTags (struct soap *soap,
|
||||||
long CrsCod,long BeginTime,
|
long CrsCod,time_t BeginTime,
|
||||||
struct swad__getTestsOutput *getTestsOut);
|
struct swad__getTestsOutput *getTestsOut);
|
||||||
|
|
||||||
static void API_GetListGrpsInMatchFromDB (struct soap *soap,
|
static void API_GetListGrpsInMatchFromDB (struct soap *soap,
|
||||||
|
@ -2645,10 +2648,11 @@ int swad__getAttendanceUsers (struct soap *soap,
|
||||||
{
|
{
|
||||||
int ReturnCode;
|
int ReturnCode;
|
||||||
struct Att_Event Event;
|
struct Att_Event Event;
|
||||||
char SubQuery[512];
|
bool AttEventIsAsociatedToGrps;
|
||||||
MYSQL_RES *mysql_res;
|
MYSQL_RES *mysql_res;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
unsigned NumRow,NumRows;
|
unsigned NumUsrs;
|
||||||
|
unsigned NumUsr;
|
||||||
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
|
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
|
||||||
size_t Length;
|
size_t Length;
|
||||||
|
|
||||||
|
@ -2684,154 +2688,96 @@ int swad__getAttendanceUsers (struct soap *soap,
|
||||||
"Requester must be a teacher");
|
"Requester must be a teacher");
|
||||||
|
|
||||||
/***** Query list of attendance users *****/
|
/***** Query list of attendance users *****/
|
||||||
if (Grp_DB_CheckIfAssociatedToGrps ("att_groups","AttCod",Event.AttCod))
|
AttEventIsAsociatedToGrps = Grp_DB_CheckIfAssociatedToGrps ("att_groups","AttCod",Event.AttCod);
|
||||||
// Event for one or more groups
|
|
||||||
// Subquery: list of users in groups of this attendance event...
|
|
||||||
// ...who have no entry in attendance list of users
|
|
||||||
sprintf (SubQuery,"SELECT DISTINCT "
|
|
||||||
"grp_users.UsrCod AS UsrCod," // row[0]
|
|
||||||
"'N' AS Present" // row[1]
|
|
||||||
" FROM att_groups,"
|
|
||||||
"grp_groups,"
|
|
||||||
"grp_types,"
|
|
||||||
"crs_users,"
|
|
||||||
"grp_users"
|
|
||||||
" WHERE att_groups.AttCod=%ld"
|
|
||||||
" AND att_groups.GrpCod=grp_groups.GrpCod"
|
|
||||||
" AND grp_groups.GrpTypCod=grp_types.GrpTypCod"
|
|
||||||
" AND grp_types.CrsCod=crs_users.CrsCod"
|
|
||||||
" AND crs_users.Role=%u"
|
|
||||||
" AND crs_users.UsrCod=grp_users.UsrCod"
|
|
||||||
" AND grp_users.GrpCod=att_groups.GrpCod"
|
|
||||||
" AND grp_users.UsrCod NOT IN"
|
|
||||||
" (SELECT UsrCod"
|
|
||||||
" FROM att_users"
|
|
||||||
" WHERE AttCod=%ld)",
|
|
||||||
Event.AttCod,
|
|
||||||
(unsigned) Rol_STD,
|
|
||||||
Event.AttCod);
|
|
||||||
else
|
|
||||||
// Event for the whole course
|
|
||||||
// Subquery: list of users in the course of this attendance event...
|
|
||||||
// ...who have no entry in attendance list of users
|
|
||||||
sprintf (SubQuery,"SELECT crs_users.UsrCod AS UsrCod," // row[0]
|
|
||||||
"'N' AS Present" // row[1]
|
|
||||||
" FROM att_events,"
|
|
||||||
"crs_users"
|
|
||||||
" WHERE att_events.AttCod=%ld"
|
|
||||||
" AND att_events.CrsCod=crs_users.CrsCod"
|
|
||||||
" AND crs_users.Role=%u"
|
|
||||||
" AND crs_users.UsrCod NOT IN"
|
|
||||||
" (SELECT UsrCod"
|
|
||||||
" FROM att_users"
|
|
||||||
" WHERE AttCod=%ld)",
|
|
||||||
Event.AttCod,
|
|
||||||
(unsigned) Rol_STD,
|
|
||||||
Event.AttCod);
|
|
||||||
// Query: list of users in attendance list + rest of users (subquery)
|
|
||||||
NumRows = (unsigned)
|
|
||||||
DB_QuerySELECT (&mysql_res,"can not get users in an attendance event",
|
|
||||||
"SELECT u.UsrCod," // row[0]
|
|
||||||
"u.Present" // row[1]
|
|
||||||
" FROM (SELECT UsrCod,"
|
|
||||||
"Present"
|
|
||||||
" FROM att_users"
|
|
||||||
" WHERE AttCod=%ld"
|
|
||||||
" UNION %s) AS u,"
|
|
||||||
"usr_data"
|
|
||||||
" WHERE u.UsrCod=usr_data.UsrCod"
|
|
||||||
" ORDER BY usr_data.Surname1,"
|
|
||||||
"usr_data.Surname2,"
|
|
||||||
"usr_data.FirstName",
|
|
||||||
(long) attendanceEventCode,
|
|
||||||
SubQuery);
|
|
||||||
|
|
||||||
getAttendanceUsersOut->numUsers = (int) NumRows;
|
NumUsrs = Att_DB_GetListUsrsInAttEvent (&mysql_res,Event.AttCod,AttEventIsAsociatedToGrps);
|
||||||
getAttendanceUsersOut->usersArray.__size = (int) NumRows;
|
|
||||||
|
|
||||||
if (NumRows == 0)
|
getAttendanceUsersOut->numUsers =
|
||||||
getAttendanceUsersOut->usersArray.__ptr = NULL;
|
getAttendanceUsersOut->usersArray.__size = (int) NumUsrs;
|
||||||
else // Events found
|
|
||||||
|
if (NumUsrs) // Users found
|
||||||
{
|
{
|
||||||
getAttendanceUsersOut->usersArray.__ptr = soap_malloc (soap,
|
getAttendanceUsersOut->usersArray.__ptr = soap_malloc (soap,
|
||||||
(getAttendanceUsersOut->usersArray.__size) *
|
(getAttendanceUsersOut->usersArray.__size) *
|
||||||
sizeof (*(getAttendanceUsersOut->usersArray.__ptr)));
|
sizeof (*(getAttendanceUsersOut->usersArray.__ptr)));
|
||||||
|
|
||||||
for (NumRow = 0;
|
for (NumUsr = 0;
|
||||||
NumRow < NumRows;
|
NumUsr < NumUsrs;
|
||||||
NumRow++)
|
NumUsr++)
|
||||||
{
|
{
|
||||||
/* Get next user */
|
/* Get next user */
|
||||||
row = mysql_fetch_row (mysql_res);
|
row = mysql_fetch_row (mysql_res);
|
||||||
|
|
||||||
/* Get user's code (row[0]) */
|
/* Get user's code (row[0]) */
|
||||||
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
|
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userCode = (int) Gbl.Usrs.Other.UsrDat.UsrCod;
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userCode = (int) Gbl.Usrs.Other.UsrDat.UsrCod;
|
||||||
|
|
||||||
/* Get user's data */
|
/* Get user's data */
|
||||||
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,-1L)) // Get some user's data from database
|
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,-1L)) // Get some user's data from database
|
||||||
{
|
{
|
||||||
Length = strlen (Gbl.Usrs.Other.UsrDat.Nickname);
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Nickname);
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userNickname =
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userNickname =
|
||||||
soap_malloc (soap,Length + 1);
|
soap_malloc (soap,Length + 1);
|
||||||
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userNickname,
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userNickname,
|
||||||
Gbl.Usrs.Other.UsrDat.Nickname,Length);
|
Gbl.Usrs.Other.UsrDat.Nickname,Length);
|
||||||
|
|
||||||
if (Gbl.Usrs.Other.UsrDat.IDs.Num)
|
if (Gbl.Usrs.Other.UsrDat.IDs.Num)
|
||||||
{
|
{
|
||||||
Length = strlen (Gbl.Usrs.Other.UsrDat.IDs.List[0].ID); // TODO: What user's ID?
|
Length = strlen (Gbl.Usrs.Other.UsrDat.IDs.List[0].ID); // TODO: What user's ID?
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userID =
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userID =
|
||||||
soap_malloc (soap,Length + 1);
|
soap_malloc (soap,Length + 1);
|
||||||
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userID,
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userID,
|
||||||
Gbl.Usrs.Other.UsrDat.IDs.List[0].ID,Length);
|
Gbl.Usrs.Other.UsrDat.IDs.List[0].ID,Length);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userID =
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userID =
|
||||||
soap_malloc (soap,1);
|
soap_malloc (soap,1);
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userID[0] = '\0';
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userID[0] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname1 =
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname1 =
|
||||||
soap_malloc (soap,Length + 1);
|
soap_malloc (soap,Length + 1);
|
||||||
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname1,
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname1,
|
||||||
Gbl.Usrs.Other.UsrDat.Surname1,Length);
|
Gbl.Usrs.Other.UsrDat.Surname1,Length);
|
||||||
|
|
||||||
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname2 =
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname2 =
|
||||||
soap_malloc (soap,Length + 1);
|
soap_malloc (soap,Length + 1);
|
||||||
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname2,
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname2,
|
||||||
Gbl.Usrs.Other.UsrDat.Surname2,Length);
|
Gbl.Usrs.Other.UsrDat.Surname2,Length);
|
||||||
|
|
||||||
Length = strlen (Gbl.Usrs.Other.UsrDat.FrstName);
|
Length = strlen (Gbl.Usrs.Other.UsrDat.FrstName);
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userFirstname =
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userFirstname =
|
||||||
soap_malloc (soap,Length + 1);
|
soap_malloc (soap,Length + 1);
|
||||||
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userFirstname,
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userFirstname,
|
||||||
Gbl.Usrs.Other.UsrDat.FrstName,Length);
|
Gbl.Usrs.Other.UsrDat.FrstName,Length);
|
||||||
|
|
||||||
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
|
||||||
Length = strlen (PhotoURL);
|
Length = strlen (PhotoURL);
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userPhoto =
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userPhoto =
|
||||||
soap_malloc (soap,Length + 1);
|
soap_malloc (soap,Length + 1);
|
||||||
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userPhoto,
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userPhoto,
|
||||||
PhotoURL,Length);
|
PhotoURL,Length);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userNickname = NULL;
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userNickname = NULL;
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userID = NULL;
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userID = NULL;
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname1 = NULL;
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname1 = NULL;
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname2 = NULL;
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname2 = NULL;
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userFirstname = NULL;
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userFirstname = NULL;
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].userPhoto = NULL;
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userPhoto = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get if user is present or not (row[1]) */
|
/* Get if user is present or not (row[1]) */
|
||||||
getAttendanceUsersOut->usersArray.__ptr[NumRow].present = (row[1][0] == 'Y') ? 1 :
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].present = (row[1][0] == 'Y') ? 1 :
|
||||||
0;
|
0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
getAttendanceUsersOut->usersArray.__ptr = NULL;
|
||||||
|
|
||||||
/***** Free structure that stores the query result *****/
|
/***** Free structure that stores the query result *****/
|
||||||
DB_FreeMySQLResult (&mysql_res);
|
DB_FreeMySQLResult (&mysql_res);
|
||||||
|
@ -2994,7 +2940,7 @@ int swad__getNotifications (struct soap *soap,
|
||||||
int ReturnCode;
|
int ReturnCode;
|
||||||
MYSQL_RES *mysql_res;
|
MYSQL_RES *mysql_res;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
unsigned NumNotifications;
|
unsigned NumNotifs;
|
||||||
unsigned NumNotif;
|
unsigned NumNotif;
|
||||||
long NtfCod;
|
long NtfCod;
|
||||||
Ntf_NotifyEvent_t NotifyEvent;
|
Ntf_NotifyEvent_t NotifyEvent;
|
||||||
|
@ -3034,34 +2980,16 @@ int swad__getNotifications (struct soap *soap,
|
||||||
return ReturnCode;
|
return ReturnCode;
|
||||||
|
|
||||||
/***** Get my notifications from database *****/
|
/***** Get my notifications from database *****/
|
||||||
NumNotifications = (unsigned)
|
if ((NumNotifs = Ntf_DB_GetMyRecentNotifications (&mysql_res,(time_t) beginTime))) // Notifications found
|
||||||
DB_QuerySELECT (&mysql_res,"can not get user's notifications",
|
|
||||||
"SELECT NtfCod," // row[0]
|
|
||||||
"NotifyEvent," // row[1]
|
|
||||||
"UNIX_TIMESTAMP(TimeNotif)," // row[2]
|
|
||||||
"FromUsrCod," // row[3]
|
|
||||||
"InsCod," // row[4]
|
|
||||||
"CtrCod," // row[5]
|
|
||||||
"DegCod," // row[6]
|
|
||||||
"CrsCod," // row[7]
|
|
||||||
"Cod," // row[8]
|
|
||||||
"Status" // row[9]
|
|
||||||
" FROM ntf_notifications"
|
|
||||||
" WHERE ToUsrCod=%ld"
|
|
||||||
" AND TimeNotif>=FROM_UNIXTIME(%ld)"
|
|
||||||
" ORDER BY TimeNotif DESC",
|
|
||||||
Gbl.Usrs.Me.UsrDat.UsrCod,beginTime);
|
|
||||||
|
|
||||||
if (NumNotifications) // Notifications found
|
|
||||||
{
|
{
|
||||||
getNotificationsOut->numNotifications = (int) NumNotifications;
|
getNotificationsOut->numNotifications =
|
||||||
getNotificationsOut->notificationsArray.__size = (int) NumNotifications;
|
getNotificationsOut->notificationsArray.__size = (int) NumNotifs;
|
||||||
getNotificationsOut->notificationsArray.__ptr = soap_malloc (soap,
|
getNotificationsOut->notificationsArray.__ptr = soap_malloc (soap,
|
||||||
(getNotificationsOut->notificationsArray.__size) *
|
(getNotificationsOut->notificationsArray.__size) *
|
||||||
sizeof (*(getNotificationsOut->notificationsArray.__ptr)));
|
sizeof (*(getNotificationsOut->notificationsArray.__ptr)));
|
||||||
|
|
||||||
for (NumNotif = 0;
|
for (NumNotif = 0;
|
||||||
NumNotif < NumNotifications;
|
NumNotif < NumNotifs;
|
||||||
NumNotif++)
|
NumNotif++)
|
||||||
{
|
{
|
||||||
/* Get next notification */
|
/* Get next notification */
|
||||||
|
@ -3349,15 +3277,10 @@ int swad__sendMessage (struct soap *soap,
|
||||||
{
|
{
|
||||||
int ReturnCode;
|
int ReturnCode;
|
||||||
long ReplyUsrCod = -1L;
|
long ReplyUsrCod = -1L;
|
||||||
char Nick[Nck_MAX_BYTES_NICK_WITH_ARROBA + 1];
|
|
||||||
char *Query = NULL;
|
|
||||||
MYSQL_RES *mysql_res;
|
MYSQL_RES *mysql_res;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
unsigned NumUsrs;
|
unsigned NumUsrs;
|
||||||
unsigned NumUsr;
|
unsigned NumUsr;
|
||||||
bool FirstNickname = true;
|
|
||||||
bool ThereAreNicknames = false;
|
|
||||||
const char *Ptr;
|
|
||||||
bool ItsMe;
|
bool ItsMe;
|
||||||
bool NotifyByEmail;
|
bool NotifyByEmail;
|
||||||
|
|
||||||
|
@ -3385,111 +3308,28 @@ int swad__sendMessage (struct soap *soap,
|
||||||
if (messageCode)
|
if (messageCode)
|
||||||
{
|
{
|
||||||
/***** Check if the original message was really received by me *****/
|
/***** Check if the original message was really received by me *****/
|
||||||
if (DB_QuerySELECTUnsigned ("can not check original message",
|
if (!Msg_DB_CheckIfMsgHasBeenReceivedByMe ((long) messageCode))
|
||||||
"SELECT SUM(N)"
|
|
||||||
" FROM (SELECT COUNT(*) AS N"
|
|
||||||
" FROM msg_rcv"
|
|
||||||
" WHERE UsrCod=%ld"
|
|
||||||
" AND MsgCod=%ld"
|
|
||||||
" UNION"
|
|
||||||
" SELECT COUNT(*) AS N"
|
|
||||||
" FROM msg_rcv_deleted"
|
|
||||||
" WHERE UsrCod=%ld"
|
|
||||||
" AND MsgCod=%ld) AS T",
|
|
||||||
Gbl.Usrs.Me.UsrDat.UsrCod,(long) messageCode,
|
|
||||||
Gbl.Usrs.Me.UsrDat.UsrCod,(long) messageCode) == 0)
|
|
||||||
return soap_sender_fault (soap,
|
return soap_sender_fault (soap,
|
||||||
"Can not send reply message",
|
"Can not send reply message",
|
||||||
"Original message does not exist");
|
"Original message does not exist");
|
||||||
|
|
||||||
/***** Get the recipient of the message *****/
|
/***** Get the recipient of the message *****/
|
||||||
ReplyUsrCod = DB_QuerySELECTCode ("can not check original message",
|
if ((ReplyUsrCod = Msg_DB_GetSender ((long) messageCode)) <= 0)
|
||||||
"SELECT UsrCod"
|
|
||||||
" FROM msg_snt"
|
|
||||||
" WHERE MsgCod=%ld"
|
|
||||||
" UNION "
|
|
||||||
"SELECT UsrCod"
|
|
||||||
" FROM msg_snt_deleted"
|
|
||||||
" WHERE MsgCod=%ld",
|
|
||||||
(long) messageCode,
|
|
||||||
(long) messageCode);
|
|
||||||
if (ReplyUsrCod <= 0)
|
|
||||||
return soap_sender_fault (soap,
|
return soap_sender_fault (soap,
|
||||||
"Can not send reply message",
|
"Can not send reply message",
|
||||||
"Original message does not exist");
|
"Original message does not exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** Allocate space for query *****/
|
/***** Query database to get users *****/
|
||||||
if ((Query = malloc (API_MAX_BYTES_QUERY_RECIPIENTS + 1)) == NULL)
|
NumUsrs = Msg_DB_GetRecipientsCods (&mysql_res,ReplyUsrCod,to);
|
||||||
Err_NotEnoughMemoryExit ();
|
|
||||||
|
|
||||||
/***** Build query for recipients from database *****/
|
|
||||||
if (ReplyUsrCod > 0)
|
|
||||||
snprintf (Query,API_MAX_BYTES_QUERY_RECIPIENTS + 1,
|
|
||||||
"SELECT UsrCod"
|
|
||||||
" FROM usr_data"
|
|
||||||
" WHERE UsrCod=%ld",
|
|
||||||
ReplyUsrCod);
|
|
||||||
else
|
|
||||||
Query[0] = '\0';
|
|
||||||
|
|
||||||
/***** Loop over recipients' nicknames building query *****/
|
|
||||||
Ptr = to;
|
|
||||||
while (*Ptr)
|
|
||||||
{
|
|
||||||
/* Find next string in text until comma (leading and trailing spaces are removed) */
|
|
||||||
Str_GetNextStringUntilComma (&Ptr,Nick,sizeof (Nick) - 1); // With leading arrobas
|
|
||||||
|
|
||||||
/* Check if string is a valid nickname */
|
|
||||||
if (Nck_CheckIfNickWithArrIsValid (Nick)) // String is a nickname (with leading arrobas)?
|
|
||||||
{
|
|
||||||
Str_RemoveLeadingArrobas (Nick);
|
|
||||||
|
|
||||||
/* Check for overflow in query */
|
|
||||||
if (strlen (Query) + Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 32 >
|
|
||||||
API_MAX_BYTES_QUERY_RECIPIENTS)
|
|
||||||
return soap_sender_fault (soap,
|
|
||||||
"Can not send message",
|
|
||||||
"Too many recipients");
|
|
||||||
|
|
||||||
/* Add this nickname to query */
|
|
||||||
if (FirstNickname)
|
|
||||||
{
|
|
||||||
if (ReplyUsrCod > 0)
|
|
||||||
Str_Concat (Query," UNION ",API_MAX_BYTES_QUERY_RECIPIENTS);
|
|
||||||
Str_Concat (Query,"SELECT UsrCod"
|
|
||||||
" FROM usr_nicknames"
|
|
||||||
" WHERE Nickname IN ('",
|
|
||||||
API_MAX_BYTES_QUERY_RECIPIENTS);
|
|
||||||
FirstNickname = false;
|
|
||||||
ThereAreNicknames = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Str_Concat (Query,",'",API_MAX_BYTES_QUERY_RECIPIENTS);
|
|
||||||
Str_Concat (Query,Nick,API_MAX_BYTES_QUERY_RECIPIENTS); // Leading arrobas already removed
|
|
||||||
Str_Concat (Query,"'",API_MAX_BYTES_QUERY_RECIPIENTS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ThereAreNicknames)
|
|
||||||
Str_Concat (Query,")",API_MAX_BYTES_QUERY_RECIPIENTS);
|
|
||||||
|
|
||||||
/***** Initialize output structure *****/
|
/***** Initialize output structure *****/
|
||||||
sendMessageOut->numUsers = 0;
|
sendMessageOut->numUsers =
|
||||||
sendMessageOut->usersArray.__size = 0;
|
sendMessageOut->usersArray.__size = (int) NumUsrs;
|
||||||
sendMessageOut->usersArray.__ptr = NULL;
|
sendMessageOut->usersArray.__ptr = NULL;
|
||||||
|
|
||||||
if (ReplyUsrCod > 0 || ThereAreNicknames) // There are a recipient to reply or nicknames in "to"
|
|
||||||
{
|
|
||||||
/***** Get users *****/
|
/***** Get users *****/
|
||||||
NumUsrs = (unsigned)
|
if (NumUsrs) // There are a recipient to reply or nicknames in "to"
|
||||||
DB_QuerySELECT (&mysql_res,"can not get users",
|
|
||||||
"%s",
|
|
||||||
Query);
|
|
||||||
|
|
||||||
sendMessageOut->numUsers = (int) NumUsrs;
|
|
||||||
sendMessageOut->usersArray.__size = (int) NumUsrs;
|
|
||||||
|
|
||||||
if (NumUsrs) // Users found
|
|
||||||
{
|
{
|
||||||
sendMessageOut->usersArray.__ptr = soap_malloc (soap,
|
sendMessageOut->usersArray.__ptr = soap_malloc (soap,
|
||||||
(sendMessageOut->usersArray.__size) *
|
(sendMessageOut->usersArray.__size) *
|
||||||
|
@ -3538,7 +3378,7 @@ int swad__sendMessage (struct soap *soap,
|
||||||
|
|
||||||
/***** Free structure that stores the query result *****/
|
/***** Free structure that stores the query result *****/
|
||||||
DB_FreeMySQLResult (&mysql_res);
|
DB_FreeMySQLResult (&mysql_res);
|
||||||
}
|
|
||||||
return SOAP_OK;
|
return SOAP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3783,42 +3623,11 @@ int swad__getTestConfig (struct soap *soap,
|
||||||
/***** Get number of tests *****/
|
/***** Get number of tests *****/
|
||||||
if (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES &&
|
if (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES &&
|
||||||
TstCfg_GetConfigMax () > 0)
|
TstCfg_GetConfigMax () > 0)
|
||||||
getTestConfigOut->numQuestions = (int) API_GetNumTestQuestionsInCrs ((long) courseCode);
|
getTestConfigOut->numQuestions = (int) Qst_DB_GetNumQstsInCrs ((long) courseCode);
|
||||||
|
|
||||||
return SOAP_OK;
|
return SOAP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/** Get number of visible test questions from database giving a course code **/
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
static unsigned API_GetNumTestQuestionsInCrs (long CrsCod)
|
|
||||||
{
|
|
||||||
/***** Get number of questions *****/
|
|
||||||
// Reject questions with any tag hidden
|
|
||||||
// Select only questions with tags
|
|
||||||
return (unsigned)
|
|
||||||
DB_QueryCOUNT ("can not get number of test questions",
|
|
||||||
"SELECT COUNT(*)"
|
|
||||||
" FROM tst_questions,"
|
|
||||||
"tst_question_tags,"
|
|
||||||
"tst_tags"
|
|
||||||
" WHERE tst_questions.CrsCod=%ld"
|
|
||||||
" AND tst_questions.QstCod NOT IN"
|
|
||||||
" (SELECT tst_question_tags.QstCod"
|
|
||||||
" FROM tst_tags,"
|
|
||||||
"tst_question_tags"
|
|
||||||
" WHERE tst_tags.CrsCod=%ld"
|
|
||||||
" AND tst_tags.TagHidden='Y'"
|
|
||||||
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
|
||||||
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
|
||||||
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
|
||||||
" AND tst_tags.CrsCod=%ld",
|
|
||||||
CrsCod,
|
|
||||||
CrsCod,
|
|
||||||
CrsCod);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/************************* Return tests of a course **************************/
|
/************************* Return tests of a course **************************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -3887,17 +3696,17 @@ int swad__getTests (struct soap *soap,
|
||||||
|
|
||||||
/***** Get questions *****/
|
/***** Get questions *****/
|
||||||
if ((ReturnCode = API_GetTstQuestions (soap,
|
if ((ReturnCode = API_GetTstQuestions (soap,
|
||||||
(long) courseCode,beginTime,getTestsOut)) != SOAP_OK)
|
(long) courseCode,(time_t) beginTime,getTestsOut)) != SOAP_OK)
|
||||||
return ReturnCode;
|
return ReturnCode;
|
||||||
|
|
||||||
/***** Get answers *****/
|
/***** Get answers *****/
|
||||||
if ((ReturnCode = API_GetTstAnswers (soap,
|
if ((ReturnCode = API_GetTstAnswers (soap,
|
||||||
(long) courseCode,beginTime,getTestsOut)) != SOAP_OK)
|
(long) courseCode,(time_t) beginTime,getTestsOut)) != SOAP_OK)
|
||||||
return ReturnCode;
|
return ReturnCode;
|
||||||
|
|
||||||
/***** Get tags for each question *****/
|
/***** Get tags for each question *****/
|
||||||
if ((ReturnCode = API_GetTstQuestionTags (soap,
|
if ((ReturnCode = API_GetTstQuestionTags (soap,
|
||||||
(long) courseCode,beginTime,getTestsOut)) != SOAP_OK)
|
(long) courseCode,(time_t) beginTime,getTestsOut)) != SOAP_OK)
|
||||||
return ReturnCode;
|
return ReturnCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3918,15 +3727,7 @@ static int API_GetTstTags (struct soap *soap,
|
||||||
unsigned NumTag;
|
unsigned NumTag;
|
||||||
|
|
||||||
/***** Get available tags from database *****/
|
/***** Get available tags from database *****/
|
||||||
NumTags = (unsigned)
|
NumTags = Tag_DB_GetEnabledTagsFromCrs (&mysql_res,CrsCod);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get test tags",
|
|
||||||
"SELECT TagCod," // row[0]
|
|
||||||
"TagTxt" // row[1]
|
|
||||||
" FROM tst_tags"
|
|
||||||
" WHERE CrsCod=%ld"
|
|
||||||
" AND TagHidden='N'"
|
|
||||||
" ORDER BY TagTxt",
|
|
||||||
CrsCod);
|
|
||||||
|
|
||||||
getTestsOut->tagsArray.__size = (int) NumTags;
|
getTestsOut->tagsArray.__size = (int) NumTags;
|
||||||
|
|
||||||
|
@ -3967,53 +3768,23 @@ static int API_GetTstTags (struct soap *soap,
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static int API_GetTstQuestions (struct soap *soap,
|
static int API_GetTstQuestions (struct soap *soap,
|
||||||
long CrsCod,long BeginTime,
|
long CrsCod,time_t BeginTime,
|
||||||
struct swad__getTestsOutput *getTestsOut)
|
struct swad__getTestsOutput *getTestsOut)
|
||||||
{
|
{
|
||||||
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
||||||
MYSQL_RES *mysql_res;
|
MYSQL_RES *mysql_res;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
unsigned NumRow;
|
unsigned NumQsts;
|
||||||
unsigned NumRows;
|
unsigned NumQst;
|
||||||
Qst_AnswerType_t AnswerType;
|
Qst_AnswerType_t AnswerType;
|
||||||
|
|
||||||
/***** Get recent test questions from database *****/
|
/***** Get recent test questions from database *****/
|
||||||
// DISTINCT is necessary to not repeat questions
|
// DISTINCT is necessary to not repeat questions
|
||||||
NumRows = (unsigned)
|
NumQsts = Qst_DB_GetRecentQuestions (&mysql_res,CrsCod,BeginTime);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get test questions",
|
|
||||||
"SELECT DISTINCT "
|
|
||||||
"tst_questions.QstCod," // row[0]
|
|
||||||
"tst_questions.AnsType," // row[1]
|
|
||||||
"tst_questions.Shuffle," // row[2]
|
|
||||||
"tst_questions.Stem," // row[3]
|
|
||||||
"tst_questions.Feedback" // row[4]
|
|
||||||
" FROM tst_questions,"
|
|
||||||
"tst_question_tags,"
|
|
||||||
"tst_tags"
|
|
||||||
" WHERE tst_questions.CrsCod=%ld"
|
|
||||||
" AND tst_questions.QstCod NOT IN"
|
|
||||||
" (SELECT tst_question_tags.QstCod"
|
|
||||||
" FROM tst_tags,"
|
|
||||||
"tst_question_tags"
|
|
||||||
" WHERE tst_tags.CrsCod=%ld"
|
|
||||||
" AND tst_tags.TagHidden='Y'"
|
|
||||||
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
|
||||||
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
|
||||||
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
|
||||||
" AND tst_tags.CrsCod=%ld"
|
|
||||||
" AND (tst_questions.EditTime>=FROM_UNIXTIME(%ld)"
|
|
||||||
" OR "
|
|
||||||
"tst_tags.ChangeTime>=FROM_UNIXTIME(%ld))"
|
|
||||||
" ORDER BY QstCod",
|
|
||||||
CrsCod,
|
|
||||||
CrsCod,
|
|
||||||
CrsCod,
|
|
||||||
BeginTime,
|
|
||||||
BeginTime);
|
|
||||||
|
|
||||||
getTestsOut->questionsArray.__size = (int) NumRows;
|
getTestsOut->questionsArray.__size = (int) NumQsts;
|
||||||
|
|
||||||
if (NumRows == 0)
|
if (NumQsts == 0)
|
||||||
getTestsOut->questionsArray.__ptr = NULL;
|
getTestsOut->questionsArray.__ptr = NULL;
|
||||||
else // Questions found
|
else // Questions found
|
||||||
{
|
{
|
||||||
|
@ -4021,38 +3792,38 @@ static int API_GetTstQuestions (struct soap *soap,
|
||||||
(getTestsOut->questionsArray.__size) *
|
(getTestsOut->questionsArray.__size) *
|
||||||
sizeof (*(getTestsOut->questionsArray.__ptr)));
|
sizeof (*(getTestsOut->questionsArray.__ptr)));
|
||||||
|
|
||||||
for (NumRow = 0;
|
for (NumQst = 0;
|
||||||
NumRow < NumRows;
|
NumQst < NumQsts;
|
||||||
NumRow++)
|
NumQst++)
|
||||||
{
|
{
|
||||||
/* Get next question */
|
/* Get next question */
|
||||||
row = mysql_fetch_row (mysql_res);
|
row = mysql_fetch_row (mysql_res);
|
||||||
|
|
||||||
/* Get question code (row[0]) */
|
/* Get question code (row[0]) */
|
||||||
getTestsOut->questionsArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
getTestsOut->questionsArray.__ptr[NumQst].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
||||||
|
|
||||||
/* Get answer type (row[1]) */
|
/* Get answer type (row[1]) */
|
||||||
AnswerType = Qst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
|
AnswerType = Qst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
|
||||||
getTestsOut->questionsArray.__ptr[NumRow].answerType =
|
getTestsOut->questionsArray.__ptr[NumQst].answerType =
|
||||||
soap_malloc (soap,Qst_MAX_BYTES_ANSWER_TYPE + 1);
|
soap_malloc (soap,Qst_MAX_BYTES_ANSWER_TYPE + 1);
|
||||||
Str_Copy (getTestsOut->questionsArray.__ptr[NumRow].answerType,
|
Str_Copy (getTestsOut->questionsArray.__ptr[NumQst].answerType,
|
||||||
Qst_StrAnswerTypesXML[AnswerType],
|
Qst_StrAnswerTypesXML[AnswerType],
|
||||||
Qst_MAX_BYTES_ANSWER_TYPE);
|
Qst_MAX_BYTES_ANSWER_TYPE);
|
||||||
|
|
||||||
/* Get shuffle (row[2]) */
|
/* Get shuffle (row[2]) */
|
||||||
getTestsOut->questionsArray.__ptr[NumRow].shuffle = (row[2][0] == 'Y') ? 1 :
|
getTestsOut->questionsArray.__ptr[NumQst].shuffle = (row[2][0] == 'Y') ? 1 :
|
||||||
0;
|
0;
|
||||||
|
|
||||||
/* Get question stem (row[3]) */
|
/* Get question stem (row[3]) */
|
||||||
getTestsOut->questionsArray.__ptr[NumRow].stem =
|
getTestsOut->questionsArray.__ptr[NumQst].stem =
|
||||||
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
||||||
Str_Copy (getTestsOut->questionsArray.__ptr[NumRow].stem,row[3],
|
Str_Copy (getTestsOut->questionsArray.__ptr[NumQst].stem,row[3],
|
||||||
Cns_MAX_BYTES_TEXT);
|
Cns_MAX_BYTES_TEXT);
|
||||||
|
|
||||||
/* Get question feedback (row[4]) */
|
/* Get question feedback (row[4]) */
|
||||||
getTestsOut->questionsArray.__ptr[NumRow].feedback =
|
getTestsOut->questionsArray.__ptr[NumQst].feedback =
|
||||||
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
||||||
Str_Copy (getTestsOut->questionsArray.__ptr[NumRow].feedback,row[4],
|
Str_Copy (getTestsOut->questionsArray.__ptr[NumQst].feedback,row[4],
|
||||||
Cns_MAX_BYTES_TEXT);
|
Cns_MAX_BYTES_TEXT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4068,54 +3839,22 @@ static int API_GetTstQuestions (struct soap *soap,
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static int API_GetTstAnswers (struct soap *soap,
|
static int API_GetTstAnswers (struct soap *soap,
|
||||||
long CrsCod,long BeginTime,
|
long CrsCod,time_t BeginTime,
|
||||||
struct swad__getTestsOutput *getTestsOut)
|
struct swad__getTestsOutput *getTestsOut)
|
||||||
{
|
{
|
||||||
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
||||||
MYSQL_RES *mysql_res;
|
MYSQL_RES *mysql_res;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
unsigned NumRow,NumRows;
|
unsigned NumAnss;
|
||||||
|
unsigned NumAns;
|
||||||
unsigned Index;
|
unsigned Index;
|
||||||
|
|
||||||
/***** Get recent test questions from database *****/
|
/***** Get answers to recent test questions from database *****/
|
||||||
NumRows = (unsigned)
|
NumAnss = Qst_DB_GetRecentAnswers (&mysql_res,CrsCod,BeginTime);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get test answers",
|
|
||||||
"SELECT QstCod," // row[0]
|
|
||||||
"AnsInd," // row[1]
|
|
||||||
"Correct," // row[2]
|
|
||||||
"Answer," // row[3]
|
|
||||||
"Feedback" // row[4]
|
|
||||||
" FROM tst_answers"
|
|
||||||
" WHERE QstCod IN "
|
|
||||||
"(SELECT tst_questions.QstCod"
|
|
||||||
" FROM tst_questions,"
|
|
||||||
"tst_question_tags,"
|
|
||||||
"tst_tags"
|
|
||||||
" WHERE tst_questions.CrsCod=%ld"
|
|
||||||
" AND tst_questions.QstCod NOT IN"
|
|
||||||
" (SELECT tst_question_tags.QstCod"
|
|
||||||
" FROM tst_tags,"
|
|
||||||
"tst_question_tags"
|
|
||||||
" WHERE tst_tags.CrsCod=%ld"
|
|
||||||
" AND tst_tags.TagHidden='Y'"
|
|
||||||
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
|
||||||
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
|
||||||
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
|
||||||
" AND tst_tags.CrsCod=%ld"
|
|
||||||
" AND (tst_questions.EditTime>=FROM_UNIXTIME(%ld)"
|
|
||||||
" OR "
|
|
||||||
"tst_tags.ChangeTime>=FROM_UNIXTIME(%ld)))"
|
|
||||||
" ORDER BY QstCod,"
|
|
||||||
"AnsInd",
|
|
||||||
CrsCod,
|
|
||||||
CrsCod,
|
|
||||||
CrsCod,
|
|
||||||
BeginTime,
|
|
||||||
BeginTime);
|
|
||||||
|
|
||||||
getTestsOut->answersArray.__size = (int) NumRows;
|
getTestsOut->answersArray.__size = (int) NumAnss;
|
||||||
|
|
||||||
if (NumRows == 0)
|
if (NumAnss == 0)
|
||||||
getTestsOut->answersArray.__ptr = NULL;
|
getTestsOut->answersArray.__ptr = NULL;
|
||||||
else // Answers found
|
else // Answers found
|
||||||
{
|
{
|
||||||
|
@ -4123,36 +3862,36 @@ static int API_GetTstAnswers (struct soap *soap,
|
||||||
(getTestsOut->answersArray.__size) *
|
(getTestsOut->answersArray.__size) *
|
||||||
sizeof (*(getTestsOut->answersArray.__ptr)));
|
sizeof (*(getTestsOut->answersArray.__ptr)));
|
||||||
|
|
||||||
for (NumRow = 0;
|
for (NumAns = 0;
|
||||||
NumRow < NumRows;
|
NumAns < NumAnss;
|
||||||
NumRow++)
|
NumAns++)
|
||||||
{
|
{
|
||||||
/* Get next question */
|
/* Get next question */
|
||||||
row = mysql_fetch_row (mysql_res);
|
row = mysql_fetch_row (mysql_res);
|
||||||
|
|
||||||
/* Get question code (row[0]) */
|
/* Get question code (row[0]) */
|
||||||
getTestsOut->answersArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
getTestsOut->answersArray.__ptr[NumAns].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
||||||
|
|
||||||
/* Get answer index (row[1]) */
|
/* Get answer index (row[1]) */
|
||||||
if (sscanf (row[1],"%u",&Index) == 1)
|
if (sscanf (row[1],"%u",&Index) == 1)
|
||||||
getTestsOut->answersArray.__ptr[NumRow].answerIndex = (int) Index;
|
getTestsOut->answersArray.__ptr[NumAns].answerIndex = (int) Index;
|
||||||
else
|
else
|
||||||
getTestsOut->answersArray.__ptr[NumRow].answerIndex = 0; // error
|
getTestsOut->answersArray.__ptr[NumAns].answerIndex = 0; // error
|
||||||
|
|
||||||
/* Get correct (row[2]) */
|
/* Get correct (row[2]) */
|
||||||
getTestsOut->answersArray.__ptr[NumRow].correct = (row[2][0] == 'Y') ? 1 :
|
getTestsOut->answersArray.__ptr[NumAns].correct = (row[2][0] == 'Y') ? 1 :
|
||||||
0;
|
0;
|
||||||
|
|
||||||
/* Get answer (row[3]) */
|
/* Get answer (row[3]) */
|
||||||
getTestsOut->answersArray.__ptr[NumRow].answerText =
|
getTestsOut->answersArray.__ptr[NumAns].answerText =
|
||||||
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
||||||
Str_Copy (getTestsOut->answersArray.__ptr[NumRow].answerText,
|
Str_Copy (getTestsOut->answersArray.__ptr[NumAns].answerText,
|
||||||
row[3],Cns_MAX_BYTES_TEXT);
|
row[3],Cns_MAX_BYTES_TEXT);
|
||||||
|
|
||||||
/* Get feedback (row[4]) */
|
/* Get feedback (row[4]) */
|
||||||
getTestsOut->answersArray.__ptr[NumRow].answerFeedback =
|
getTestsOut->answersArray.__ptr[NumAns].answerFeedback =
|
||||||
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
||||||
Str_Copy (getTestsOut->answersArray.__ptr[NumRow].answerFeedback,
|
Str_Copy (getTestsOut->answersArray.__ptr[NumAns].answerFeedback,
|
||||||
row[4],Cns_MAX_BYTES_TEXT);
|
row[4],Cns_MAX_BYTES_TEXT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4168,77 +3907,47 @@ static int API_GetTstAnswers (struct soap *soap,
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static int API_GetTstQuestionTags (struct soap *soap,
|
static int API_GetTstQuestionTags (struct soap *soap,
|
||||||
long CrsCod,long BeginTime,
|
long CrsCod,time_t BeginTime,
|
||||||
struct swad__getTestsOutput *getTestsOut)
|
struct swad__getTestsOutput *getTestsOut)
|
||||||
{
|
{
|
||||||
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
||||||
MYSQL_RES *mysql_res;
|
MYSQL_RES *mysql_res;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
unsigned NumRow,NumRows;
|
unsigned NumQstTags;
|
||||||
|
unsigned NumQstTag;
|
||||||
unsigned Index;
|
unsigned Index;
|
||||||
|
|
||||||
/***** Get recent test questions from database *****/
|
/***** Get recent test questions from database *****/
|
||||||
NumRows = (unsigned)
|
NumQstTags = Tag_DB_GetRecentTags (&mysql_res,CrsCod,BeginTime);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get test question tags",
|
|
||||||
"SELECT QstCod," // row[0]
|
|
||||||
"TagCod," // row[1]
|
|
||||||
"TagInd" // row[2]
|
|
||||||
" FROM tst_question_tags"
|
|
||||||
" WHERE QstCod IN "
|
|
||||||
"(SELECT tst_questions.QstCod"
|
|
||||||
" FROM tst_questions,"
|
|
||||||
"tst_question_tags,"
|
|
||||||
"tst_tags"
|
|
||||||
" WHERE tst_questions.CrsCod=%ld"
|
|
||||||
" AND tst_questions.QstCod NOT IN"
|
|
||||||
" (SELECT tst_question_tags.QstCod"
|
|
||||||
" FROM tst_tags,"
|
|
||||||
"tst_question_tags"
|
|
||||||
" WHERE tst_tags.CrsCod=%ld"
|
|
||||||
" AND tst_tags.TagHidden='Y'"
|
|
||||||
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
|
||||||
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
|
||||||
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
|
||||||
" AND tst_tags.CrsCod=%ld"
|
|
||||||
" AND (tst_questions.EditTime>=FROM_UNIXTIME(%ld)"
|
|
||||||
" OR "
|
|
||||||
"tst_tags.ChangeTime>=FROM_UNIXTIME(%ld)))"
|
|
||||||
" ORDER BY QstCod,"
|
|
||||||
"TagInd",
|
|
||||||
CrsCod,
|
|
||||||
CrsCod,
|
|
||||||
CrsCod,
|
|
||||||
BeginTime,
|
|
||||||
BeginTime);
|
|
||||||
|
|
||||||
getTestsOut->questionTagsArray.__size = (int) NumRows;
|
getTestsOut->questionTagsArray.__size = (int) NumQstTags;
|
||||||
|
|
||||||
if (NumRows == 0)
|
if (NumQstTags == 0)
|
||||||
getTestsOut->questionTagsArray.__ptr = NULL;
|
getTestsOut->questionTagsArray.__ptr = NULL;
|
||||||
else // Answers found
|
else // Questions-tags found
|
||||||
{
|
{
|
||||||
getTestsOut->questionTagsArray.__ptr = soap_malloc (soap,
|
getTestsOut->questionTagsArray.__ptr = soap_malloc (soap,
|
||||||
(getTestsOut->questionTagsArray.__size) *
|
(getTestsOut->questionTagsArray.__size) *
|
||||||
sizeof (*(getTestsOut->questionTagsArray.__ptr)));
|
sizeof (*(getTestsOut->questionTagsArray.__ptr)));
|
||||||
|
|
||||||
for (NumRow = 0;
|
for (NumQstTag = 0;
|
||||||
NumRow < NumRows;
|
NumQstTag < NumQstTags;
|
||||||
NumRow++)
|
NumQstTag++)
|
||||||
{
|
{
|
||||||
/* Get next question */
|
/* Get next question */
|
||||||
row = mysql_fetch_row (mysql_res);
|
row = mysql_fetch_row (mysql_res);
|
||||||
|
|
||||||
/* Get question code (row[0]) */
|
/* Get question code (row[0]) */
|
||||||
getTestsOut->questionTagsArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
getTestsOut->questionTagsArray.__ptr[NumQstTag].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
||||||
|
|
||||||
/* Get tag code (row[1]) */
|
/* Get tag code (row[1]) */
|
||||||
getTestsOut->questionTagsArray.__ptr[NumRow].tagCode = (int) Str_ConvertStrCodToLongCod (row[1]);
|
getTestsOut->questionTagsArray.__ptr[NumQstTag].tagCode = (int) Str_ConvertStrCodToLongCod (row[1]);
|
||||||
|
|
||||||
/* Get tag index (row[2]) */
|
/* Get tag index (row[2]) */
|
||||||
if (sscanf (row[2],"%u",&Index) == 1)
|
if (sscanf (row[2],"%u",&Index) == 1)
|
||||||
getTestsOut->questionTagsArray.__ptr[NumRow].tagIndex = (int) Index;
|
getTestsOut->questionTagsArray.__ptr[NumQstTag].tagIndex = (int) Index;
|
||||||
else
|
else
|
||||||
getTestsOut->questionTagsArray.__ptr[NumRow].tagIndex = 0; // error
|
getTestsOut->questionTagsArray.__ptr[NumQstTag].tagIndex = 0; // error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4499,27 +4208,8 @@ int swad__getGames (struct soap *soap,
|
||||||
"Request forbidden",
|
"Request forbidden",
|
||||||
"Requester must be a student in the course");
|
"Requester must be a student in the course");
|
||||||
|
|
||||||
/***** Query list of games *****/
|
/***** Query list of games available for me *****/
|
||||||
NumGames = (unsigned)
|
NumGames = Gam_DB_GetListAvailableGames (&mysql_res);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get games",
|
|
||||||
"SELECT gam_games.GamCod," // row[0]
|
|
||||||
"gam_games.UsrCod," // row[1]
|
|
||||||
"UNIX_TIMESTAMP(MIN(mch_matches.StartTime)) AS StartTime," // row[2]
|
|
||||||
"UNIX_TIMESTAMP(MAX(mch_matches.EndTime)) AS EndTime," // row[3]
|
|
||||||
"gam_games.MaxGrade," // row[4]
|
|
||||||
"gam_games.Visibility," // row[5]
|
|
||||||
"gam_games.Title," // row[6]
|
|
||||||
"gam_games.Txt" // row[7]
|
|
||||||
" FROM gam_games"
|
|
||||||
" LEFT JOIN mch_matches"
|
|
||||||
" ON gam_games.GamCod=mch_matches.GamCod"
|
|
||||||
" WHERE gam_games.CrsCod=%ld"
|
|
||||||
" AND Hidden='N'"
|
|
||||||
" GROUP BY gam_games.GamCod"
|
|
||||||
" ORDER BY StartTime DESC,"
|
|
||||||
"EndTime DESC,"
|
|
||||||
"gam_games.Title DESC",
|
|
||||||
Gbl.Hierarchy.Crs.CrsCod);
|
|
||||||
getGamesOut->gamesArray.__size =
|
getGamesOut->gamesArray.__size =
|
||||||
getGamesOut->numGames = (int) NumGames;
|
getGamesOut->numGames = (int) NumGames;
|
||||||
|
|
||||||
|
@ -4683,29 +4373,8 @@ int swad__getMatches (struct soap *soap,
|
||||||
"Request forbidden",
|
"Request forbidden",
|
||||||
"Requester must be a student in the course");
|
"Requester must be a student in the course");
|
||||||
|
|
||||||
/***** Query list of matches *****/
|
/***** Query list of matches available for me *****/
|
||||||
NumMatches = (unsigned)
|
NumMatches = Mch_DB_GetAvailableMatchesInGame (&mysql_res,Game.GamCod);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get matches",
|
|
||||||
"SELECT MchCod," // row[ 0]
|
|
||||||
"UsrCod," // row[ 1]
|
|
||||||
"UNIX_TIMESTAMP(StartTime)," // row[ 2]
|
|
||||||
"UNIX_TIMESTAMP(EndTime)," // row[ 3]
|
|
||||||
"Title," // row[ 4]
|
|
||||||
"QstInd" // row[ 5]
|
|
||||||
" FROM mch_matches"
|
|
||||||
" WHERE GamCod=%ld"
|
|
||||||
" AND (MchCod NOT IN"
|
|
||||||
" (SELECT MchCod FROM mch_groups)"
|
|
||||||
" OR"
|
|
||||||
" MchCod IN"
|
|
||||||
" (SELECT mch_groups.MchCod"
|
|
||||||
" FROM mch_groups,"
|
|
||||||
"grp_users"
|
|
||||||
" WHERE grp_users.UsrCod=%ld"
|
|
||||||
" AND mch_groups.GrpCod=grp_users.GrpCod))"
|
|
||||||
" ORDER BY MchCod",
|
|
||||||
Game.GamCod,
|
|
||||||
Gbl.Usrs.Me.UsrDat.UsrCod);
|
|
||||||
getMatchesOut->matchesArray.__size =
|
getMatchesOut->matchesArray.__size =
|
||||||
getMatchesOut->numMatches = (int) NumMatches;
|
getMatchesOut->numMatches = (int) NumMatches;
|
||||||
|
|
||||||
|
@ -5652,36 +5321,8 @@ int swad__getLocation (struct soap *soap,
|
||||||
"Bad MAC",
|
"Bad MAC",
|
||||||
"MAC address format should be 12 hexadecimal digits");
|
"MAC address format should be 12 hexadecimal digits");
|
||||||
|
|
||||||
/***** Get list of locations *****/
|
/***** Get location *****/
|
||||||
NumLocs = (unsigned)
|
NumLocs = Roo_DB_GetLocationByMAC (&mysql_res,MACnum);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get matches",
|
|
||||||
"SELECT ins_instits.InsCod," // row[ 0]
|
|
||||||
"ins_instits.ShortName," // row[ 1]
|
|
||||||
"ins_instits.FullName," // row[ 2]
|
|
||||||
"ctr_centers.CtrCod," // row[ 3]
|
|
||||||
"ctr_centers.ShortName," // row[ 4]
|
|
||||||
"ctr_centers.FullName," // row[ 5]
|
|
||||||
"bld_buildings.BldCod," // row[ 6]
|
|
||||||
"bld_buildings.ShortName," // row[ 7]
|
|
||||||
"bld_buildings.FullName," // row[ 8]
|
|
||||||
"roo_rooms.Floor," // row[ 9]
|
|
||||||
"roo_rooms.RooCod," // row[10]
|
|
||||||
"roo_rooms.ShortName," // row[11]
|
|
||||||
"roo_rooms.FullName" // row[12]
|
|
||||||
" FROM roo_macs,"
|
|
||||||
"roo_rooms,"
|
|
||||||
"bld_buildings,"
|
|
||||||
"ctr_centers,"
|
|
||||||
"ins_instits"
|
|
||||||
" WHERE roo_macs.MAC=%llu"
|
|
||||||
" AND roo_macs.RooCod=roo_rooms.RooCod"
|
|
||||||
" AND roo_rooms.BldCod=bld_buildings.BldCod"
|
|
||||||
" AND bld_buildings.CtrCod=ctr_centers.CtrCod"
|
|
||||||
" AND ctr_centers.InsCod=ins_instits.InsCod"
|
|
||||||
" ORDER BY roo_rooms.Capacity DESC," // Get the biggest room
|
|
||||||
"roo_rooms.ShortName"
|
|
||||||
" LIMIT 1",
|
|
||||||
MACnum);
|
|
||||||
|
|
||||||
API_GetDataOfLocation (soap,
|
API_GetDataOfLocation (soap,
|
||||||
&(getLocationOut->location),
|
&(getLocationOut->location),
|
||||||
|
@ -5769,40 +5410,7 @@ int swad__getLastLocation (struct soap *soap,
|
||||||
if (Roo_DB_CheckIfICanSeeUsrLocation ((long) userCode))
|
if (Roo_DB_CheckIfICanSeeUsrLocation ((long) userCode))
|
||||||
{
|
{
|
||||||
/***** Get list of locations *****/
|
/***** Get list of locations *****/
|
||||||
NumLocs = (unsigned)
|
NumLocs = Roo_DB_GetUsrLastLocation (&mysql_res,(long) userCode);
|
||||||
DB_QuerySELECT (&mysql_res,"can not get matches",
|
|
||||||
"SELECT ins_instits.InsCod," // row[ 0]
|
|
||||||
"ins_instits.ShortName," // row[ 1]
|
|
||||||
"ins_instits.FullName," // row[ 2]
|
|
||||||
"ctr_centers.CtrCod," // row[ 3]
|
|
||||||
"ctr_centers.ShortName," // row[ 4]
|
|
||||||
"ctr_centers.FullName," // row[ 5]
|
|
||||||
"bld_buildings.BldCod," // row[ 6]
|
|
||||||
"bld_buildings.ShortName," // row[ 7]
|
|
||||||
"bld_buildings.FullName," // row[ 8]
|
|
||||||
"roo_rooms.Floor," // row[ 9]
|
|
||||||
"roo_rooms.RooCod," // row[10]
|
|
||||||
"roo_rooms.ShortName," // row[11]
|
|
||||||
"roo_rooms.FullName," // row[12]
|
|
||||||
"UNIX_TIMESTAMP(roo_check_in.CheckInTime)" // row[13]
|
|
||||||
" FROM roo_check_in,"
|
|
||||||
"roo_rooms,"
|
|
||||||
"bld_buildings,"
|
|
||||||
"ctr_centers,"
|
|
||||||
"ins_instits"
|
|
||||||
" WHERE roo_check_in.UsrCod=%d"
|
|
||||||
" AND roo_check_in.ChkCod="
|
|
||||||
"(SELECT ChkCod"
|
|
||||||
" FROM roo_check_in"
|
|
||||||
" WHERE UsrCod=%d"
|
|
||||||
" ORDER BY ChkCod DESC"
|
|
||||||
" LIMIT 1)" // Faster than SELECT MAX
|
|
||||||
" AND roo_check_in.RooCod=roo_rooms.RooCod"
|
|
||||||
" AND roo_rooms.BldCod=bld_buildings.BldCod"
|
|
||||||
" AND bld_buildings.CtrCod=ctr_centers.CtrCod"
|
|
||||||
" AND ctr_centers.InsCod=ins_instits.InsCod",
|
|
||||||
userCode,
|
|
||||||
userCode);
|
|
||||||
API_GetDataOfLocation (soap,
|
API_GetDataOfLocation (soap,
|
||||||
&(getLastLocationOut->location),
|
&(getLastLocationOut->location),
|
||||||
&(getLastLocationOut->checkinTime), // Get check in time
|
&(getLastLocationOut->checkinTime), // Get check in time
|
||||||
|
|
|
@ -25,7 +25,9 @@
|
||||||
/********************************** Headers **********************************/
|
/********************************** Headers **********************************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE // For asprintf
|
||||||
#include <mysql/mysql.h> // To access MySQL databases
|
#include <mysql/mysql.h> // To access MySQL databases
|
||||||
|
#include <stdio.h> // For asprintf
|
||||||
|
|
||||||
#include "swad_attendance.h"
|
#include "swad_attendance.h"
|
||||||
#include "swad_attendance_database.h"
|
#include "swad_attendance_database.h"
|
||||||
|
@ -473,6 +475,91 @@ unsigned Att_DB_GetPresentAndComments (MYSQL_RES **mysql_res,long AttCod,long Us
|
||||||
UsrCod);
|
UsrCod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/*********** Return a list with the users in an attendance event *************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
unsigned Att_DB_GetListUsrsInAttEvent (MYSQL_RES **mysql_res,
|
||||||
|
long AttCod,bool AttEventIsAsociatedToGrps)
|
||||||
|
{
|
||||||
|
char *SubQuery;
|
||||||
|
unsigned NumUsrs;
|
||||||
|
|
||||||
|
/***** Query list of attendance users *****/
|
||||||
|
if (AttEventIsAsociatedToGrps)
|
||||||
|
{
|
||||||
|
// Event for one or more groups
|
||||||
|
// Subquery: list of users in groups of this attendance event...
|
||||||
|
// ...who have no entry in attendance list of users
|
||||||
|
if (asprintf (&SubQuery,"SELECT DISTINCT "
|
||||||
|
"grp_users.UsrCod AS UsrCod," // row[0]
|
||||||
|
"'N' AS Present" // row[1]
|
||||||
|
" FROM att_groups,"
|
||||||
|
"grp_groups,"
|
||||||
|
"grp_types,"
|
||||||
|
"crs_users,"
|
||||||
|
"grp_users"
|
||||||
|
" WHERE att_groups.AttCod=%ld"
|
||||||
|
" AND att_groups.GrpCod=grp_groups.GrpCod"
|
||||||
|
" AND grp_groups.GrpTypCod=grp_types.GrpTypCod"
|
||||||
|
" AND grp_types.CrsCod=crs_users.CrsCod"
|
||||||
|
" AND crs_users.Role=%u"
|
||||||
|
" AND crs_users.UsrCod=grp_users.UsrCod"
|
||||||
|
" AND grp_users.GrpCod=att_groups.GrpCod"
|
||||||
|
" AND grp_users.UsrCod NOT IN"
|
||||||
|
" (SELECT UsrCod"
|
||||||
|
" FROM att_users"
|
||||||
|
" WHERE AttCod=%ld)",
|
||||||
|
AttCod,
|
||||||
|
(unsigned) Rol_STD,
|
||||||
|
AttCod) < 0)
|
||||||
|
Err_NotEnoughMemoryExit ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Event for the whole course
|
||||||
|
// Subquery: list of users in the course of this attendance event...
|
||||||
|
// ...who have no entry in attendance list of users
|
||||||
|
if (asprintf (&SubQuery,"SELECT crs_users.UsrCod AS UsrCod," // row[0]
|
||||||
|
"'N' AS Present" // row[1]
|
||||||
|
" FROM att_events,"
|
||||||
|
"crs_users"
|
||||||
|
" WHERE att_events.AttCod=%ld"
|
||||||
|
" AND att_events.CrsCod=crs_users.CrsCod"
|
||||||
|
" AND crs_users.Role=%u"
|
||||||
|
" AND crs_users.UsrCod NOT IN"
|
||||||
|
" (SELECT UsrCod"
|
||||||
|
" FROM att_users"
|
||||||
|
" WHERE AttCod=%ld)",
|
||||||
|
AttCod,
|
||||||
|
(unsigned) Rol_STD,
|
||||||
|
AttCod) < 0)
|
||||||
|
Err_NotEnoughMemoryExit ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query: list of users in attendance list + rest of users (subquery)
|
||||||
|
NumUsrs = (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get users in an attendance event",
|
||||||
|
"SELECT u.UsrCod," // row[0]
|
||||||
|
"u.Present" // row[1]
|
||||||
|
" FROM (SELECT UsrCod,"
|
||||||
|
"Present"
|
||||||
|
" FROM att_users"
|
||||||
|
" WHERE AttCod=%ld"
|
||||||
|
" UNION %s) AS u,"
|
||||||
|
"usr_data"
|
||||||
|
" WHERE u.UsrCod=usr_data.UsrCod"
|
||||||
|
" ORDER BY usr_data.Surname1,"
|
||||||
|
"usr_data.Surname2,"
|
||||||
|
"usr_data.FirstName",
|
||||||
|
AttCod,
|
||||||
|
SubQuery);
|
||||||
|
|
||||||
|
free (SubQuery);
|
||||||
|
|
||||||
|
return NumUsrs;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/********* Register a user in an attendance event changing comments **********/
|
/********* Register a user in an attendance event changing comments **********/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -67,6 +67,8 @@ unsigned Att_DB_GetNumStdsTotalWhoAreInAttEvent (long AttCod);
|
||||||
unsigned Att_DB_GetNumStdsFromListWhoAreInAttEvent (long AttCod,const char *SubQueryUsrs);
|
unsigned Att_DB_GetNumStdsFromListWhoAreInAttEvent (long AttCod,const char *SubQueryUsrs);
|
||||||
bool Att_DB_CheckIfUsrIsInTableAttUsr (long AttCod,long UsrCod,bool *Present);
|
bool Att_DB_CheckIfUsrIsInTableAttUsr (long AttCod,long UsrCod,bool *Present);
|
||||||
unsigned Att_DB_GetPresentAndComments (MYSQL_RES **mysql_res,long AttCod,long UsrCod);
|
unsigned Att_DB_GetPresentAndComments (MYSQL_RES **mysql_res,long AttCod,long UsrCod);
|
||||||
|
unsigned Att_DB_GetListUsrsInAttEvent (MYSQL_RES **mysql_res,
|
||||||
|
long AttCod,bool AttEventIsAsociatedToGrps);
|
||||||
void Att_DB_RegUsrInAttEventChangingComments (long AttCod,long UsrCod,
|
void Att_DB_RegUsrInAttEventChangingComments (long AttCod,long UsrCod,
|
||||||
bool Present,
|
bool Present,
|
||||||
const char *CommentStd,
|
const char *CommentStd,
|
||||||
|
|
|
@ -602,13 +602,14 @@ TODO: FIX BUG, URGENT! En las fechas como par
|
||||||
|
|
||||||
TODO: En las encuestas, que los estudiantes no puedan ver los resultados hasta que no finalice el plazo.
|
TODO: En las encuestas, que los estudiantes no puedan ver los resultados hasta que no finalice el plazo.
|
||||||
*/
|
*/
|
||||||
#define Log_PLATFORM_VERSION "SWAD 21.54.3 (2021-11-08)"
|
#define Log_PLATFORM_VERSION "SWAD 21.54.4 (2021-11-09)"
|
||||||
#define CSS_FILE "swad20.45.css"
|
#define CSS_FILE "swad20.45.css"
|
||||||
#define JS_FILE "swad20.69.1.js"
|
#define JS_FILE "swad20.69.1.js"
|
||||||
/*
|
/*
|
||||||
TODO: Rename CENTRE to CENTER in help wiki.
|
TODO: Rename CENTRE to CENTER in help wiki.
|
||||||
TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams
|
TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams
|
||||||
|
|
||||||
|
Version 21.54.4: Nov 09, 2021 Queries moved from API module to database modules. (322222 lines)
|
||||||
Version 21.54.3: Nov 08, 2021 Queries moved from API module to database modules. (322095 lines)
|
Version 21.54.3: Nov 08, 2021 Queries moved from API module to database modules. (322095 lines)
|
||||||
Version 21.54.2: Nov 08, 2021 Queries moved to module swad_user_database and other modules. (322054 lines)
|
Version 21.54.2: Nov 08, 2021 Queries moved to module swad_user_database and other modules. (322054 lines)
|
||||||
Version 21.54.1: Nov 08, 2021 Queries moved to module swad_user_database. (322060 lines)
|
Version 21.54.1: Nov 08, 2021 Queries moved to module swad_user_database. (322060 lines)
|
||||||
|
|
|
@ -187,6 +187,34 @@ unsigned Gam_DB_GetListGames (MYSQL_RES **mysql_res,Gam_Order_t SelectedOrder)
|
||||||
return NumGames;
|
return NumGames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/*************** Get data of all games in the current course *****************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
unsigned Gam_DB_GetListAvailableGames (MYSQL_RES **mysql_res)
|
||||||
|
{
|
||||||
|
return (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get games",
|
||||||
|
"SELECT gam_games.GamCod," // row[0]
|
||||||
|
"gam_games.UsrCod," // row[1]
|
||||||
|
"UNIX_TIMESTAMP(MIN(mch_matches.StartTime)) AS StartTime," // row[2]
|
||||||
|
"UNIX_TIMESTAMP(MAX(mch_matches.EndTime)) AS EndTime," // row[3]
|
||||||
|
"gam_games.MaxGrade," // row[4]
|
||||||
|
"gam_games.Visibility," // row[5]
|
||||||
|
"gam_games.Title," // row[6]
|
||||||
|
"gam_games.Txt" // row[7]
|
||||||
|
" FROM gam_games"
|
||||||
|
" LEFT JOIN mch_matches"
|
||||||
|
" ON gam_games.GamCod=mch_matches.GamCod"
|
||||||
|
" WHERE gam_games.CrsCod=%ld"
|
||||||
|
" AND Hidden='N'"
|
||||||
|
" GROUP BY gam_games.GamCod"
|
||||||
|
" ORDER BY StartTime DESC,"
|
||||||
|
"EndTime DESC,"
|
||||||
|
"gam_games.Title DESC",
|
||||||
|
Gbl.Hierarchy.Crs.CrsCod);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/********************** Get game data using its code *************************/
|
/********************** Get game data using its code *************************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
/********************************* Headers ***********************************/
|
/********************************* Headers ***********************************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#include "swad_game.h"
|
||||||
#include "swad_hierarchy_level.h"
|
#include "swad_hierarchy_level.h"
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -43,6 +44,7 @@ void Gam_DB_UpdateGame (const struct Gam_Game *Game,const char *Txt);
|
||||||
void Gam_DB_HideOrUnhideGame (long GamCod,bool Hide);
|
void Gam_DB_HideOrUnhideGame (long GamCod,bool Hide);
|
||||||
|
|
||||||
unsigned Gam_DB_GetListGames (MYSQL_RES **mysql_res,Gam_Order_t SelectedOrder);
|
unsigned Gam_DB_GetListGames (MYSQL_RES **mysql_res,Gam_Order_t SelectedOrder);
|
||||||
|
unsigned Gam_DB_GetListAvailableGames (MYSQL_RES **mysql_res);
|
||||||
unsigned Gam_DB_GetDataOfGameByCod (MYSQL_RES **mysql_res,long GamCod);
|
unsigned Gam_DB_GetDataOfGameByCod (MYSQL_RES **mysql_res,long GamCod);
|
||||||
void Gam_DB_GetGameTxt (long GamCod,char Txt[Cns_MAX_BYTES_TEXT + 1]);
|
void Gam_DB_GetGameTxt (long GamCod,char Txt[Cns_MAX_BYTES_TEXT + 1]);
|
||||||
bool Gam_DB_CheckIfSimilarGameExists (const struct Gam_Game *Game);
|
bool Gam_DB_CheckIfSimilarGameExists (const struct Gam_Game *Game);
|
||||||
|
|
|
@ -274,7 +274,7 @@ void Mch_ListMatches (struct Gam_Games *Games,
|
||||||
unsigned NumMatches;
|
unsigned NumMatches;
|
||||||
|
|
||||||
/***** Get data of matches from database *****/
|
/***** Get data of matches from database *****/
|
||||||
NumMatches = Mch_DB_GetMatches (&mysql_res,Game->GamCod);
|
NumMatches = Mch_DB_GetMatchesInGame (&mysql_res,Game->GamCod);
|
||||||
|
|
||||||
/***** Begin box *****/
|
/***** Begin box *****/
|
||||||
Games->GamCod = Game->GamCod;
|
Games->GamCod = Game->GamCod;
|
||||||
|
|
|
@ -228,7 +228,7 @@ unsigned Mch_DB_GetStartEndMatchesInGame (MYSQL_RES **mysql_res,long GamCod)
|
||||||
/************************* Get the matches of a game *************************/
|
/************************* Get the matches of a game *************************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
unsigned Mch_DB_GetMatches (MYSQL_RES **mysql_res,long GamCod)
|
unsigned Mch_DB_GetMatchesInGame (MYSQL_RES **mysql_res,long GamCod)
|
||||||
{
|
{
|
||||||
char *SubQuery;
|
char *SubQuery;
|
||||||
|
|
||||||
|
@ -279,6 +279,36 @@ unsigned Mch_DB_GetMatches (MYSQL_RES **mysql_res,long GamCod)
|
||||||
free (SubQuery);
|
free (SubQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/********************* Get available matches in a game ***********************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
unsigned Mch_DB_GetAvailableMatchesInGame (MYSQL_RES **mysql_res,long GamCod)
|
||||||
|
{
|
||||||
|
return (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get matches",
|
||||||
|
"SELECT MchCod," // row[ 0]
|
||||||
|
"UsrCod," // row[ 1]
|
||||||
|
"UNIX_TIMESTAMP(StartTime)," // row[ 2]
|
||||||
|
"UNIX_TIMESTAMP(EndTime)," // row[ 3]
|
||||||
|
"Title," // row[ 4]
|
||||||
|
"QstInd" // row[ 5]
|
||||||
|
" FROM mch_matches"
|
||||||
|
" WHERE GamCod=%ld"
|
||||||
|
" AND (MchCod NOT IN"
|
||||||
|
" (SELECT MchCod FROM mch_groups)"
|
||||||
|
" OR"
|
||||||
|
" MchCod IN"
|
||||||
|
" (SELECT mch_groups.MchCod"
|
||||||
|
" FROM mch_groups,"
|
||||||
|
"grp_users"
|
||||||
|
" WHERE grp_users.UsrCod=%ld"
|
||||||
|
" AND mch_groups.GrpCod=grp_users.GrpCod))"
|
||||||
|
" ORDER BY MchCod",
|
||||||
|
GamCod,
|
||||||
|
Gbl.Usrs.Me.UsrDat.UsrCod);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/****************** Get parameter with what is being shown *******************/
|
/****************** Get parameter with what is being shown *******************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -46,7 +46,8 @@ void Mch_DB_UpdateVisResultsMchUsr (long MchCod,bool ShowUsrResults);
|
||||||
|
|
||||||
unsigned Mch_DB_GetDataOfMatchByCod (MYSQL_RES **mysql_res,long MchCod);
|
unsigned Mch_DB_GetDataOfMatchByCod (MYSQL_RES **mysql_res,long MchCod);
|
||||||
unsigned Mch_DB_GetStartEndMatchesInGame (MYSQL_RES **mysql_res,long GamCod);
|
unsigned Mch_DB_GetStartEndMatchesInGame (MYSQL_RES **mysql_res,long GamCod);
|
||||||
unsigned Mch_DB_GetMatches (MYSQL_RES **mysql_res,long GamCod);
|
unsigned Mch_DB_GetMatchesInGame (MYSQL_RES **mysql_res,long GamCod);
|
||||||
|
unsigned Mch_DB_GetAvailableMatchesInGame (MYSQL_RES **mysql_res,long GamCod);
|
||||||
Mch_Showing_t Mch_DB_GetShowingFromStr (const char *Str);
|
Mch_Showing_t Mch_DB_GetShowingFromStr (const char *Str);
|
||||||
unsigned Mch_DB_GetNumMchsInGame (long GamCod);
|
unsigned Mch_DB_GetNumMchsInGame (long GamCod);
|
||||||
unsigned Mch_DB_GetNumUnfinishedMchsInGame (long GamCod);
|
unsigned Mch_DB_GetNumUnfinishedMchsInGame (long GamCod);
|
||||||
|
|
|
@ -805,6 +805,130 @@ bool Msg_DB_CheckIfRcvMsgIsDeletedForAllItsRecipients (long MsgCod)
|
||||||
// in table of received messages undeleted
|
// in table of received messages undeleted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/************************* Get the sender of a message ***********************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
long Msg_DB_GetSender (long MsgCod)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
DB_QuerySELECTCode ("can not get sender",
|
||||||
|
"SELECT UsrCod"
|
||||||
|
" FROM msg_snt"
|
||||||
|
" WHERE MsgCod=%ld"
|
||||||
|
" UNION "
|
||||||
|
"SELECT UsrCod"
|
||||||
|
" FROM msg_snt_deleted"
|
||||||
|
" WHERE MsgCod=%ld",
|
||||||
|
MsgCod,
|
||||||
|
MsgCod);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/************** Check if a message has been really received by me ************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
bool Msg_DB_CheckIfMsgHasBeenReceivedByMe (long MsgCod)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
DB_QueryEXISTS ("can not check original message",
|
||||||
|
"SELECT EXISTS"
|
||||||
|
"(SELECT *"
|
||||||
|
" FROM msg_rcv"
|
||||||
|
" WHERE UsrCod=%ld"
|
||||||
|
" AND MsgCod=%ld"
|
||||||
|
" UNION"
|
||||||
|
" SELECT *"
|
||||||
|
" FROM msg_rcv_deleted"
|
||||||
|
" WHERE UsrCod=%ld"
|
||||||
|
" AND MsgCod=%ld)",
|
||||||
|
Gbl.Usrs.Me.UsrDat.UsrCod,MsgCod,
|
||||||
|
Gbl.Usrs.Me.UsrDat.UsrCod,MsgCod);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/***************************** Get recipients' codes *************************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
#define Msg_DB_MAX_BYTES_QUERY_RECIPIENTS (16 * 1024 - 1)
|
||||||
|
|
||||||
|
unsigned Msg_DB_GetRecipientsCods (MYSQL_RES **mysql_res,
|
||||||
|
long ReplyUsrCod,const char *ListRecipients)
|
||||||
|
{
|
||||||
|
char *Query = NULL;
|
||||||
|
const char *Ptr;
|
||||||
|
char Nick[Nck_MAX_BYTES_NICK_WITH_ARROBA + 1];
|
||||||
|
bool FirstNickname = true;
|
||||||
|
bool ThereAreNicknames = false;
|
||||||
|
unsigned NumUsrs = 0;
|
||||||
|
|
||||||
|
/***** Allocate space for query *****/
|
||||||
|
if ((Query = malloc (Msg_DB_MAX_BYTES_QUERY_RECIPIENTS + 1)) == NULL)
|
||||||
|
Err_NotEnoughMemoryExit ();
|
||||||
|
|
||||||
|
/***** Build query for recipients from database *****/
|
||||||
|
if (ReplyUsrCod > 0)
|
||||||
|
snprintf (Query,Msg_DB_MAX_BYTES_QUERY_RECIPIENTS + 1,
|
||||||
|
"SELECT UsrCod"
|
||||||
|
" FROM usr_data"
|
||||||
|
" WHERE UsrCod=%ld",
|
||||||
|
ReplyUsrCod);
|
||||||
|
else
|
||||||
|
Query[0] = '\0';
|
||||||
|
|
||||||
|
/***** Loop over recipients' nicknames building query *****/
|
||||||
|
Ptr = ListRecipients;
|
||||||
|
while (*Ptr)
|
||||||
|
{
|
||||||
|
/* Find next string in text until comma (leading and trailing spaces are removed) */
|
||||||
|
Str_GetNextStringUntilComma (&Ptr,Nick,sizeof (Nick) - 1); // With leading arrobas
|
||||||
|
|
||||||
|
/* Check if string is a valid nickname */
|
||||||
|
if (Nck_CheckIfNickWithArrIsValid (Nick)) // String is a nickname (with leading arrobas)?
|
||||||
|
{
|
||||||
|
Str_RemoveLeadingArrobas (Nick);
|
||||||
|
|
||||||
|
/* Check for overflow in query */
|
||||||
|
if (strlen (Query) + Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 32 >
|
||||||
|
Msg_DB_MAX_BYTES_QUERY_RECIPIENTS)
|
||||||
|
Err_NotEnoughMemoryExit ();
|
||||||
|
|
||||||
|
/* Add this nickname to query */
|
||||||
|
if (FirstNickname)
|
||||||
|
{
|
||||||
|
if (ReplyUsrCod > 0)
|
||||||
|
Str_Concat (Query," UNION ",Msg_DB_MAX_BYTES_QUERY_RECIPIENTS);
|
||||||
|
Str_Concat (Query,"SELECT UsrCod"
|
||||||
|
" FROM usr_nicknames"
|
||||||
|
" WHERE Nickname IN ('",
|
||||||
|
Msg_DB_MAX_BYTES_QUERY_RECIPIENTS);
|
||||||
|
FirstNickname = false;
|
||||||
|
ThereAreNicknames = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Str_Concat (Query,",'",Msg_DB_MAX_BYTES_QUERY_RECIPIENTS);
|
||||||
|
Str_Concat (Query,Nick,Msg_DB_MAX_BYTES_QUERY_RECIPIENTS); // Leading arrobas already removed
|
||||||
|
Str_Concat (Query,"'",Msg_DB_MAX_BYTES_QUERY_RECIPIENTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ThereAreNicknames)
|
||||||
|
Str_Concat (Query,")",Msg_DB_MAX_BYTES_QUERY_RECIPIENTS);
|
||||||
|
|
||||||
|
if (ReplyUsrCod > 0 || ThereAreNicknames) // There are a recipient to reply or nicknames in list
|
||||||
|
{
|
||||||
|
/***** Get users *****/
|
||||||
|
NumUsrs = (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get users",
|
||||||
|
"%s",
|
||||||
|
Query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***** Free space for query *****/
|
||||||
|
free (Query);
|
||||||
|
|
||||||
|
return NumUsrs;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/************ Get number of recipients of a message from database ************/
|
/************ Get number of recipients of a message from database ************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <mysql/mysql.h> // To access MySQL databases
|
#include <mysql/mysql.h> // To access MySQL databases
|
||||||
|
|
||||||
#include "swad_hierarchy_level.h"
|
#include "swad_hierarchy_level.h"
|
||||||
|
#include "swad_message.h"
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/****************************** Public constants *****************************/
|
/****************************** Public constants *****************************/
|
||||||
|
@ -76,6 +77,10 @@ void Msg_DB_GetStatusOfRcvMsg (long MsgCod,
|
||||||
bool *Open,bool *Replied,bool *Expanded);
|
bool *Open,bool *Replied,bool *Expanded);
|
||||||
bool Msg_DB_CheckIfSntMsgIsDeleted (long MsgCod);
|
bool Msg_DB_CheckIfSntMsgIsDeleted (long MsgCod);
|
||||||
bool Msg_DB_CheckIfRcvMsgIsDeletedForAllItsRecipients (long MsgCod);
|
bool Msg_DB_CheckIfRcvMsgIsDeletedForAllItsRecipients (long MsgCod);
|
||||||
|
long Msg_DB_GetSender (long MsgCod);
|
||||||
|
bool Msg_DB_CheckIfMsgHasBeenReceivedByMe (long MsgCod);
|
||||||
|
unsigned Msg_DB_GetRecipientsCods (MYSQL_RES **mysql_res,
|
||||||
|
long ReplyUsrCod,const char *ListRecipients);
|
||||||
unsigned Msg_DB_GetNumRecipients (long MsgCod);
|
unsigned Msg_DB_GetNumRecipients (long MsgCod);
|
||||||
unsigned Msg_DB_GetKnownRecipients (MYSQL_RES **mysql_res,long MsgCod);
|
unsigned Msg_DB_GetKnownRecipients (MYSQL_RES **mysql_res,long MsgCod);
|
||||||
unsigned Msg_DB_GetNumSntMsgs (HieLvl_Level_t Scope,Msg_Status_t MsgStatus);
|
unsigned Msg_DB_GetNumSntMsgs (HieLvl_Level_t Scope,Msg_Status_t MsgStatus);
|
||||||
|
|
|
@ -378,6 +378,33 @@ unsigned Ntf_DB_GetMyNotifications (MYSQL_RES **mysql_res,bool AllNotifications)
|
||||||
SubQuery);
|
SubQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/************************* Get my recent notifications ***********************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
unsigned Ntf_DB_GetMyRecentNotifications (MYSQL_RES **mysql_res,time_t BeginTime)
|
||||||
|
{
|
||||||
|
return (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get user's notifications",
|
||||||
|
"SELECT NtfCod," // row[0]
|
||||||
|
"NotifyEvent," // row[1]
|
||||||
|
"UNIX_TIMESTAMP(TimeNotif)," // row[2]
|
||||||
|
"FromUsrCod," // row[3]
|
||||||
|
"InsCod," // row[4]
|
||||||
|
"CtrCod," // row[5]
|
||||||
|
"DegCod," // row[6]
|
||||||
|
"CrsCod," // row[7]
|
||||||
|
"Cod," // row[8]
|
||||||
|
"Status" // row[9]
|
||||||
|
" FROM ntf_notifications"
|
||||||
|
" WHERE ToUsrCod=%ld"
|
||||||
|
" AND TimeNotif>=FROM_UNIXTIME(%ld)"
|
||||||
|
" ORDER BY TimeNotif DESC",
|
||||||
|
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||||
|
(long) BeginTime);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/******************* Get pending notifications to a user *********************/
|
/******************* Get pending notifications to a user *********************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -65,6 +65,7 @@ unsigned Ntf_DB_GetNumNotifSent (MYSQL_RES **mysql_res,
|
||||||
long DegCod,long CrsCod,
|
long DegCod,long CrsCod,
|
||||||
Ntf_NotifyEvent_t NotifyEvent);
|
Ntf_NotifyEvent_t NotifyEvent);
|
||||||
unsigned Ntf_DB_GetMyNotifications (MYSQL_RES **mysql_res,bool AllNotifications);
|
unsigned Ntf_DB_GetMyNotifications (MYSQL_RES **mysql_res,bool AllNotifications);
|
||||||
|
unsigned Ntf_DB_GetMyRecentNotifications (MYSQL_RES **mysql_res,time_t BeginTime);
|
||||||
unsigned Ntf_DB_GetPendingNtfsToUsr (MYSQL_RES **mysql_res,long ToUsrCod);
|
unsigned Ntf_DB_GetPendingNtfsToUsr (MYSQL_RES **mysql_res,long ToUsrCod);
|
||||||
unsigned Ntf_DB_GetNumAllMyUnseenNtfs (void);
|
unsigned Ntf_DB_GetNumAllMyUnseenNtfs (void);
|
||||||
unsigned Ntf_DB_GetNumMyNewUnseenNtfs (void);
|
unsigned Ntf_DB_GetNumMyNewUnseenNtfs (void);
|
||||||
|
|
|
@ -568,6 +568,37 @@ unsigned Qst_DB_GetTrivialQst (MYSQL_RES **mysql_res,
|
||||||
return NumQsts;
|
return NumQsts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/** Get number of visible test questions from database giving a course code **/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
unsigned Qst_DB_GetNumQstsInCrs (long CrsCod)
|
||||||
|
{
|
||||||
|
/***** Get number of questions *****/
|
||||||
|
// Reject questions with any tag hidden
|
||||||
|
// Select only questions with tags
|
||||||
|
return (unsigned)
|
||||||
|
DB_QueryCOUNT ("can not get number of test questions",
|
||||||
|
"SELECT COUNT(*)"
|
||||||
|
" FROM tst_questions,"
|
||||||
|
"tst_question_tags,"
|
||||||
|
"tst_tags"
|
||||||
|
" WHERE tst_questions.CrsCod=%ld"
|
||||||
|
" AND tst_questions.QstCod NOT IN"
|
||||||
|
" (SELECT tst_question_tags.QstCod"
|
||||||
|
" FROM tst_tags,"
|
||||||
|
"tst_question_tags"
|
||||||
|
" WHERE tst_tags.CrsCod=%ld"
|
||||||
|
" AND tst_tags.TagHidden='Y'"
|
||||||
|
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
||||||
|
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
||||||
|
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
||||||
|
" AND tst_tags.CrsCod=%ld",
|
||||||
|
CrsCod,
|
||||||
|
CrsCod,
|
||||||
|
CrsCod);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/*********************** Get number of test questions ************************/
|
/*********************** Get number of test questions ************************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -1112,6 +1143,90 @@ unsigned Qst_DB_GetNumCrssWithPluggableQsts (HieLvl_Level_t Scope,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/******* Get recent test questions from database giving a course code ********/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
unsigned Qst_DB_GetRecentQuestions (MYSQL_RES **mysql_res,
|
||||||
|
long CrsCod,time_t BeginTime)
|
||||||
|
{
|
||||||
|
// DISTINCT is necessary to not repeat questions
|
||||||
|
return (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get test questions",
|
||||||
|
"SELECT DISTINCT "
|
||||||
|
"tst_questions.QstCod," // row[0]
|
||||||
|
"tst_questions.AnsType," // row[1]
|
||||||
|
"tst_questions.Shuffle," // row[2]
|
||||||
|
"tst_questions.Stem," // row[3]
|
||||||
|
"tst_questions.Feedback" // row[4]
|
||||||
|
" FROM tst_questions,"
|
||||||
|
"tst_question_tags,"
|
||||||
|
"tst_tags"
|
||||||
|
" WHERE tst_questions.CrsCod=%ld"
|
||||||
|
" AND tst_questions.QstCod NOT IN"
|
||||||
|
" (SELECT tst_question_tags.QstCod"
|
||||||
|
" FROM tst_tags,"
|
||||||
|
"tst_question_tags"
|
||||||
|
" WHERE tst_tags.CrsCod=%ld"
|
||||||
|
" AND tst_tags.TagHidden='Y'"
|
||||||
|
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
||||||
|
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
||||||
|
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
||||||
|
" AND tst_tags.CrsCod=%ld"
|
||||||
|
" AND (tst_questions.EditTime>=FROM_UNIXTIME(%ld)"
|
||||||
|
" OR "
|
||||||
|
"tst_tags.ChangeTime>=FROM_UNIXTIME(%ld))"
|
||||||
|
" ORDER BY QstCod",
|
||||||
|
CrsCod,
|
||||||
|
CrsCod,
|
||||||
|
CrsCod,
|
||||||
|
(long) BeginTime,
|
||||||
|
(long) BeginTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/** Get answers of recent test questions from database giving a course code **/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
unsigned Qst_DB_GetRecentAnswers (MYSQL_RES **mysql_res,
|
||||||
|
long CrsCod,time_t BeginTime)
|
||||||
|
{
|
||||||
|
return (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get test answers",
|
||||||
|
"SELECT QstCod," // row[0]
|
||||||
|
"AnsInd," // row[1]
|
||||||
|
"Correct," // row[2]
|
||||||
|
"Answer," // row[3]
|
||||||
|
"Feedback" // row[4]
|
||||||
|
" FROM tst_answers"
|
||||||
|
" WHERE QstCod IN "
|
||||||
|
"(SELECT tst_questions.QstCod"
|
||||||
|
" FROM tst_questions,"
|
||||||
|
"tst_question_tags,"
|
||||||
|
"tst_tags"
|
||||||
|
" WHERE tst_questions.CrsCod=%ld"
|
||||||
|
" AND tst_questions.QstCod NOT IN"
|
||||||
|
" (SELECT tst_question_tags.QstCod"
|
||||||
|
" FROM tst_tags,"
|
||||||
|
"tst_question_tags"
|
||||||
|
" WHERE tst_tags.CrsCod=%ld"
|
||||||
|
" AND tst_tags.TagHidden='Y'"
|
||||||
|
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
||||||
|
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
||||||
|
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
||||||
|
" AND tst_tags.CrsCod=%ld"
|
||||||
|
" AND (tst_questions.EditTime>=FROM_UNIXTIME(%ld)"
|
||||||
|
" OR "
|
||||||
|
"tst_tags.ChangeTime>=FROM_UNIXTIME(%ld)))"
|
||||||
|
" ORDER BY QstCod,"
|
||||||
|
"AnsInd",
|
||||||
|
CrsCod,
|
||||||
|
CrsCod,
|
||||||
|
CrsCod,
|
||||||
|
(long) BeginTime,
|
||||||
|
(long) BeginTime);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/****************** Get data of a question from database *********************/
|
/****************** Get data of a question from database *********************/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -57,6 +57,7 @@ unsigned Qst_DB_GetQstsForNewTestPrint (MYSQL_RES **mysql_res,
|
||||||
unsigned Qst_DB_GetTrivialQst (MYSQL_RES **mysql_res,
|
unsigned Qst_DB_GetTrivialQst (MYSQL_RES **mysql_res,
|
||||||
char DegreesStr[API_MAX_BYTES_DEGREES_STR + 1],
|
char DegreesStr[API_MAX_BYTES_DEGREES_STR + 1],
|
||||||
float lowerScore,float upperScore);
|
float lowerScore,float upperScore);
|
||||||
|
unsigned Qst_DB_GetNumQstsInCrs (long CrsCod);
|
||||||
unsigned Qst_DB_GetNumQsts (MYSQL_RES **mysql_res,
|
unsigned Qst_DB_GetNumQsts (MYSQL_RES **mysql_res,
|
||||||
HieLvl_Level_t Scope,Qst_AnswerType_t AnsType);
|
HieLvl_Level_t Scope,Qst_AnswerType_t AnsType);
|
||||||
unsigned Qst_DB_GetNumCrssWithQsts (HieLvl_Level_t Scope,
|
unsigned Qst_DB_GetNumCrssWithQsts (HieLvl_Level_t Scope,
|
||||||
|
@ -64,6 +65,11 @@ unsigned Qst_DB_GetNumCrssWithQsts (HieLvl_Level_t Scope,
|
||||||
unsigned Qst_DB_GetNumCrssWithPluggableQsts (HieLvl_Level_t Scope,
|
unsigned Qst_DB_GetNumCrssWithPluggableQsts (HieLvl_Level_t Scope,
|
||||||
Qst_AnswerType_t AnsType);
|
Qst_AnswerType_t AnsType);
|
||||||
|
|
||||||
|
unsigned Qst_DB_GetRecentQuestions (MYSQL_RES **mysql_res,
|
||||||
|
long CrsCod,time_t BeginTime);
|
||||||
|
unsigned Qst_DB_GetRecentAnswers (MYSQL_RES **mysql_res,
|
||||||
|
long CrsCod,time_t BeginTime);
|
||||||
|
|
||||||
unsigned Qst_DB_GetQstData (MYSQL_RES **mysql_res,long QstCod);
|
unsigned Qst_DB_GetQstData (MYSQL_RES **mysql_res,long QstCod);
|
||||||
Qst_AnswerType_t Qst_DB_GetQstAnswerType (long QstCod);
|
Qst_AnswerType_t Qst_DB_GetQstAnswerType (long QstCod);
|
||||||
long Qst_DB_GetQstMedCod (long CrsCod,long QstCod);
|
long Qst_DB_GetQstMedCod (long CrsCod,long QstCod);
|
||||||
|
|
|
@ -442,3 +442,82 @@ bool Roo_DB_CheckIfICanSeeUsrLocation (long UsrCod)
|
||||||
Gbl.Usrs.Me.UsrDat.UsrCod,
|
Gbl.Usrs.Me.UsrDat.UsrCod,
|
||||||
UsrCod);
|
UsrCod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/***************** Check in (send user's current location) *******************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
unsigned Roo_DB_GetUsrLastLocation (MYSQL_RES **mysql_res,long UsrCod)
|
||||||
|
{
|
||||||
|
return (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get matches",
|
||||||
|
"SELECT ins_instits.InsCod," // row[ 0]
|
||||||
|
"ins_instits.ShortName," // row[ 1]
|
||||||
|
"ins_instits.FullName," // row[ 2]
|
||||||
|
"ctr_centers.CtrCod," // row[ 3]
|
||||||
|
"ctr_centers.ShortName," // row[ 4]
|
||||||
|
"ctr_centers.FullName," // row[ 5]
|
||||||
|
"bld_buildings.BldCod," // row[ 6]
|
||||||
|
"bld_buildings.ShortName," // row[ 7]
|
||||||
|
"bld_buildings.FullName," // row[ 8]
|
||||||
|
"roo_rooms.Floor," // row[ 9]
|
||||||
|
"roo_rooms.RooCod," // row[10]
|
||||||
|
"roo_rooms.ShortName," // row[11]
|
||||||
|
"roo_rooms.FullName," // row[12]
|
||||||
|
"UNIX_TIMESTAMP(roo_check_in.CheckInTime)" // row[13]
|
||||||
|
" FROM roo_check_in,"
|
||||||
|
"roo_rooms,"
|
||||||
|
"bld_buildings,"
|
||||||
|
"ctr_centers,"
|
||||||
|
"ins_instits"
|
||||||
|
" WHERE roo_check_in.UsrCod=%ld"
|
||||||
|
" AND roo_check_in.ChkCod="
|
||||||
|
"(SELECT ChkCod"
|
||||||
|
" FROM roo_check_in"
|
||||||
|
" WHERE UsrCod=%ld"
|
||||||
|
" ORDER BY ChkCod DESC"
|
||||||
|
" LIMIT 1)" // Faster than SELECT MAX
|
||||||
|
" AND roo_check_in.RooCod=roo_rooms.RooCod"
|
||||||
|
" AND roo_rooms.BldCod=bld_buildings.BldCod"
|
||||||
|
" AND bld_buildings.CtrCod=ctr_centers.CtrCod"
|
||||||
|
" AND ctr_centers.InsCod=ins_instits.InsCod",
|
||||||
|
UsrCod,
|
||||||
|
UsrCod);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**************** Get location associated to a MAC address *******************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
unsigned Roo_DB_GetLocationByMAC (MYSQL_RES **mysql_res,unsigned long long MACnum)
|
||||||
|
{
|
||||||
|
return (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get matches",
|
||||||
|
"SELECT ins_instits.InsCod," // row[ 0]
|
||||||
|
"ins_instits.ShortName," // row[ 1]
|
||||||
|
"ins_instits.FullName," // row[ 2]
|
||||||
|
"ctr_centers.CtrCod," // row[ 3]
|
||||||
|
"ctr_centers.ShortName," // row[ 4]
|
||||||
|
"ctr_centers.FullName," // row[ 5]
|
||||||
|
"bld_buildings.BldCod," // row[ 6]
|
||||||
|
"bld_buildings.ShortName," // row[ 7]
|
||||||
|
"bld_buildings.FullName," // row[ 8]
|
||||||
|
"roo_rooms.Floor," // row[ 9]
|
||||||
|
"roo_rooms.RooCod," // row[10]
|
||||||
|
"roo_rooms.ShortName," // row[11]
|
||||||
|
"roo_rooms.FullName" // row[12]
|
||||||
|
" FROM roo_macs,"
|
||||||
|
"roo_rooms,"
|
||||||
|
"bld_buildings,"
|
||||||
|
"ctr_centers,"
|
||||||
|
"ins_instits"
|
||||||
|
" WHERE roo_macs.MAC=%llu"
|
||||||
|
" AND roo_macs.RooCod=roo_rooms.RooCod"
|
||||||
|
" AND roo_rooms.BldCod=bld_buildings.BldCod"
|
||||||
|
" AND bld_buildings.CtrCod=ctr_centers.CtrCod"
|
||||||
|
" AND ctr_centers.InsCod=ins_instits.InsCod"
|
||||||
|
" ORDER BY roo_rooms.Capacity DESC," // Get the biggest room
|
||||||
|
"roo_rooms.ShortName"
|
||||||
|
" LIMIT 1",
|
||||||
|
MACnum);
|
||||||
|
}
|
||||||
|
|
|
@ -63,5 +63,7 @@ void Roo_DB_RemoveAllRoomsInCtr (long CtrCod);
|
||||||
long Roo_DB_CheckIn (long RooCod);
|
long Roo_DB_CheckIn (long RooCod);
|
||||||
|
|
||||||
bool Roo_DB_CheckIfICanSeeUsrLocation (long UsrCod);
|
bool Roo_DB_CheckIfICanSeeUsrLocation (long UsrCod);
|
||||||
|
unsigned Roo_DB_GetUsrLastLocation (MYSQL_RES **mysql_res,long UsrCod);
|
||||||
|
unsigned Roo_DB_GetLocationByMAC (MYSQL_RES **mysql_res,unsigned long long MACnum);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -225,17 +225,18 @@ unsigned Tag_DB_GetAllTagsFromCurrentCrs (MYSQL_RES **mysql_res)
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
// Return the number of rows of the result
|
// Return the number of rows of the result
|
||||||
|
|
||||||
unsigned Tag_DB_GetEnabledTagsFromThisCrs (MYSQL_RES **mysql_res)
|
unsigned Tag_DB_GetEnabledTagsFromCrs (MYSQL_RES **mysql_res,long CrsCod)
|
||||||
{
|
{
|
||||||
/***** Get available not hidden tags from database *****/
|
/***** Get available not hidden tags from database *****/
|
||||||
return (unsigned) DB_QuerySELECT (mysql_res,"can not get available enabled tags",
|
return (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get available enabled tags",
|
||||||
"SELECT TagCod," // row[0]
|
"SELECT TagCod," // row[0]
|
||||||
"TagTxt" // row[1]
|
"TagTxt" // row[1]
|
||||||
" FROM tst_tags"
|
" FROM tst_tags"
|
||||||
" WHERE CrsCod=%ld"
|
" WHERE CrsCod=%ld"
|
||||||
" AND TagHidden='N'"
|
" AND TagHidden='N'"
|
||||||
" ORDER BY TagTxt",
|
" ORDER BY TagTxt",
|
||||||
Gbl.Hierarchy.Crs.CrsCod);
|
CrsCod);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -270,6 +271,48 @@ long Tag_DB_GetTagCodFromTagTxt (const char *TagTxt)
|
||||||
TagTxt);
|
TagTxt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/*** Get tags of recent test questions from database giving a course code ****/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
unsigned Tag_DB_GetRecentTags (MYSQL_RES **mysql_res,
|
||||||
|
long CrsCod,time_t BeginTime)
|
||||||
|
{
|
||||||
|
return (unsigned)
|
||||||
|
DB_QuerySELECT (mysql_res,"can not get question tags",
|
||||||
|
"SELECT QstCod," // row[0]
|
||||||
|
"TagCod," // row[1]
|
||||||
|
"TagInd" // row[2]
|
||||||
|
" FROM tst_question_tags"
|
||||||
|
" WHERE QstCod IN "
|
||||||
|
"(SELECT tst_questions.QstCod"
|
||||||
|
" FROM tst_questions,"
|
||||||
|
"tst_question_tags,"
|
||||||
|
"tst_tags"
|
||||||
|
" WHERE tst_questions.CrsCod=%ld"
|
||||||
|
" AND tst_questions.QstCod NOT IN"
|
||||||
|
" (SELECT tst_question_tags.QstCod"
|
||||||
|
" FROM tst_tags,"
|
||||||
|
"tst_question_tags"
|
||||||
|
" WHERE tst_tags.CrsCod=%ld"
|
||||||
|
" AND tst_tags.TagHidden='Y'"
|
||||||
|
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
||||||
|
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
||||||
|
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
||||||
|
" AND tst_tags.CrsCod=%ld"
|
||||||
|
" AND (tst_questions.EditTime>=FROM_UNIXTIME(%ld)"
|
||||||
|
" OR "
|
||||||
|
"tst_tags.ChangeTime>=FROM_UNIXTIME(%ld)))"
|
||||||
|
" ORDER BY QstCod,"
|
||||||
|
"TagInd",
|
||||||
|
CrsCod,
|
||||||
|
CrsCod,
|
||||||
|
CrsCod,
|
||||||
|
(long) BeginTime,
|
||||||
|
(long) BeginTime);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/******** Remove associations between questions and tags in a course *********/
|
/******** Remove associations between questions and tags in a course *********/
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
@ -55,10 +55,13 @@ void Tag_DB_EnableOrDisableTag (long TagCod,bool TagHidden);
|
||||||
|
|
||||||
unsigned Tag_DB_GetTagsQst (MYSQL_RES **mysql_res,long QstCod);
|
unsigned Tag_DB_GetTagsQst (MYSQL_RES **mysql_res,long QstCod);
|
||||||
unsigned Tag_DB_GetAllTagsFromCurrentCrs (MYSQL_RES **mysql_res);
|
unsigned Tag_DB_GetAllTagsFromCurrentCrs (MYSQL_RES **mysql_res);
|
||||||
unsigned Tag_DB_GetEnabledTagsFromThisCrs (MYSQL_RES **mysql_res);
|
unsigned Tag_DB_GetEnabledTagsFromCrs (MYSQL_RES **mysql_res,long CrsCod);
|
||||||
bool Tag_DB_CheckIfCurrentCrsHasTestTags (void);
|
bool Tag_DB_CheckIfCurrentCrsHasTestTags (void);
|
||||||
long Tag_DB_GetTagCodFromTagTxt (const char *TagTxt);
|
long Tag_DB_GetTagCodFromTagTxt (const char *TagTxt);
|
||||||
|
|
||||||
|
unsigned Tag_DB_GetRecentTags (MYSQL_RES **mysql_res,
|
||||||
|
long CrsCod,time_t BeginTime);
|
||||||
|
|
||||||
void Tag_DB_RemTagsInQstsInCrs (long CrsCod);
|
void Tag_DB_RemTagsInQstsInCrs (long CrsCod);
|
||||||
void Tag_DB_RemTagsInCrs (long CrsCod);
|
void Tag_DB_RemTagsInCrs (long CrsCod);
|
||||||
void Tag_DB_RemTagsFromQst (long QstCod);
|
void Tag_DB_RemTagsFromQst (long QstCod);
|
||||||
|
|
|
@ -143,7 +143,8 @@ static void Tst_ShowFormRequestTest (struct Qst_Questions *Questions)
|
||||||
Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE);
|
Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE);
|
||||||
|
|
||||||
/***** Get tags *****/
|
/***** Get tags *****/
|
||||||
if ((Questions->Tags.Num = Tag_DB_GetEnabledTagsFromThisCrs (&mysql_res)) != 0)
|
if ((Questions->Tags.Num = Tag_DB_GetEnabledTagsFromCrs (&mysql_res,
|
||||||
|
Gbl.Hierarchy.Crs.CrsCod)) != 0)
|
||||||
{
|
{
|
||||||
/***** Check if minimum date-time of next access to test is older than now *****/
|
/***** Check if minimum date-time of next access to test is older than now *****/
|
||||||
if (Tst_CheckIfNextTstAllowed ())
|
if (Tst_CheckIfNextTstAllowed ())
|
||||||
|
|
Loading…
Reference in New Issue
Block a user