Version 15.37

This commit is contained in:
Antonio Cañas Vargas 2015-11-11 03:00:22 +01:00
parent bb31835ecb
commit e722d8e7e8
23 changed files with 130 additions and 202 deletions

View File

@ -11158,3 +11158,10 @@ OPTIMIZE TABLE ws_keys;
----- -----
SELECT TstCod,AllowTeachers,UNIX_TIMESTAMP(TstTime) AS T,NumQsts,NumQstsNotBlank,Score FROM tst_exams WHERE T>='0' AND T<='2000000000' ORDER BY TstCod; SELECT TstCod,AllowTeachers,UNIX_TIMESTAMP(TstTime) AS T,NumQsts,NumQstsNotBlank,Score FROM tst_exams WHERE T>='0' AND T<='2000000000' ORDER BY TstCod;
-----
SELECT * FROM expanded_folders WHERE UNIX_TIMESTAMP() > UNIX_TIMESTAMP(ClickTime)+'1000';
SELECT * FROM expanded_folders WHERE ClickTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'1000');

View File

@ -1,14 +1,6 @@
CREATE DATABASE IF NOT EXISTS swad DEFAULT CHARACTER SET=latin1 DEFAULT COLLATE latin1_spanish_ci; CREATE DATABASE IF NOT EXISTS swad DEFAULT CHARACTER SET=latin1 DEFAULT COLLATE latin1_spanish_ci;
USE swad; USE swad;
-- --
-- Table IP_last: stores the last click from each IP address
--
CREATE TABLE IF NOT EXISTS IP_last (
IP CHAR(15) NOT NULL,
LastClick DATETIME NOT NULL,
PRIMARY KEY(IP),
INDEX(LastClick));
--
-- Table IP_prefs: stores user's preferences for each IP address -- Table IP_prefs: stores user's preferences for each IP address
-- --
CREATE TABLE IF NOT EXISTS IP_prefs ( CREATE TABLE IF NOT EXISTS IP_prefs (

View File

@ -156,7 +156,9 @@ static void RSS_WriteNotices (FILE *FileRSS,struct Course *Crs)
/***** Get active notices in course *****/ /***** Get active notices in course *****/
sprintf (Query,"SELECT NotCod,UNIX_TIMESTAMP(CreatTime) AS T,UsrCod,Content" sprintf (Query,"SELECT NotCod,UNIX_TIMESTAMP(CreatTime) AS T,UsrCod,Content"
" FROM notices WHERE CrsCod='%ld' AND Status='%u' ORDER BY T DESC", " FROM notices"
" WHERE CrsCod='%ld' AND Status='%u'"
" ORDER BY T DESC",
Crs->CrsCod,(unsigned) Not_ACTIVE_NOTICE); Crs->CrsCod,(unsigned) Not_ACTIVE_NOTICE);
NumNotices = DB_QuerySELECT (Query,&mysql_res,"can not get notices from database"); NumNotices = DB_QuerySELECT (Query,&mysql_res,"can not get notices from database");

View File

@ -108,16 +108,23 @@
// TODO: Row with total of users in figures // TODO: Row with total of users in figures
// TODO: Remove total rows in listing of places // TODO: Remove total rows in listing of places
// TODO: Show message indicating that mail could be in SPAM folder // TODO: Show message indicating that mail could be in SPAM folder
// TODO: Remove email address for recipients rejected (mailbox unavailable)
/*****************************************************************************/ /*****************************************************************************/
/****************************** Public constants *****************************/ /****************************** Public constants *****************************/
/*****************************************************************************/ /*****************************************************************************/
#define Log_PLATFORM_VERSION "SWAD 15.36 (2015/11/10)" #define Log_PLATFORM_VERSION "SWAD 15.37 (2015/11/11)"
// Number of lines (includes comments but not blank lines) has been got with the following command: // Number of lines (includes comments but not blank lines) has been got with the following command:
// nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*.h sql/swad*.sql | tail -1 // nl swad*.c swad*.h css/swad*.css py/swad*.py js/swad*.js soap/swad*.h sql/swad*.sql | tail -1
/* /*
Version 15.37: Nov 11, 2015 Changes to speed up queries related to time.
Time to next test printed in user's local time.
Table table IP_last removed. (186909 lines)
1 change necessary in database:
DROP TABLE IF EXISTS IP_last;
Version 15.36: Nov 10, 2015 Fixed bug in assignments, reported by Javier Fernández Baldomero. Version 15.36: Nov 10, 2015 Fixed bug in assignments, reported by Javier Fernández Baldomero.
Changes in automatic creation of assignment folders. (186985 lines) Changes in automatic creation of assignment folders. (186985 lines)
Version 15.35.5: Nov 09, 2015 Fixed bug in swad.sql, reported by Florent H. Carré. Version 15.35.5: Nov 09, 2015 Fixed bug in swad.sql, reported by Florent H. Carré.

View File

@ -3490,7 +3490,7 @@ void Crs_RemoveOldCrss (void)
/***** Get old courses from database *****/ /***** Get old courses from database *****/
sprintf (Query,"SELECT CrsCod FROM crs_last WHERE" sprintf (Query,"SELECT CrsCod FROM crs_last WHERE"
" UNIX_TIMESTAMP(LastTime) < UNIX_TIMESTAMP()-%lu" " LastTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')"
" AND CrsCod NOT IN (SELECT DISTINCT CrsCod FROM crs_usr)", " AND CrsCod NOT IN (SELECT DISTINCT CrsCod FROM crs_usr)",
SecondsWithoutAccess); SecondsWithoutAccess);
if ((NumCrss = DB_QuerySELECT (Query,&mysql_res,"can not get old users"))) if ((NumCrss = DB_QuerySELECT (Query,&mysql_res,"can not get old users")))

View File

@ -85,22 +85,6 @@ void DB_CreateTablesIfNotExist (void)
Lay_ShowAlert (Lay_INFO,Txt_Creating_database_tables_if_they_do_not_exist); Lay_ShowAlert (Lay_INFO,Txt_Creating_database_tables_if_they_do_not_exist);
fprintf (Gbl.F.Out,"<ol>"); fprintf (Gbl.F.Out,"<ol>");
/***** Table IP_last *****/
/*
mysql> DESCRIBE IP_last;
+-----------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+-------+
| IP | char(15) | NO | PRI | NULL | |
| LastClick | datetime | NO | MUL | NULL | |
+-----------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)
*/
DB_CreateTable ("CREATE TABLE IF NOT EXISTS IP_last ("
"IP CHAR(15) NOT NULL,"
"LastClick DATETIME NOT NULL,"
"PRIMARY KEY(IP),INDEX(LastClick))");
/***** Table IP_prefs *****/ /***** Table IP_prefs *****/
/* /*
mysql> DESCRIBE IP_prefs; mysql> DESCRIBE IP_prefs;

View File

@ -744,7 +744,7 @@ void Enr_RemoveOldUsrs (void)
sprintf (Query,"SELECT UsrCod FROM" sprintf (Query,"SELECT UsrCod FROM"
"(" "("
"SELECT UsrCod FROM usr_last WHERE" "SELECT UsrCod FROM usr_last WHERE"
" UNIX_TIMESTAMP(LastTime) < UNIX_TIMESTAMP()-%lu" " LastTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')"
" UNION " " UNION "
"SELECT UsrCod FROM usr_data WHERE" "SELECT UsrCod FROM usr_data WHERE"
" UsrCod NOT IN (SELECT UsrCod FROM usr_last)" " UsrCod NOT IN (SELECT UsrCod FROM usr_last)"

View File

@ -7058,7 +7058,7 @@ void Brw_RemoveExpiredExpandedFolders (void)
/***** Remove all expired clipboards *****/ /***** Remove all expired clipboards *****/
sprintf (Query,"DELETE LOW_PRIORITY FROM expanded_folders" sprintf (Query,"DELETE LOW_PRIORITY FROM expanded_folders"
" WHERE UNIX_TIMESTAMP() > UNIX_TIMESTAMP(ClickTime)+%ld", " WHERE ClickTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
Cfg_TIME_TO_DELETE_BROWSER_EXPANDED_FOLDERS); Cfg_TIME_TO_DELETE_BROWSER_EXPANDED_FOLDERS);
DB_QueryDELETE (Query,"can not remove old expanded folders"); DB_QueryDELETE (Query,"can not remove old expanded folders");
} }
@ -7073,7 +7073,7 @@ static void Brw_RemoveExpiredClipboards (void)
/***** Remove all expired clipboards *****/ /***** Remove all expired clipboards *****/
sprintf (Query,"DELETE LOW_PRIORITY FROM clipboard" sprintf (Query,"DELETE LOW_PRIORITY FROM clipboard"
" WHERE UNIX_TIMESTAMP() > UNIX_TIMESTAMP(CopyTime)+%ld", " WHERE CopyTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
Cfg_TIME_TO_DELETE_BROWSER_CLIPBOARD); Cfg_TIME_TO_DELETE_BROWSER_CLIPBOARD);
DB_QueryDELETE (Query,"can not remove old paths from clipboard"); DB_QueryDELETE (Query,"can not remove old paths from clipboard");
} }

View File

@ -1245,7 +1245,8 @@ static void For_GetPstData (long PstCod,long *UsrCod,time_t *CreatTimeUTC,
/***** Get data of a post from database *****/ /***** Get data of a post from database *****/
sprintf (Query,"SELECT UsrCod,UNIX_TIMESTAMP(CreatTime),Subject,Content" sprintf (Query,"SELECT UsrCod,UNIX_TIMESTAMP(CreatTime),Subject,Content"
" FROM forum_post WHERE PstCod='%ld'",PstCod); " FROM forum_post WHERE PstCod='%ld'",
PstCod);
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get data of a post"); NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get data of a post");
/***** Result should have a unique row *****/ /***** Result should have a unique row *****/
@ -3427,7 +3428,9 @@ void For_GetThrData (struct ForumThread *Thr)
"UNIX_TIMESTAMP(m1.CreatTime)," "UNIX_TIMESTAMP(m1.CreatTime),"
"m0.Subject" "m0.Subject"
" FROM forum_thread,forum_post AS m0,forum_post AS m1" " FROM forum_thread,forum_post AS m0,forum_post AS m1"
" WHERE forum_thread.ThrCod='%ld' AND forum_thread.FirstPstCod=m0.PstCod AND forum_thread.LastPstCod=m1.PstCod", " WHERE forum_thread.ThrCod='%ld'"
" AND forum_thread.FirstPstCod=m0.PstCod"
" AND forum_thread.LastPstCod=m1.PstCod",
Thr->ThrCod); Thr->ThrCod);
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get data of a thread of a forum"); NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get data of a thread of a forum");
@ -4208,7 +4211,7 @@ void For_RemoveExpiredThrsClipboards (void)
/***** Remove all expired clipboards *****/ /***** Remove all expired clipboards *****/
sprintf (Query,"DELETE LOW_PRIORITY FROM forum_thr_clip" sprintf (Query,"DELETE LOW_PRIORITY FROM forum_thr_clip"
" WHERE UNIX_TIMESTAMP() > UNIX_TIMESTAMP(TimeInsert)+%ld", " WHERE TimeInsert<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
Cfg_TIME_TO_DELETE_THREAD_CLIPBOARD); Cfg_TIME_TO_DELETE_THREAD_CLIPBOARD);
DB_QueryDELETE (Query,"can not remove old threads from clipboards"); DB_QueryDELETE (Query,"can not remove old threads from clipboards");
} }

View File

@ -2353,7 +2353,7 @@ void Grp_OpenGroupsAutomatically (void)
/***** Find group types to be opened *****/ /***** Find group types to be opened *****/
sprintf (Query,"SELECT GrpTypCod FROM crs_grp_types" sprintf (Query,"SELECT GrpTypCod FROM crs_grp_types"
" WHERE CrsCod='%ld' AND MustBeOpened='Y'" " WHERE CrsCod='%ld' AND MustBeOpened='Y'"
" AND UNIX_TIMESTAMP(OpenTime)<=UNIX_TIMESTAMP()", " AND OpenTime<=NOW()",
Gbl.CurrentCrs.Crs.CrsCod); Gbl.CurrentCrs.Crs.CrsCod);
NumGrpTypes = (unsigned) DB_QuerySELECT (Query,&mysql_res, NumGrpTypes = (unsigned) DB_QuerySELECT (Query,&mysql_res,
"can not get the types of group to be opened"); "can not get the types of group to be opened");

View File

@ -1269,7 +1269,7 @@ static void Mai_InsertMailKey (const char *Email,const char MailKey[Mai_LENGTH_E
/***** Remove expired pending passwords from database *****/ /***** Remove expired pending passwords from database *****/
sprintf (Query,"DELETE FROM pending_emails" sprintf (Query,"DELETE FROM pending_emails"
" WHERE (UNIX_TIMESTAMP() > UNIX_TIMESTAMP(DateAndTime)+'%ld')", " WHERE DateAndTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
Cfg_TIME_TO_DELETE_OLD_PENDING_EMAILS); Cfg_TIME_TO_DELETE_OLD_PENDING_EMAILS);
DB_QueryDELETE (Query,"can not remove old pending mail keys"); DB_QueryDELETE (Query,"can not remove old pending mail keys");

View File

@ -2418,14 +2418,16 @@ static void Msg_GetMsgSntData (long MsgCod,long *CrsCod,long *UsrCod,
/***** Get data of message from table msg_snt *****/ /***** Get data of message from table msg_snt *****/
*Deleted = false; *Deleted = false;
sprintf (Query,"SELECT CrsCod,UsrCod,UNIX_TIMESTAMP(CreatTime)" sprintf (Query,"SELECT CrsCod,UsrCod,UNIX_TIMESTAMP(CreatTime)"
" FROM msg_snt WHERE MsgCod='%ld'",MsgCod); " FROM msg_snt WHERE MsgCod='%ld'",
MsgCod);
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get data of a message"); NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get data of a message");
if (NumRows == 0) // If not result ==> sent message is deleted if (NumRows == 0) // If not result ==> sent message is deleted
{ {
/***** Get data of message from table msg_snt_deleted *****/ /***** Get data of message from table msg_snt_deleted *****/
sprintf (Query,"SELECT CrsCod,UsrCod,UNIX_TIMESTAMP(CreatTime)" sprintf (Query,"SELECT CrsCod,UsrCod,UNIX_TIMESTAMP(CreatTime)"
" FROM msg_snt_deleted WHERE MsgCod='%ld'",MsgCod); " FROM msg_snt_deleted WHERE MsgCod='%ld'",
MsgCod);
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get data of a message"); NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get data of a message");
*Deleted = true; *Deleted = true;

View File

@ -1279,7 +1279,7 @@ void Ntf_SendPendingNotifByEMailToAllUsrs (void)
/***** Get users who must be notified from database ******/ /***** Get users who must be notified from database ******/
// (Status & Ntf_STATUS_BIT_EMAIL) && !(Status & Ntf_STATUS_BIT_SENT) && !(Status & (Ntf_STATUS_BIT_READ | Ntf_STATUS_BIT_REMOVED)) // (Status & Ntf_STATUS_BIT_EMAIL) && !(Status & Ntf_STATUS_BIT_SENT) && !(Status & (Ntf_STATUS_BIT_READ | Ntf_STATUS_BIT_REMOVED))
sprintf (Query,"SELECT DISTINCT ToUsrCod FROM notif" sprintf (Query,"SELECT DISTINCT ToUsrCod FROM notif"
" WHERE UNIX_TIMESTAMP(TimeNotif) < UNIX_TIMESTAMP()-%lu" " WHERE TimeNotif<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')"
" AND (Status & %u)<>0 AND (Status & %u)=0 AND (Status & %u)=0", " AND (Status & %u)<>0 AND (Status & %u)=0 AND (Status & %u)=0",
Cfg_TIME_TO_SEND_PENDING_NOTIF, Cfg_TIME_TO_SEND_PENDING_NOTIF,
(unsigned) Ntf_STATUS_BIT_EMAIL, (unsigned) Ntf_STATUS_BIT_EMAIL,
@ -1320,7 +1320,7 @@ void Ntf_SendPendingNotifByEMailToAllUsrs (void)
/***** Delete old notifications ******/ /***** Delete old notifications ******/
sprintf (Query,"DELETE LOW_PRIORITY FROM notif" sprintf (Query,"DELETE LOW_PRIORITY FROM notif"
" WHERE UNIX_TIMESTAMP(TimeNotif) < UNIX_TIMESTAMP()-%lu", " WHERE TimeNotif<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
Cfg_TIME_TO_DELETE_OLD_NOTIF); Cfg_TIME_TO_DELETE_OLD_NOTIF);
DB_QueryDELETE (Query,"can not remove old notifications"); DB_QueryDELETE (Query,"can not remove old notifications");
} }
@ -1877,7 +1877,7 @@ static unsigned Ntf_GetNumberOfMyNewUnseenNtfs (void)
/***** Get number of places with a name from database *****/ /***** Get number of places with a name from database *****/
sprintf (Query,"SELECT COUNT(*) FROM notif" sprintf (Query,"SELECT COUNT(*) FROM notif"
" WHERE ToUsrCod='%ld' AND (Status & %u)=0" " WHERE ToUsrCod='%ld' AND (Status & %u)=0"
" AND UNIX_TIMESTAMP(TimeNotif)>'%ld'", " AND TimeNotif>FROM_UNIXTIME('%ld')",
Gbl.Usrs.Me.UsrDat.UsrCod, Gbl.Usrs.Me.UsrDat.UsrCod,
(unsigned) (Ntf_STATUS_BIT_READ | Ntf_STATUS_BIT_REMOVED), (unsigned) (Ntf_STATUS_BIT_READ | Ntf_STATUS_BIT_REMOVED),
Gbl.Usrs.Me.UsrLast.LastAccNotif); Gbl.Usrs.Me.UsrLast.LastAccNotif);

View File

@ -456,7 +456,7 @@ void Pwd_SetMyPendingPassword (char PlainPassword[Pwd_MAX_LENGTH_PLAIN_PASSWORD+
/***** Remove expired pending passwords from database *****/ /***** Remove expired pending passwords from database *****/
sprintf (Query,"DELETE FROM pending_passwd" sprintf (Query,"DELETE FROM pending_passwd"
" WHERE (UNIX_TIMESTAMP() > UNIX_TIMESTAMP(DateAndTime)+'%ld')", " WHERE DateAndTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
Cfg_TIME_TO_DELETE_OLD_PENDING_PASSWORDS); Cfg_TIME_TO_DELETE_OLD_PENDING_PASSWORDS);
DB_QueryDELETE (Query,"can not remove expired pending passwords"); DB_QueryDELETE (Query,"can not remove expired pending passwords");

View File

@ -1237,7 +1237,7 @@ static long Pho_GetDegWithAvgPhotoLeastRecentlyUpdated (void)
/***** 2. If all the degrees are in table, choose the least recently updated *****/ /***** 2. If all the degrees are in table, choose the least recently updated *****/
/* Get degrees from database */ /* Get degrees from database */
sprintf (Query,"SELECT DegCod FROM sta_degrees" sprintf (Query,"SELECT DegCod FROM sta_degrees"
" WHERE UNIX_TIMESTAMP(TimeAvgPhoto)<UNIX_TIMESTAMP()-%ld" " WHERE TimeAvgPhoto<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')"
" ORDER BY TimeAvgPhoto LIMIT 1", " ORDER BY TimeAvgPhoto LIMIT 1",
Cfg_MIN_TIME_TO_RECOMPUTE_AVG_PHOTO); Cfg_MIN_TIME_TO_RECOMPUTE_AVG_PHOTO);
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get degrees"); NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get degrees");
@ -1287,7 +1287,8 @@ static long Pho_GetTimeAvgPhotoWasComputed (long DegCod)
/***** Get last time an average photo was computed from database *****/ /***** Get last time an average photo was computed from database *****/
sprintf (Query,"SELECT MIN(UNIX_TIMESTAMP(TimeAvgPhoto))" sprintf (Query,"SELECT MIN(UNIX_TIMESTAMP(TimeAvgPhoto))"
" FROM sta_degrees WHERE DegCod='%ld'",DegCod); " FROM sta_degrees WHERE DegCod='%ld'",
DegCod);
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get last time an average photo was computed"); NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get last time an average photo was computed");
if (NumRows == 1) if (NumRows == 1)

View File

@ -213,7 +213,7 @@ void Pre_RemoveOldPrefsFromIP (void)
/***** Remove old preferences *****/ /***** Remove old preferences *****/
sprintf (Query,"DELETE LOW_PRIORITY FROM IP_prefs" sprintf (Query,"DELETE LOW_PRIORITY FROM IP_prefs"
" WHERE UNIX_TIMESTAMP() > UNIX_TIMESTAMP(LastChange)+%ld", " WHERE LastChange<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
Cfg_TIME_TO_DELETE_IP_PREFS); Cfg_TIME_TO_DELETE_IP_PREFS);
DB_QueryDELETE (Query,"can not remove old preferences"); DB_QueryDELETE (Query,"can not remove old preferences");
} }

View File

@ -717,13 +717,13 @@ static unsigned long Prf_GetRankingNumClicksPerDay (long UsrCod)
" AS NumClicksPerDay" " AS NumClicksPerDay"
" FROM usr_figures" " FROM usr_figures"
" WHERE UsrCod<>'%ld'" // Necessary because the following comparison is not exact in floating point " WHERE UsrCod<>'%ld'" // Necessary because the following comparison is not exact in floating point
" AND NumClicks>='0' AND UNIX_TIMESTAMP(FirstClickTime)>'0')" " AND NumClicks>='0' AND FirstClickTime>FROM_UNIXTIME('0'))"
" AS TableNumClicksPerDay" " AS TableNumClicksPerDay"
" WHERE NumClicksPerDay>" " WHERE NumClicksPerDay>"
"(SELECT NumClicks/(DATEDIFF(NOW(),FirstClickTime)+1)" "(SELECT NumClicks/(DATEDIFF(NOW(),FirstClickTime)+1)"
" FROM usr_figures" " FROM usr_figures"
" WHERE UsrCod='%ld'" " WHERE UsrCod='%ld'"
" AND NumClicks>='0' AND UNIX_TIMESTAMP(FirstClickTime)>'0')", " AND NumClicks>='0' AND FirstClickTime>FROM_UNIXTIME('0'))",
UsrCod,UsrCod); UsrCod,UsrCod);
return DB_QueryCOUNT (Query,"can not get ranking using number of clicks per day"); return DB_QueryCOUNT (Query,"can not get ranking using number of clicks per day");
} }
@ -738,7 +738,7 @@ static unsigned long Prf_GetNumUsrsWithNumClicksPerDay (void)
/***** Select number of rows with values already calculated *****/ /***** Select number of rows with values already calculated *****/
sprintf (Query,"SELECT COUNT(*) FROM usr_figures" sprintf (Query,"SELECT COUNT(*) FROM usr_figures"
" WHERE NumClicks>='0' AND UNIX_TIMESTAMP(FirstClickTime)>'0'"); " WHERE NumClicks>='0' AND FirstClickTime>FROM_UNIXTIME('0')");
return DB_QueryCOUNT (Query,"can not get number of users with number of clicks per day"); return DB_QueryCOUNT (Query,"can not get number of users with number of clicks per day");
} }

View File

@ -236,9 +236,11 @@ void Ses_RemoveExpiredSessions (void)
/* A session expire when last click (LastTime) is too old, /* A session expire when last click (LastTime) is too old,
or when there was at least one refresh (navigator supports AJAX) and last refresh is too old (browser probably was closed) */ or when there was at least one refresh (navigator supports AJAX) and last refresh is too old (browser probably was closed) */
sprintf (Query,"DELETE LOW_PRIORITY FROM sessions WHERE" sprintf (Query,"DELETE LOW_PRIORITY FROM sessions WHERE"
" (UNIX_TIMESTAMP() > UNIX_TIMESTAMP(LastTime)+%ld) OR" " LastTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu') OR"
" ((UNIX_TIMESTAMP(LastRefresh) > UNIX_TIMESTAMP(LastTime)+1) AND" " LastRefresh BETWEEN "
" (UNIX_TIMESTAMP() > UNIX_TIMESTAMP(LastRefresh)+%ld))", "(LastTime+INTERVAL 1 SECOND)"
" AND "
"FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
Cfg_TIME_TO_CLOSE_SESSION_FROM_LAST_CLICK, Cfg_TIME_TO_CLOSE_SESSION_FROM_LAST_CLICK,
Cfg_TIME_TO_CLOSE_SESSION_FROM_LAST_REFRESH); Cfg_TIME_TO_CLOSE_SESSION_FROM_LAST_REFRESH);
DB_QueryDELETE (Query,"can not remove expired sessions"); DB_QueryDELETE (Query,"can not remove expired sessions");

View File

@ -235,70 +235,6 @@ void Sta_GetRemoteAddr (void)
Gbl.IP[0] = '\0'; Gbl.IP[0] = '\0';
} }
/*****************************************************************************/
/********* If this click is made from the same IP too fast, abort ************/
/*****************************************************************************/
/*
void Sta_ExitIfTooFast (void)
{
extern const char *Txt_STR_LANG_ID[Txt_NUM_LANGUAGES];
extern const char *Txt_Too_fast;
extern const char *Txt_Go_back;
char Query[512];
unsigned NumClicks; // Very recent clicks from this IP (0 or 1)
***** Some actions can be made fast *****
if (Gbl.CurrentAct == ActRefCon || // Refresh connected
Gbl.CurrentAct == ActRefLstClk || // Refresh last clicks
Gbl.CurrentAct == ActAutUsrChgLan) // Change my language automatically just after log in
return;
***** Get if a click/refresh is made from the same IP very recently *****
sprintf (Query,"SELECT COUNT(*) FROM IP_last"
" WHERE IP='%s' AND UNIX_TIMESTAMP(LastClick)>UNIX_TIMESTAMP()-%u",
Gbl.IP,Cfg_MIN_TIME_BETWEEN_2_CLICKS_FROM_THE_SAME_IP);
NumClicks = (unsigned) DB_QueryCOUNT (Query,"can not get the number of very recent clicks");
***** Remove old clicks/refreshes *****
sprintf (Query,"DELETE FROM IP_last"
" WHERE UNIX_TIMESTAMP(LastClick)<=UNIX_TIMESTAMP()-%u",
Cfg_MIN_TIME_BETWEEN_2_CLICKS_FROM_THE_SAME_IP);
DB_QueryDELETE (Query,"can not remove old last IP");
***** Replace last click/refresh from this IP *****
sprintf (Query,"REPLACE INTO IP_last"
" (IP,LastClick)"
" VALUES ('%s',NOW())",
Gbl.IP);
DB_QueryREPLACE (Query,"can not update last IP");
***** If too fast, write warning and exit *****
if (NumClicks) // Too fast
{
***** Write header to standard output to avoid timeout *****
// Two \r\n are necessary
fprintf (stdout,"Content-type: text/html; charset=windows-1252\r\n\r\n"
"<!DOCTYPE html>\n"
"<html lang=\"%s\">\n"
"<head>"
"<title>%s</title>"
"</head>"
"<body>"
"<h1 style=\"text-align:center;\">%s</h1>"
"<h2 style=\"text-align:center;\">"
"<a href=\"\" onclick=\"window.history.back();\">&larr; %s</a>"
"</h2>"
"</body>"
"</html>",
Txt_STR_LANG_ID[Gbl.Prefs.Language],
Cfg_PLATFORM_FULL_NAME,
Txt_Too_fast,
Txt_Go_back);
exit (0);
// sleep (Cfg_MIN_TIME_BETWEEN_2_CLICKS_FROM_THE_SAME_IP); // Sleep those seconds
}
}
*/
/*****************************************************************************/ /*****************************************************************************/
/**************************** Log access in database *************************/ /**************************** Log access in database *************************/
/*****************************************************************************/ /*****************************************************************************/
@ -412,7 +348,7 @@ void Sta_RemoveOldEntriesRecentLog (void)
/***** Remove all expired clipboards *****/ /***** Remove all expired clipboards *****/
sprintf (Query,"DELETE LOW_PRIORITY FROM log_recent" sprintf (Query,"DELETE LOW_PRIORITY FROM log_recent"
" WHERE UNIX_TIMESTAMP(ClickTime)<UNIX_TIMESTAMP()-%ld", " WHERE ClickTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
Sta_SECONDS_IN_RECENT_LOG); Sta_SECONDS_IN_RECENT_LOG);
DB_QueryDELETE (Query,"can not remove old entries from recent log"); DB_QueryDELETE (Query,"can not remove old entries from recent log");
} }
@ -1118,12 +1054,11 @@ static void Sta_ShowHits (Sta_GlobalOrCourseAccesses_t GlobalOrCourse)
StrQueryCountType,LogTable); StrQueryCountType,LogTable);
break; break;
} }
sprintf (QueryAux," WHERE" sprintf (QueryAux," WHERE %s.ClickTime"
" UNIX_TIMESTAMP(%s.ClickTime)>='%ld'" " BETWEEN FROM_UNIXTIME('%ld') AND FROM_UNIXTIME('%ld')",
" AND" LogTable,
" UNIX_TIMESTAMP(%s.ClickTime)<='%ld'", (long) Gbl.DateRange.TimeUTC[0],
LogTable,(long) Gbl.DateRange.TimeUTC[0], (long) Gbl.DateRange.TimeUTC[1]);
LogTable,(long) Gbl.DateRange.TimeUTC[1]);
strcat (Query,QueryAux); strcat (Query,QueryAux);
switch (GlobalOrCourse) switch (GlobalOrCourse)
@ -2168,12 +2103,12 @@ static void Sta_ShowDistrAccessesPerDaysAndHour (unsigned long NumRows,MYSQL_RES
if (NumRow == 1) if (NumRow == 1)
Dat_AssignDate (&PreviousReadDate,&CurrentReadDate); Dat_AssignDate (&PreviousReadDate,&CurrentReadDate);
/* Update number of pages generated per hour */ /* Update number of hits per hour */
if (PreviousReadDate.Year != CurrentReadDate.Year || if (PreviousReadDate.Year != CurrentReadDate.Year ||
PreviousReadDate.Month != CurrentReadDate.Month || PreviousReadDate.Month != CurrentReadDate.Month ||
PreviousReadDate.Day != CurrentReadDate.Day) // Current read date (CurrentReadDate) is older than previous read date (PreviousReadDate) */ PreviousReadDate.Day != CurrentReadDate.Day) // Current read date (CurrentReadDate) is older than previous read date (PreviousReadDate) */
{ {
/* In the next loop we show (NumDaysFromLastDateToCurrDate-1) days (the menos antiguos) with 0 clicks /* In the next loop we show (NumDaysFromLastDateToCurrDate-1) days with 0 clicks
and a last day (older) with Hits.Num */ and a last day (older) with Hits.Num */
Dat_AssignDate (&Date,&LastDate); Dat_AssignDate (&Date,&LastDate);
NumDaysFromLastDateToCurrDate = Dat_GetNumDaysBetweenDates (&PreviousReadDate,&LastDate); NumDaysFromLastDateToCurrDate = Dat_GetNumDaysBetweenDates (&PreviousReadDate,&LastDate);

View File

@ -138,7 +138,6 @@ typedef enum
/*****************************************************************************/ /*****************************************************************************/
void Sta_GetRemoteAddr (void); void Sta_GetRemoteAddr (void);
void Sta_ExitIfTooFast (void);
void Sta_LogAccess (const char *Comments); void Sta_LogAccess (const char *Comments);
void Sta_RemoveOldEntriesRecentLog (void); void Sta_RemoveOldEntriesRecentLog (void);
void Sta_AskShowCrsHits (void); void Sta_AskShowCrsHits (void);

View File

@ -561,13 +561,13 @@ static void Tst_ShowTstTotalMark (double TotalScore)
static bool Tst_CheckIfNextTstAllowed (void) static bool Tst_CheckIfNextTstAllowed (void)
{ {
extern const char *Txt_You_can_not_make_a_new_test_in_the_course_X_until_TIME_Y; extern const char *Txt_Test;
extern const char *Txt_You_can_not_make_a_new_test_in_the_course_X_until_TIME_Y_on_DATE_Z; extern const char *Txt_You_can_not_make_a_new_test_in_the_course_X_until;
char Query[512]; char Query[512];
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
long NumSecondsFromNowToNextAccTst = -1L; // Access allowed when this number <= 0 long NumSecondsFromNowToNextAccTst = -1L; // Access allowed when this number <= 0
unsigned Year,Month,Day,Hour,Minute,Second; time_t TimeNextTestUTC = (time_t) 0;
/***** Superusers are allowed to do all test they want *****/ /***** Superusers are allowed to do all test they want *****/
if (Gbl.Usrs.Me.LoggedRole == Rol_SYS_ADM) if (Gbl.Usrs.Me.LoggedRole == Rol_SYS_ADM)
@ -575,7 +575,7 @@ static bool Tst_CheckIfNextTstAllowed (void)
/***** Get date of next allowed access to test from database *****/ /***** Get date of next allowed access to test from database *****/
sprintf (Query,"SELECT UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)-UNIX_TIMESTAMP()," sprintf (Query,"SELECT UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)-UNIX_TIMESTAMP(),"
"LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND" "UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)"
" FROM crs_usr" " FROM crs_usr"
" WHERE CrsCod='%ld' AND UsrCod='%ld'", " WHERE CrsCod='%ld' AND UsrCod='%ld'",
Gbl.Test.Config.MinTimeNxtTstPerQst, Gbl.Test.Config.MinTimeNxtTstPerQst,
@ -587,9 +587,8 @@ static bool Tst_CheckIfNextTstAllowed (void)
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
if (row[0]) if (row[0])
if (sscanf (row[0],"%ld",&NumSecondsFromNowToNextAccTst) == 1) if (sscanf (row[0],"%ld",&NumSecondsFromNowToNextAccTst) == 1)
/* Datetime of next access allowed (row[1]) */ /* Time UTC of next access allowed (row[1]) */
if (sscanf (row[1],"%04u-%02u-%02u %02u:%02u:%02u",&Year,&Month,&Day,&Hour,&Minute,&Second) != 6) TimeNextTestUTC = Dat_GetUNIXTimeFromStr (row[1]);
Lay_ShowErrorAndExit ("Wrong date of next allowed access to test.");
} }
else else
Lay_ShowErrorAndExit ("Error when reading date of next allowed access to test."); Lay_ShowErrorAndExit ("Error when reading date of next allowed access to test.");
@ -600,15 +599,31 @@ static bool Tst_CheckIfNextTstAllowed (void)
/***** Check if access is allowed *****/ /***** Check if access is allowed *****/
if (NumSecondsFromNowToNextAccTst > 0) if (NumSecondsFromNowToNextAccTst > 0)
{ {
if (Year == Gbl.Now.Date.Year && /***** Start frame *****/
Month == Gbl.Now.Date.Month && Lay_StartRoundFrameTable (NULL,2,Txt_Test);
Day == Gbl.Now.Date.Day) // Next access allowed is today Lay_WriteHeaderClassPhoto (1,false,false,
sprintf (Gbl.Message,Txt_You_can_not_make_a_new_test_in_the_course_X_until_TIME_Y, Gbl.CurrentIns.Ins.InsCod,
Gbl.CurrentCrs.Crs.FullName,Hour,Minute,Second); Gbl.CurrentDeg.Deg.DegCod,
else Gbl.CurrentCrs.Crs.CrsCod);
sprintf (Gbl.Message,Txt_You_can_not_make_a_new_test_in_the_course_X_until_TIME_Y_on_DATE_Z,
Gbl.CurrentCrs.Crs.FullName,Hour,Minute,Second,Year,Month,Day); /***** Write warning *****/
Lay_ShowAlert (Lay_WARNING,Gbl.Message); fprintf (Gbl.F.Out,"<tr>"
"<td class=\"DAT CENTER_MIDDLE\">");
fprintf (Gbl.F.Out,Txt_You_can_not_make_a_new_test_in_the_course_X_until,
Gbl.CurrentCrs.Crs.FullName);
fprintf (Gbl.F.Out,": "
"<span id=\"date_next_test\">"
"</span>"
"<script type=\"text/javascript\">"
"writeLocalDateTimeFromUTC('date_next_test',%ld,'&nbsp;');"
"</script>"
"</td>"
"</tr>",
(long) TimeNextTestUTC);
/***** End frame *****/
Lay_EndRoundFrameTable ();
return false; return false;
} }
return true; return true;
@ -6209,8 +6224,8 @@ static void Tst_ShowResultsOfTestExams (struct UsrData *UsrDat)
"NumQsts,NumQstsNotBlank,Score" "NumQsts,NumQstsNotBlank,Score"
" FROM tst_exams" " FROM tst_exams"
" WHERE CrsCod='%ld' AND UsrCod='%ld'" " WHERE CrsCod='%ld' AND UsrCod='%ld'"
" AND UNIX_TIMESTAMP(TstTime)>='%ld'" " AND TstTime>=FROM_UNIXTIME('%ld')"
" AND UNIX_TIMESTAMP(TstTime)<='%ld'" " AND TstTime<=FROM_UNIXTIME('%ld')"
" ORDER BY TstCod", " ORDER BY TstCod",
Gbl.CurrentCrs.Crs.CrsCod, Gbl.CurrentCrs.Crs.CrsCod,
UsrDat->UsrCod, UsrDat->UsrCod,

View File

@ -49860,64 +49860,25 @@ const char *Txt_You_can_not_leave_the_web_address_empty =
"You can not leave the web address empty."; // Necessita de tradução "You can not leave the web address empty."; // Necessita de tradução
#endif #endif
const char *Txt_You_can_not_make_a_new_test_in_the_course_X_until_TIME_Y = // Warning: it is very important to include %s and three %02u in the following sentences const char *Txt_You_can_not_make_a_new_test_in_the_course_X_until = // Warning: it is very important to include %s in the following sentences
#if L==0 #if L==0
"No puede hacer un nuevo test en la asignatura <strong>%s</strong>" "No puede hacer un nuevo test en la asignatura <strong>%s</strong> hasta"; // Necessita traduccio
" hasta las %02uh%02u'%02u&quot;"; // Necessita traduccio
#elif L==1 #elif L==1
"You can not make a new test in the course <strong>%s</strong>" "You can not make a new test in the course <strong>%s</strong> until"; // Need Übersetzung
" until %02uh%02u'%02u&quot;"; // Need Übersetzung
#elif L==2 #elif L==2
"You can not make a new test in the course <strong>%s</strong>" "You can not make a new test in the course <strong>%s</strong> until";
" until %02uh%02u'%02u&quot;";
#elif L==3 #elif L==3
"No puede hacer un nuevo test en la asignatura <strong>%s</strong>" "No puede hacer un nuevo test en la asignatura <strong>%s</strong> hasta";
" hasta las %02uh%02u'%02u&quot;";
#elif L==4 #elif L==4
"You can not make a new test in the course <strong>%s</strong>" "You can not make a new test in the course <strong>%s</strong> until"; // Besoin de traduction
" until %02uh%02u'%02u&quot;"; // Besoin de traduction
#elif L==5 #elif L==5
"No puede hacer un nuevo test en la asignatura <strong>%s</strong>" "No puede hacer un nuevo test en la asignatura <strong>%s</strong> hasta"; // Okoteve traducción
" hasta las %02uh%02u'%02u&quot;"; // Okoteve traducción
#elif L==6 #elif L==6
"Non puoi fare un nuovo test nel corso <strong>%s</strong>" "Non puoi fare un nuovo test nel corso <strong>%s</strong> fino";
" fino al %02uh%02u'%02u&quot;";
#elif L==7 #elif L==7
"You can not make a new test in the course <strong>%s</strong>" "You can not make a new test in the course <strong>%s</strong> until"; // Potrzebujesz tlumaczenie
" until %02uh%02u'%02u&quot;"; // Potrzebujesz tlumaczenie
#elif L==8 #elif L==8
"You can not make a new test in the course <strong>%s</strong>" "You can not make a new test in the course <strong>%s</strong> until"; // Necessita de tradução
" until %02uh%02u'%02u&quot;"; // Necessita de tradução
#endif
const char *Txt_You_can_not_make_a_new_test_in_the_course_X_until_TIME_Y_on_DATE_Z = // Warning: it is very important to include %s, five %02u and %04u in the following sentences
#if L==0
"No puede hacer un nuevo test en la asignatura <strong>%s</strong>"
" hasta las %02u:%02u:%02u del %04u-%02u-%02u"; // Necessita traduccio
#elif L==1
"You can not make a new test in the course <strong>%s</strong>"
" until %02u:%02u:%02u on %04u-%02u-%02u"; // Need Übersetzung
#elif L==2
"You can not make a new test in the course <strong>%s</strong>"
" until %02u:%02u:%02u on %04u-%02u-%02u";
#elif L==3
"No puede hacer un nuevo test en la asignatura <strong>%s</strong>"
" hasta las %02u:%02u:%02u del %04u-%02u-%02u";
#elif L==4
"You can not make a new test in the course <strong>%s</strong>"
" until %02u:%02u:%02u on %04u-%02u-%02u"; // Besoin de traduction
#elif L==5
"No puede hacer un nuevo test en la asignatura <strong>%s</strong>"
" hasta las %02u:%02u:%02u del %04u-%02u-%02u"; // Okoteve traducción
#elif L==6
"Non puoi fare un nuovo test nel corso <strong>%s</strong>"
" fino al %02u:%02u:%02u del %04u-%02u-%02u";
#elif L==7
"You can not make a new test in the course <strong>%s</strong>"
" until %02u:%02u:%02u on %04u-%02u-%02u"; // Potrzebujesz tlumaczenie
#elif L==8
"You can not make a new test in the course <strong>%s</strong>"
" until %02u:%02u:%02u on %04u-%02u-%02u"; // Necessita de tradução
#endif #endif
const char *Txt_You_can_not_paste_file_or_folder_here = const char *Txt_You_can_not_paste_file_or_folder_here =

View File

@ -474,7 +474,7 @@ static int Svc_RemoveOldWSKeys (void)
/* A session expire when last click (LastTime) is too old, /* A session expire when last click (LastTime) is too old,
or when there was at least one refresh (navigator supports AJAX) and last refresh is too old (browser probably was closed) */ or when there was at least one refresh (navigator supports AJAX) and last refresh is too old (browser probably was closed) */
sprintf (Query,"DELETE LOW_PRIORITY FROM ws_keys WHERE" sprintf (Query,"DELETE LOW_PRIORITY FROM ws_keys WHERE"
" UNIX_TIMESTAMP() > UNIX_TIMESTAMP(LastTime)+%ld", " LastTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
Cfg_TIME_TO_DELETE_Svc_KEY); Cfg_TIME_TO_DELETE_Svc_KEY);
if (mysql_query (&Gbl.mysql,Query)) if (mysql_query (&Gbl.mysql,Query))
return soap_receiver_fault (Gbl.soap, return soap_receiver_fault (Gbl.soap,
@ -2545,7 +2545,8 @@ int swad__getNotifications (struct soap *soap,
/***** Get my notifications from database *****/ /***** Get my notifications from database *****/
sprintf (Query,"SELECT NtfCod,NotifyEvent,UNIX_TIMESTAMP(TimeNotif)," sprintf (Query,"SELECT NtfCod,NotifyEvent,UNIX_TIMESTAMP(TimeNotif),"
"FromUsrCod,InsCod,CtrCod,DegCod,CrsCod,Cod,Status" "FromUsrCod,InsCod,CtrCod,DegCod,CrsCod,Cod,Status"
" FROM notif WHERE ToUsrCod=%ld AND UNIX_TIMESTAMP(TimeNotif)>=%ld" " FROM notif"
" WHERE ToUsrCod='%ld' AND TimeNotif>=FROM_UNIXTIME('%ld')"
" ORDER BY TimeNotif DESC", " ORDER BY TimeNotif DESC",
Gbl.Usrs.Me.UsrDat.UsrCod,beginTime); Gbl.Usrs.Me.UsrDat.UsrCod,beginTime);
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get user's notifications"); NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get user's notifications");
@ -3413,11 +3414,16 @@ static int Svc_GetTstQuestions (long CrsCod,long BeginTime,struct swad__getTests
" AND tst_questions.QstCod=tst_question_tags.QstCod" " AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod" " AND tst_question_tags.TagCod=tst_tags.TagCod"
" AND tst_tags.CrsCod='%ld'" " AND tst_tags.CrsCod='%ld'"
" AND (UNIX_TIMESTAMP(tst_questions.EditTime)>='%ld'" " AND "
" OR UNIX_TIMESTAMP(tst_tags.ChangeTime)>='%ld')" "("
"tst_questions.EditTime>=FROM_UNIXTIME('%ld')"
" OR "
"tst_tags.ChangeTime>=FROM_UNIXTIME('%ld')"
")"
" ORDER BY QstCod", " ORDER BY QstCod",
CrsCod,CrsCod,CrsCod, CrsCod,CrsCod,CrsCod,
BeginTime,BeginTime); BeginTime,
BeginTime);
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test questions"); NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test questions");
getTestsOut->questionsArray.__size = (int) NumRows; getTestsOut->questionsArray.__size = (int) NumRows;
@ -3492,11 +3498,17 @@ static int Svc_GetTstAnswers (long CrsCod,long BeginTime,struct swad__getTestsOu
" AND tst_questions.QstCod=tst_question_tags.QstCod" " AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod" " AND tst_question_tags.TagCod=tst_tags.TagCod"
" AND tst_tags.CrsCod='%ld'" " AND tst_tags.CrsCod='%ld'"
" AND (UNIX_TIMESTAMP(tst_questions.EditTime)>='%ld'" " AND "
" OR UNIX_TIMESTAMP(tst_tags.ChangeTime)>='%ld'))" "("
"tst_questions.EditTime>=FROM_UNIXTIME('%ld')"
" OR "
"tst_tags.ChangeTime>=FROM_UNIXTIME('%ld')"
")"
")"
" ORDER BY QstCod,AnsInd", " ORDER BY QstCod,AnsInd",
CrsCod,CrsCod,CrsCod, CrsCod,CrsCod,CrsCod,
BeginTime,BeginTime); BeginTime,
BeginTime);
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test answers"); NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test answers");
getTestsOut->answersArray.__size = (int) NumRows; getTestsOut->answersArray.__size = (int) NumRows;
@ -3571,11 +3583,17 @@ static int Svc_GetTstQuestionTags (long CrsCod,long BeginTime,struct swad__getTe
" AND tst_questions.QstCod=tst_question_tags.QstCod" " AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod" " AND tst_question_tags.TagCod=tst_tags.TagCod"
" AND tst_tags.CrsCod='%ld'" " AND tst_tags.CrsCod='%ld'"
" AND (UNIX_TIMESTAMP(tst_questions.EditTime)>='%ld'" " AND "
" OR UNIX_TIMESTAMP(tst_tags.ChangeTime)>='%ld'))" "("
"tst_questions.EditTime>=FROM_UNIXTIME('%ld')"
" OR "
"tst_tags.ChangeTime>=FROM_UNIXTIME('%ld')"
")"
")"
" ORDER BY QstCod,TagInd", " ORDER BY QstCod,TagInd",
CrsCod,CrsCod,CrsCod, CrsCod,CrsCod,CrsCod,
BeginTime,BeginTime); BeginTime,
BeginTime);
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test question tags"); NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test question tags");
getTestsOut->questionTagsArray.__size = (int) NumRows; getTestsOut->questionTagsArray.__size = (int) NumRows;