Version 21.37: Oct 19, 2021 New module swad_statistic_database for database queries related to statistics of accesses to platform.

This commit is contained in:
acanas 2021-10-19 18:18:50 +02:00
parent 42d013dcd3
commit 2e7d0b099b
10 changed files with 715 additions and 575 deletions

View File

@ -79,8 +79,9 @@ OBJS = swad_account.o swad_account_database.o swad_action.o swad_admin.o \
swad_report_database.o swad_role.o swad_role_database.o swad_room.o \
swad_room_database.o swad_RSS.o \
swad_scope.o swad_search.o swad_session.o swad_session_database.o \
swad_setting.o swad_setting_database.o swad_statistic.o swad_string.o \
swad_survey.o swad_syllabus.o swad_system_config.o \
swad_setting.o swad_setting_database.o swad_statistic.o \
swad_statistic_database.o swad_string.o swad_survey.o swad_syllabus.o \
swad_system_config.o \
swad_tab.o swad_tag.o swad_test.o swad_test_config.o \
swad_test_import.o swad_test_print.o swad_test_visibility.o \
swad_theme.o \

View File

@ -131,8 +131,8 @@ static void Att_PutLinkAttEvent (struct Att_Event *AttEvent,
const char *Class);
static void Att_PutParamsCodGrps (long AttCod);
static unsigned Att_GetNumUsrsFromAListWhoAreInAttEvent (long AttCod,
long LstSelectedUsrCods[],
unsigned NumUsrsInList);
long LstSelectedUsrCods[],
unsigned NumUsrsInList);
static bool Att_CheckIfUsrIsPresentInAttEvent (long AttCod,long UsrCod);
static bool Att_CheckIfUsrIsPresentInAttEventAndGetComments (long AttCod,long UsrCod,
char CommentStd[Cns_MAX_BYTES_TEXT + 1],
@ -2085,8 +2085,8 @@ void Att_RegisterStudentsInAttEvent (void)
/*****************************************************************************/
static unsigned Att_GetNumUsrsFromAListWhoAreInAttEvent (long AttCod,
long LstSelectedUsrCods[],
unsigned NumUsrsInList)
long LstSelectedUsrCods[],
unsigned NumUsrsInList)
{
char *SubQueryUsrs;
unsigned NumUsrsInAttEvent;

View File

@ -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.
*/
#define Log_PLATFORM_VERSION "SWAD 21.36 (2021-10-18)"
#define Log_PLATFORM_VERSION "SWAD 21.37 (2021-10-19)"
#define CSS_FILE "swad20.45.css"
#define JS_FILE "swad20.69.1.js"
/*
TODO: Rename CENTRE to CENTER in help wiki.
TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams
Version 21.37: Oct 19, 2021 New module swad_statistic_database for database queries related to statistics of accesses to platform. (320363 lines)
Version 21.36: Oct 18, 2021 New module swad_setting_database for database queries related to user's settings / preferences. (320253 lines)
Version 21.35.1: Oct 18, 2021 Queries moved to module swad_file_database. (320175 lines)
Version 21.35: Oct 18, 2021 New module swad_file_database for database queries related to files. (320171 lines)

View File

@ -380,6 +380,20 @@ unsigned Log_DB_GetMyHitsPerYear (MYSQL_RES **mysql_res,
SubQueryRol);
}
/*****************************************************************************/
/********************* Get the comments of a hit from log ********************/
/*****************************************************************************/
void Log_DB_GetLogComments (long LogCod,char Comments[Cns_MAX_BYTES_TEXT + 1])
{
DB_QuerySELECTString (Comments,Cns_MAX_BYTES_TEXT,
"can not get log comments",
"SELECT Comments"
" FROM log_comments"
" WHERE LogCod=%ld",
LogCod);
}
/*****************************************************************************/
/************ Sometimes, we delete old entries in recent log table ***********/
/*****************************************************************************/

View File

@ -60,6 +60,7 @@ unsigned Log_DB_GetMyHistoricCrss (MYSQL_RES **mysql_res,
unsigned Log_DB_GetMyHitsPerYear (MYSQL_RES **mysql_res,
bool AnyCourse,long CrsCod,Rol_Role_t Role,
time_t FirstClickTimeUTC);
void Log_DB_GetLogComments (long LogCod,char Comments[Cns_MAX_BYTES_TEXT + 1]);
void Log_DB_RemoveOldEntriesRecentLog (void);

View File

@ -42,9 +42,11 @@
#include "swad_HTML.h"
#include "swad_ID.h"
#include "swad_log.h"
#include "swad_log_database.h"
#include "swad_profile.h"
#include "swad_role.h"
#include "swad_statistic.h"
#include "swad_statistic_database.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
@ -94,12 +96,6 @@ static const unsigned Sta_CellPadding[Sta_NUM_CLICKS_GROUPED_BY] =
/******************************* Private types *******************************/
/*****************************************************************************/
typedef enum
{
Sta_SHOW_GLOBAL_ACCESSES,
Sta_SHOW_COURSE_ACCESSES,
} Sta_GlobalOrCourseAccesses_t;
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
@ -262,8 +258,8 @@ static void Sta_PutFormCrsHits (struct Sta_Stats *Stats)
/***** Contextual menu *****/
Mnu_ContextMenuBegin ();
Sta_PutLinkToGlobalHits (); // Global hits
Log_PutLinkToLastClicks (); // Last clicks in real time
Sta_PutLinkToGlobalHits (); // Global hits
Log_PutLinkToLastClicks (); // Last clicks in real time
Mnu_ContextMenuEnd ();
/***** Get and update type of list,
@ -743,10 +739,6 @@ void Sta_SeeCrsAccesses (void)
/******************** Compute and show access statistics ********************/
/*****************************************************************************/
#define Sta_MAX_BYTES_QUERY_ACCESS (1024 + (10 + ID_MAX_BYTES_USR_ID) * 5000 - 1)
#define Sta_MAX_BYTES_COUNT_TYPE (256 - 1)
static void Sta_ShowHits (Sta_GlobalOrCourseAccesses_t GlobalOrCourse)
{
extern const char *Txt_You_must_select_one_ore_more_users;
@ -757,24 +749,19 @@ static void Sta_ShowHits (Sta_GlobalOrCourseAccesses_t GlobalOrCourse)
extern const char *Txt_STAT_TYPE_COUNT_CAPS[Sta_NUM_COUNT_TYPES];
extern const char *Txt_Time_zone_used_in_the_calculation_of_these_statistics;
struct Sta_Stats Stats;
char *Query = NULL;
char QueryAux[512];
long LengthQuery;
MYSQL_RES *mysql_res;
unsigned NumHits;
const char *LogTable;
Sta_ClicksDetailedOrGrouped_t DetailedOrGrouped = Sta_CLICKS_GROUPED;
struct UsrData UsrDat;
char BrowserTimeZone[Dat_MAX_BYTES_TIME_ZONE + 1];
unsigned NumUsr = 0;
const char *Ptr;
char StrRole[256];
char StrQueryCountType[Sta_MAX_BYTES_COUNT_TYPE + 1];
unsigned NumDays;
bool ICanQueryWholeRange;
unsigned NumUsrsInList = 0;
long *LstSelectedUsrCods = NULL;
/***** Reset stats context *****/
Sta_ResetStats (&Stats);
Stats.GlobalOrCourse = GlobalOrCourse;
/***** Get initial and ending dates *****/
Dat_GetIniEndDatesFromForm ();
@ -820,7 +807,7 @@ static void Sta_ShowHits (Sta_GlobalOrCourseAccesses_t GlobalOrCourse)
Act_NUM_ACTIONS - 1,
(unsigned long) Sta_NUM_ACTION_DEFAULT);
switch (GlobalOrCourse)
switch (Stats.GlobalOrCourse)
{
case Sta_SHOW_GLOBAL_ACCESSES:
/***** Get the type of user of clicks *****/
@ -883,14 +870,20 @@ static void Sta_ShowHits (Sta_GlobalOrCourseAccesses_t GlobalOrCourse)
/****** Get lists of selected users ******/
Usr_GetListsSelectedEncryptedUsrsCods (&Gbl.Usrs.Selected);
/***** Count number of valid users in list of encrypted user codes *****/
NumUsrsInList = Usr_CountNumUsrsInListOfSelectedEncryptedUsrCods (&Gbl.Usrs.Selected);
/***** Show the form again *****/
Sta_PutFormCrsHits (&Stats);
/***** Begin results section *****/
HTM_SECTION_Begin (Sta_STAT_RESULTS_SECTION_ID);
/***** Check selection *****/
if (!Usr_CheckIfThereAreUsrsInListOfSelectedEncryptedUsrCods (&Gbl.Usrs.Selected)) // Error: there are no users selected
/***** Check users' selection *****/
if (NumUsrsInList)
/* Get list of user codes from encrypted user codes */
Usr_GetListSelectedUsrCods (&Gbl.Usrs.Selected,NumUsrsInList,&LstSelectedUsrCods);
else // There are no users selected
{
/* Write warning message, clean and abort */
Ale_ShowAlert (Ale_WARNING,Txt_You_must_select_one_ore_more_users);
@ -902,7 +895,7 @@ static void Sta_ShowHits (Sta_GlobalOrCourseAccesses_t GlobalOrCourse)
/***** Check if range of dates is forbidden for me *****/
NumDays = Dat_GetNumDaysBetweenDates (&Gbl.DateRange.DateIni.Date,&Gbl.DateRange.DateEnd.Date);
ICanQueryWholeRange = (Gbl.Usrs.Me.Role.Logged >= Rol_TCH && GlobalOrCourse == Sta_SHOW_COURSE_ACCESSES) ||
ICanQueryWholeRange = (Gbl.Usrs.Me.Role.Logged >= Rol_TCH && Stats.GlobalOrCourse == Sta_SHOW_COURSE_ACCESSES) ||
(Gbl.Usrs.Me.Role.Logged == Rol_TCH && Gbl.Scope.Current == HieLvl_CRS) ||
(Gbl.Usrs.Me.Role.Logged == Rol_DEG_ADM && (Gbl.Scope.Current == HieLvl_DEG ||
Gbl.Scope.Current == HieLvl_CRS)) ||
@ -922,516 +915,9 @@ static void Sta_ShowHits (Sta_GlobalOrCourseAccesses_t GlobalOrCourse)
return;
}
/***** Query depending on the type of count *****/
switch (Stats.CountType)
{
case Sta_TOTAL_CLICKS:
Str_Copy (StrQueryCountType,"COUNT(*)",sizeof (StrQueryCountType) - 1);
break;
case Sta_DISTINCT_USRS:
sprintf (StrQueryCountType,"COUNT(DISTINCT(%s.UsrCod))",LogTable);
break;
case Sta_CLICKS_PER_USR:
sprintf (StrQueryCountType,"COUNT(*)/GREATEST(COUNT(DISTINCT(%s.UsrCod)),1)+0.000000",LogTable);
break;
case Sta_GENERATION_TIME:
sprintf (StrQueryCountType,"(AVG(%s.TimeToGenerate)/1E6)+0.000000",LogTable);
break;
case Sta_SEND_TIME:
sprintf (StrQueryCountType,"(AVG(%s.TimeToSend)/1E6)+0.000000",LogTable);
break;
}
/***** Select clicks from the table of log *****/
/* Allocate memory for the query */
if ((Query = malloc (Sta_MAX_BYTES_QUERY_ACCESS + 1)) == NULL)
Err_NotEnoughMemoryExit ();
/* Start the query */
switch (Stats.ClicksGroupedBy)
{
case Sta_CLICKS_CRS_DETAILED_LIST:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE LogCod,"
"UsrCod,"
"Role,"
"UNIX_TIMESTAMP(ClickTime) AS F,"
"ActCod"
" FROM %s",
LogTable);
break;
case Sta_CLICKS_CRS_PER_USR:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE UsrCod,"
"%s AS Num"
" FROM %s",
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_DAY:
case Sta_CLICKS_GBL_PER_DAY:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%Y%%m%%d') AS Day,"
"%s"
" FROM %s",
BrowserTimeZone,
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_DAY_AND_HOUR:
case Sta_CLICKS_GBL_PER_DAY_AND_HOUR:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%Y%%m%%d') AS Day,"
"DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%H') AS Hour,"
"%s"
" FROM %s",
BrowserTimeZone,
BrowserTimeZone,
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_WEEK:
case Sta_CLICKS_GBL_PER_WEEK:
/* With %x%v the weeks are counted from monday to sunday.
With %X%V the weeks are counted from sunday to saturday. */
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
(Gbl.Prefs.FirstDayOfWeek == 0) ?
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%x%%v') AS Week,"// Weeks start on monday
"%s"
" FROM %s" :
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%X%%V') AS Week,"// Weeks start on sunday
"%s"
" FROM %s",
BrowserTimeZone,
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_MONTH:
case Sta_CLICKS_GBL_PER_MONTH:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%Y%%m') AS Month,"
"%s"
" FROM %s",
BrowserTimeZone,
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_YEAR:
case Sta_CLICKS_GBL_PER_YEAR:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%Y') AS Year,"
"%s"
" FROM %s",
BrowserTimeZone,
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_HOUR:
case Sta_CLICKS_GBL_PER_HOUR:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%H') AS Hour,"
"%s"
" FROM %s",
BrowserTimeZone,
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_MINUTE:
case Sta_CLICKS_GBL_PER_MINUTE:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%H%%i') AS Minute,"
"%s"
" FROM %s",
BrowserTimeZone,
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_ACTION:
case Sta_CLICKS_GBL_PER_ACTION:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE ActCod,"
"%s AS Num"
" FROM %s",
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_PLUGIN:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE log_api.PlgCod,"
"%s AS Num"
" FROM %s,"
"log_api",
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_API_FUNCTION:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE log_api.FunCod,"
"%s AS Num"
" FROM %s,"
"log_api",
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_BANNER:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE log_banners.BanCod,"
"%s AS Num"
" FROM %s,"
"log_banners",
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_COUNTRY:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE CtyCod,"
"%s AS Num"
" FROM %s",
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_INSTITUTION:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE InsCod,"
"%s AS Num"
" FROM %s",
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_CENTER:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE CtrCod,"
"%s AS Num"
" FROM %s",
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_DEGREE:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE DegCod,"
"%s AS Num"
" FROM %s",
StrQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_COURSE:
snprintf (Query,Sta_MAX_BYTES_QUERY_ACCESS + 1,
"SELECT SQL_NO_CACHE CrsCod,"
"%s AS Num"
" FROM %s",
StrQueryCountType,
LogTable);
break;
}
sprintf (QueryAux," WHERE %s.ClickTime"
" BETWEEN FROM_UNIXTIME(%ld)"
" AND FROM_UNIXTIME(%ld)",
LogTable,
(long) Gbl.DateRange.TimeUTC[Dat_STR_TIME],
(long) Gbl.DateRange.TimeUTC[Dat_END_TIME]);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
switch (GlobalOrCourse)
{
case Sta_SHOW_GLOBAL_ACCESSES:
/* Scope */
switch (Gbl.Scope.Current)
{
case HieLvl_UNK:
case HieLvl_SYS:
break;
case HieLvl_CTY:
if (Gbl.Hierarchy.Cty.CtyCod > 0)
{
sprintf (QueryAux," AND %s.CtyCod=%ld",
LogTable,Gbl.Hierarchy.Cty.CtyCod);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
}
break;
case HieLvl_INS:
if (Gbl.Hierarchy.Ins.InsCod > 0)
{
sprintf (QueryAux," AND %s.InsCod=%ld",
LogTable,Gbl.Hierarchy.Ins.InsCod);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
}
break;
case HieLvl_CTR:
if (Gbl.Hierarchy.Ctr.CtrCod > 0)
{
sprintf (QueryAux," AND %s.CtrCod=%ld",
LogTable,Gbl.Hierarchy.Ctr.CtrCod);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
}
break;
case HieLvl_DEG:
if (Gbl.Hierarchy.Deg.DegCod > 0)
{
sprintf (QueryAux," AND %s.DegCod=%ld",
LogTable,Gbl.Hierarchy.Deg.DegCod);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
}
break;
case HieLvl_CRS:
if (Gbl.Hierarchy.Level == HieLvl_CRS)
{
sprintf (QueryAux," AND %s.CrsCod=%ld",
LogTable,Gbl.Hierarchy.Crs.CrsCod);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
}
break;
}
/* Type of users */
switch (Stats.Role)
{
case Sta_ROLE_IDENTIFIED_USRS:
sprintf (StrRole," AND %s.Role<>%u",
LogTable,(unsigned) Rol_UNK);
break;
case Sta_ROLE_ALL_USRS:
switch (Stats.CountType)
{
case Sta_TOTAL_CLICKS:
case Sta_GENERATION_TIME:
case Sta_SEND_TIME:
StrRole[0] = '\0';
break;
case Sta_DISTINCT_USRS:
case Sta_CLICKS_PER_USR:
sprintf (StrRole," AND %s.Role<>%u",
LogTable,(unsigned) Rol_UNK);
break;
}
break;
case Sta_ROLE_INS_ADMINS:
sprintf (StrRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_INS_ADM);
break;
case Sta_ROLE_CTR_ADMINS:
sprintf (StrRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_CTR_ADM);
break;
case Sta_ROLE_DEG_ADMINS:
sprintf (StrRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_DEG_ADM);
break;
case Sta_ROLE_TEACHERS:
sprintf (StrRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_TCH);
break;
case Sta_ROLE_NON_EDITING_TEACHERS:
sprintf (StrRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_NET);
break;
case Sta_ROLE_STUDENTS:
sprintf (StrRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_STD);
break;
case Sta_ROLE_USERS:
sprintf (StrRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_USR);
break;
case Sta_ROLE_GUESTS:
sprintf (StrRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_GST);
break;
case Sta_ROLE_UNKNOWN_USRS:
sprintf (StrRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_UNK);
break;
case Sta_ROLE_ME:
sprintf (StrRole," AND %s.UsrCod=%ld",
LogTable,Gbl.Usrs.Me.UsrDat.UsrCod);
break;
}
Str_Concat (Query,StrRole,Sta_MAX_BYTES_QUERY_ACCESS);
switch (Stats.ClicksGroupedBy)
{
case Sta_CLICKS_GBL_PER_PLUGIN:
case Sta_CLICKS_GBL_PER_API_FUNCTION:
sprintf (QueryAux," AND %s.LogCod=log_api.LogCod",
LogTable);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_GBL_PER_BANNER:
sprintf (QueryAux," AND %s.LogCod=log_banners.LogCod",
LogTable);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
break;
default:
break;
}
break;
case Sta_SHOW_COURSE_ACCESSES:
sprintf (QueryAux," AND %s.CrsCod=%ld",
LogTable,Gbl.Hierarchy.Crs.CrsCod);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
/***** Initialize data structure of the user *****/
Usr_UsrDataConstructor (&UsrDat);
LengthQuery = strlen (Query);
NumUsr = 0;
Ptr = Gbl.Usrs.Selected.List[Rol_UNK];
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,UsrDat.EnUsrCod,
Cry_BYTES_ENCRYPTED_STR_SHA256_BASE64);
Usr_GetUsrCodFromEncryptedUsrCod (&UsrDat);
if (UsrDat.UsrCod > 0)
{
LengthQuery = LengthQuery + 25 + 10 + 1;
if (LengthQuery > Sta_MAX_BYTES_QUERY_ACCESS - 128)
Err_ShowErrorAndExit ("Query is too large.");
sprintf (QueryAux,
NumUsr ? " OR %s.UsrCod=%ld" :
" AND (%s.UsrCod=%ld",
LogTable,UsrDat.UsrCod);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
NumUsr++;
}
}
Str_Concat (Query,")",Sta_MAX_BYTES_QUERY_ACCESS);
/***** Free memory used by the data of the user *****/
Usr_UsrDataDestructor (&UsrDat);
break;
}
/* Select action */
if (Stats.NumAction != ActAll)
{
sprintf (QueryAux," AND %s.ActCod=%ld",
LogTable,Act_GetActCod (Stats.NumAction));
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
}
/* End the query */
switch (Stats.ClicksGroupedBy)
{
case Sta_CLICKS_CRS_DETAILED_LIST:
Str_Concat (Query," ORDER BY F",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_CRS_PER_USR:
sprintf (QueryAux," GROUP BY %s.UsrCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_CRS_PER_DAY:
case Sta_CLICKS_GBL_PER_DAY:
Str_Concat (Query," GROUP BY Day"
" ORDER BY Day DESC",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_CRS_PER_DAY_AND_HOUR:
case Sta_CLICKS_GBL_PER_DAY_AND_HOUR:
Str_Concat (Query," GROUP BY Day,Hour"
" ORDER BY Day DESC,Hour",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_CRS_PER_WEEK:
case Sta_CLICKS_GBL_PER_WEEK:
Str_Concat (Query," GROUP BY Week"
" ORDER BY Week DESC",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_CRS_PER_MONTH:
case Sta_CLICKS_GBL_PER_MONTH:
Str_Concat (Query," GROUP BY Month"
" ORDER BY Month DESC",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_CRS_PER_YEAR:
case Sta_CLICKS_GBL_PER_YEAR:
Str_Concat (Query," GROUP BY Year"
" ORDER BY Year DESC",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_CRS_PER_HOUR:
case Sta_CLICKS_GBL_PER_HOUR:
Str_Concat (Query," GROUP BY Hour"
" ORDER BY Hour",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_CRS_PER_MINUTE:
case Sta_CLICKS_GBL_PER_MINUTE:
Str_Concat (Query," GROUP BY Minute"
" ORDER BY Minute",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_CRS_PER_ACTION:
case Sta_CLICKS_GBL_PER_ACTION:
sprintf (QueryAux," GROUP BY %s.ActCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_GBL_PER_PLUGIN:
Str_Concat (Query," GROUP BY log_api.PlgCod"
" ORDER BY Num DESC",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_GBL_PER_API_FUNCTION:
Str_Concat (Query," GROUP BY log_api.FunCod"
" ORDER BY Num DESC",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_GBL_PER_BANNER:
Str_Concat (Query," GROUP BY log_banners.BanCod"
" ORDER BY Num DESC",
Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_GBL_PER_COUNTRY:
sprintf (QueryAux," GROUP BY %s.CtyCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_GBL_PER_INSTITUTION:
sprintf (QueryAux," GROUP BY %s.InsCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_GBL_PER_CENTER:
sprintf (QueryAux," GROUP BY %s.CtrCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_GBL_PER_DEGREE:
sprintf (QueryAux," GROUP BY %s.DegCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
break;
case Sta_CLICKS_GBL_PER_COURSE:
sprintf (QueryAux," GROUP BY %s.CrsCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,QueryAux,Sta_MAX_BYTES_QUERY_ACCESS);
break;
}
/***** Write query for debug *****/
/*
if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM)
Ale_ShowAlert (Ale_INFO,Query);
*/
/***** Make the query *****/
NumHits = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get clicks",
"%s",
Query);
/***** Count the number of rows in result *****/
if (NumHits == 0)
Ale_ShowAlert (Ale_INFO,Txt_There_are_no_accesses_with_the_selected_search_criteria);
else
if ((NumHits = Sta_DB_GetHits (&mysql_res,&Stats,LogTable,BrowserTimeZone,
NumUsrsInList,LstSelectedUsrCods)))
{
/***** Put the table with the clicks *****/
if (Stats.ClicksGroupedBy == Sta_CLICKS_CRS_DETAILED_LIST)
@ -1509,19 +995,26 @@ static void Sta_ShowHits (Sta_GlobalOrCourseAccesses_t GlobalOrCourse)
Sta_ShowNumHitsPerCourse (Stats.CountType,NumHits,mysql_res);
break;
}
HTM_TABLE_End ();
/* End box and section */
Box_BoxEnd ();
HTM_SECTION_End ();
}
else // No hits retrieved
Ale_ShowAlert (Ale_INFO,Txt_There_are_no_accesses_with_the_selected_search_criteria);
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
/***** Free memory used by list of selected users' codes *****/
if (Gbl.Action.Act == ActSeeAccCrs)
if (Stats.GlobalOrCourse == Sta_SHOW_COURSE_ACCESSES)
{
if (NumUsrsInList)
Usr_FreeListSelectedUsrCods (LstSelectedUsrCods);
Usr_FreeListsSelectedEncryptedUsrsCods (&Gbl.Usrs.Selected);
}
/***** Write time zone used in the calculation of these statistics *****/
switch (Stats.ClicksGroupedBy)
@ -1787,7 +1280,7 @@ static void Sta_ShowDetailedAccessesList (const struct Sta_Stats *Stats,
}
/*****************************************************************************/
/******** Show a listing of with the number of clicks of each user ***********/
/*************** Get and write the comments of a hit from log ****************/
/*****************************************************************************/
static void Sta_WriteLogComments (long LogCod)
@ -1795,12 +1288,7 @@ static void Sta_WriteLogComments (long LogCod)
char Comments[Cns_MAX_BYTES_TEXT + 1];
/***** Get log comments from database *****/
DB_QuerySELECTString (Comments,sizeof (Comments) - 1,
"can not get log comments",
"SELECT Comments"
" FROM log_comments"
" WHERE LogCod=%ld",
LogCod);
Log_DB_GetLogComments (LogCod,Comments);
/***** Write comments *****/
if (Comments[0])
@ -2351,7 +1839,7 @@ static void Sta_DrawBarColors (Sta_ColorType_t ColorType,double HitsMax)
HTM_Unsigned (0);
HTM_TD_End ();
for (Interval = 1;
for (Interval = 1;
Interval <= 4;
Interval++)
{
@ -2985,34 +2473,34 @@ static void Sta_ShowAverageAccessesPerMinute (unsigned NumHits,MYSQL_RES *mysql_
/***** X axis *****/
HTM_TR_Begin (NULL);
/* First division (left) */
HTM_TD_Begin ("class=\"LM\" style=\"width:%upx;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_IMG (Cfg_URL_ICON_PUBLIC,"ejexizq24x1.gif",NULL,
"style=\"display:block;width:%upx;height:1px;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_TD_End ();
/* All the intermediate divisions */
for (i = 0;
i < Sta_NUM_DIVISIONS_X * 2;
i++)
{
/* First division (left) */
HTM_TD_Begin ("class=\"LM\" style=\"width:%upx;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_IMG (Cfg_URL_ICON_PUBLIC,"ejex24x1.gif",NULL,
"style=\"display:block;width:%upx;height:1px;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_IMG (Cfg_URL_ICON_PUBLIC,"ejexizq24x1.gif",NULL,
"style=\"display:block;width:%upx;height:1px;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_TD_End ();
}
/* Last division (right) */
HTM_TD_Begin ("class=\"LM\" style=\"width:%upx;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_IMG (Cfg_URL_ICON_PUBLIC,"tr24x1.gif",NULL,
"style=\"display:block;width:%upx;height:1px;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_TD_End ();
/* All the intermediate divisions */
for (i = 0;
i < Sta_NUM_DIVISIONS_X * 2;
i++)
{
HTM_TD_Begin ("class=\"LM\" style=\"width:%upx;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_IMG (Cfg_URL_ICON_PUBLIC,"ejex24x1.gif",NULL,
"style=\"display:block;width:%upx;height:1px;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_TD_End ();
}
/* Last division (right) */
HTM_TD_Begin ("class=\"LM\" style=\"width:%upx;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_IMG (Cfg_URL_ICON_PUBLIC,"tr24x1.gif",NULL,
"style=\"display:block;width:%upx;height:1px;\"",
Sta_WIDTH_SEMIDIVISION_GRAPHIC);
HTM_TD_End ();
HTM_TR_End ();

View File

@ -128,8 +128,15 @@ struct Sta_Hits
double Total;
};
typedef enum
{
Sta_SHOW_GLOBAL_ACCESSES,
Sta_SHOW_COURSE_ACCESSES,
} Sta_GlobalOrCourseAccesses_t;
struct Sta_Stats
{
Sta_GlobalOrCourseAccesses_t GlobalOrCourse;
Sta_ClicksGroupedBy_t ClicksGroupedBy;
Sta_Role_t Role;
Sta_CountType_t CountType;

576
swad_statistic_database.c Normal file
View File

@ -0,0 +1,576 @@
// swad_statistic_database.c: statistics, operations with database
/*
SWAD (Shared Workspace At a Distance),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2021 Antonio Cañas Vargas
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#include <stddef.h> // For NULL
#include <string.h> // For string functions
#include "swad_database.h"
#include "swad_error.h"
#include "swad_global.h"
#include "swad_ID.h"
#include "swad_statistic.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
/*****************************************************************************/
/******************************* Private types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
/*****************************************************************************/
/******************** Compute and show access statistics ********************/
/*****************************************************************************/
#define Sta_DB_MAX_BYTES_QUERY (1024 + (10 + ID_MAX_BYTES_USR_ID) * 5000 - 1)
unsigned Sta_DB_GetHits (MYSQL_RES **mysql_res,
const struct Sta_Stats *Stats,
const char *LogTable,
const char BrowserTimeZone[Dat_MAX_BYTES_TIME_ZONE + 1],
unsigned NumUsrsInList,
const long LstSelectedUsrCods[])
{
char SubQueryCountType[256];
char SubQueryRole[256];
char SubQuery[512];
char *Query = NULL;
long LengthQuery;
unsigned NumUsr;
unsigned NumHits;
/***** Build subquery depending on the type of count *****/
switch (Stats->CountType)
{
case Sta_TOTAL_CLICKS:
Str_Copy (SubQueryCountType,"COUNT(*)",sizeof (SubQueryCountType) - 1);
break;
case Sta_DISTINCT_USRS:
sprintf (SubQueryCountType,"COUNT(DISTINCT(%s.UsrCod))",LogTable);
break;
case Sta_CLICKS_PER_USR:
sprintf (SubQueryCountType,"COUNT(*)/GREATEST(COUNT(DISTINCT(%s.UsrCod)),1)+0.000000",LogTable);
break;
case Sta_GENERATION_TIME:
sprintf (SubQueryCountType,"(AVG(%s.TimeToGenerate)/1E6)+0.000000",LogTable);
break;
case Sta_SEND_TIME:
sprintf (SubQueryCountType,"(AVG(%s.TimeToSend)/1E6)+0.000000",LogTable);
break;
}
/***** Allocate memory for the query *****/
if ((Query = malloc (Sta_DB_MAX_BYTES_QUERY + 1)) == NULL)
Err_NotEnoughMemoryExit ();
/***** Begin building the query *****/
switch (Stats->ClicksGroupedBy)
{
case Sta_CLICKS_CRS_DETAILED_LIST:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE LogCod,"
"UsrCod,"
"Role,"
"UNIX_TIMESTAMP(ClickTime) AS F,"
"ActCod"
" FROM %s",
LogTable);
break;
case Sta_CLICKS_CRS_PER_USR:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE UsrCod,"
"%s AS Num"
" FROM %s",
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_DAY:
case Sta_CLICKS_GBL_PER_DAY:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%Y%%m%%d') AS Day,"
"%s"
" FROM %s",
BrowserTimeZone,
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_DAY_AND_HOUR:
case Sta_CLICKS_GBL_PER_DAY_AND_HOUR:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%Y%%m%%d') AS Day,"
"DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%H') AS Hour,"
"%s"
" FROM %s",
BrowserTimeZone,
BrowserTimeZone,
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_WEEK:
case Sta_CLICKS_GBL_PER_WEEK:
/* With %x%v the weeks are counted from monday to sunday.
With %X%V the weeks are counted from sunday to saturday. */
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
(Gbl.Prefs.FirstDayOfWeek == 0) ?
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%x%%v') AS Week,"// Weeks start on monday
"%s"
" FROM %s" :
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%X%%V') AS Week,"// Weeks start on sunday
"%s"
" FROM %s",
BrowserTimeZone,
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_MONTH:
case Sta_CLICKS_GBL_PER_MONTH:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%Y%%m') AS Month,"
"%s"
" FROM %s",
BrowserTimeZone,
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_YEAR:
case Sta_CLICKS_GBL_PER_YEAR:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%Y') AS Year,"
"%s"
" FROM %s",
BrowserTimeZone,
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_HOUR:
case Sta_CLICKS_GBL_PER_HOUR:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%H') AS Hour,"
"%s"
" FROM %s",
BrowserTimeZone,
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_MINUTE:
case Sta_CLICKS_GBL_PER_MINUTE:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE DATE_FORMAT(CONVERT_TZ(ClickTime,@@session.time_zone,'%s'),'%%H%%i') AS Minute,"
"%s"
" FROM %s",
BrowserTimeZone,
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_CRS_PER_ACTION:
case Sta_CLICKS_GBL_PER_ACTION:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE ActCod,"
"%s AS Num"
" FROM %s",
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_PLUGIN:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE log_api.PlgCod,"
"%s AS Num"
" FROM %s,"
"log_api",
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_API_FUNCTION:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE log_api.FunCod,"
"%s AS Num"
" FROM %s,"
"log_api",
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_BANNER:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE log_banners.BanCod,"
"%s AS Num"
" FROM %s,"
"log_banners",
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_COUNTRY:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE CtyCod,"
"%s AS Num"
" FROM %s",
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_INSTITUTION:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE InsCod,"
"%s AS Num"
" FROM %s",
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_CENTER:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE CtrCod,"
"%s AS Num"
" FROM %s",
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_DEGREE:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE DegCod,"
"%s AS Num"
" FROM %s",
SubQueryCountType,
LogTable);
break;
case Sta_CLICKS_GBL_PER_COURSE:
snprintf (Query,Sta_DB_MAX_BYTES_QUERY + 1,
"SELECT SQL_NO_CACHE CrsCod,"
"%s AS Num"
" FROM %s",
SubQueryCountType,
LogTable);
break;
}
sprintf (SubQuery," WHERE %s.ClickTime"
" BETWEEN FROM_UNIXTIME(%ld)"
" AND FROM_UNIXTIME(%ld)",
LogTable,
(long) Gbl.DateRange.TimeUTC[Dat_STR_TIME],
(long) Gbl.DateRange.TimeUTC[Dat_END_TIME]);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
switch (Stats->GlobalOrCourse)
{
case Sta_SHOW_GLOBAL_ACCESSES:
/* Scope */
switch (Gbl.Scope.Current)
{
case HieLvl_UNK:
case HieLvl_SYS:
break;
case HieLvl_CTY:
if (Gbl.Hierarchy.Cty.CtyCod > 0)
{
sprintf (SubQuery," AND %s.CtyCod=%ld",
LogTable,Gbl.Hierarchy.Cty.CtyCod);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
}
break;
case HieLvl_INS:
if (Gbl.Hierarchy.Ins.InsCod > 0)
{
sprintf (SubQuery," AND %s.InsCod=%ld",
LogTable,Gbl.Hierarchy.Ins.InsCod);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
}
break;
case HieLvl_CTR:
if (Gbl.Hierarchy.Ctr.CtrCod > 0)
{
sprintf (SubQuery," AND %s.CtrCod=%ld",
LogTable,Gbl.Hierarchy.Ctr.CtrCod);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
}
break;
case HieLvl_DEG:
if (Gbl.Hierarchy.Deg.DegCod > 0)
{
sprintf (SubQuery," AND %s.DegCod=%ld",
LogTable,Gbl.Hierarchy.Deg.DegCod);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
}
break;
case HieLvl_CRS:
if (Gbl.Hierarchy.Level == HieLvl_CRS)
{
sprintf (SubQuery," AND %s.CrsCod=%ld",
LogTable,Gbl.Hierarchy.Crs.CrsCod);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
}
break;
}
/* Type of users */
switch (Stats->Role)
{
case Sta_ROLE_IDENTIFIED_USRS:
sprintf (SubQueryRole," AND %s.Role<>%u",
LogTable,(unsigned) Rol_UNK);
break;
case Sta_ROLE_ALL_USRS:
switch (Stats->CountType)
{
case Sta_TOTAL_CLICKS:
case Sta_GENERATION_TIME:
case Sta_SEND_TIME:
SubQueryRole[0] = '\0';
break;
case Sta_DISTINCT_USRS:
case Sta_CLICKS_PER_USR:
sprintf (SubQueryRole," AND %s.Role<>%u",
LogTable,(unsigned) Rol_UNK);
break;
}
break;
case Sta_ROLE_INS_ADMINS:
sprintf (SubQueryRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_INS_ADM);
break;
case Sta_ROLE_CTR_ADMINS:
sprintf (SubQueryRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_CTR_ADM);
break;
case Sta_ROLE_DEG_ADMINS:
sprintf (SubQueryRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_DEG_ADM);
break;
case Sta_ROLE_TEACHERS:
sprintf (SubQueryRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_TCH);
break;
case Sta_ROLE_NON_EDITING_TEACHERS:
sprintf (SubQueryRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_NET);
break;
case Sta_ROLE_STUDENTS:
sprintf (SubQueryRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_STD);
break;
case Sta_ROLE_USERS:
sprintf (SubQueryRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_USR);
break;
case Sta_ROLE_GUESTS:
sprintf (SubQueryRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_GST);
break;
case Sta_ROLE_UNKNOWN_USRS:
sprintf (SubQueryRole," AND %s.Role=%u",
LogTable,(unsigned) Rol_UNK);
break;
case Sta_ROLE_ME:
sprintf (SubQueryRole," AND %s.UsrCod=%ld",
LogTable,Gbl.Usrs.Me.UsrDat.UsrCod);
break;
}
Str_Concat (Query,SubQueryRole,Sta_DB_MAX_BYTES_QUERY);
switch (Stats->ClicksGroupedBy)
{
case Sta_CLICKS_GBL_PER_PLUGIN:
case Sta_CLICKS_GBL_PER_API_FUNCTION:
sprintf (SubQuery," AND %s.LogCod=log_api.LogCod",
LogTable);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_GBL_PER_BANNER:
sprintf (SubQuery," AND %s.LogCod=log_banners.LogCod",
LogTable);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
break;
default:
break;
}
break;
case Sta_SHOW_COURSE_ACCESSES:
sprintf (SubQuery," AND %s.CrsCod=%ld",
LogTable,Gbl.Hierarchy.Crs.CrsCod);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
if (NumUsrsInList)
{
LengthQuery = strlen (Query);
for (NumUsr = 0;
NumUsr < NumUsrsInList;
NumUsr++)
{
LengthQuery = LengthQuery + 25 + 10 + 1;
if (LengthQuery > Sta_DB_MAX_BYTES_QUERY - 128)
Err_ShowErrorAndExit ("Query is too large.");
sprintf (SubQuery,
NumUsr ? " OR %s.UsrCod=%ld" :
" AND (%s.UsrCod=%ld",
LogTable,LstSelectedUsrCods[NumUsr]);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
}
Str_Concat (Query,")",Sta_DB_MAX_BYTES_QUERY);
}
break;
}
/* Select action */
if (Stats->NumAction != ActAll)
{
sprintf (SubQuery," AND %s.ActCod=%ld",
LogTable,Act_GetActCod (Stats->NumAction));
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
}
/* End the query */
switch (Stats->ClicksGroupedBy)
{
case Sta_CLICKS_CRS_DETAILED_LIST:
Str_Concat (Query," ORDER BY F",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_CRS_PER_USR:
sprintf (SubQuery," GROUP BY %s.UsrCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_CRS_PER_DAY:
case Sta_CLICKS_GBL_PER_DAY:
Str_Concat (Query," GROUP BY Day"
" ORDER BY Day DESC",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_CRS_PER_DAY_AND_HOUR:
case Sta_CLICKS_GBL_PER_DAY_AND_HOUR:
Str_Concat (Query," GROUP BY Day,Hour"
" ORDER BY Day DESC,Hour",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_CRS_PER_WEEK:
case Sta_CLICKS_GBL_PER_WEEK:
Str_Concat (Query," GROUP BY Week"
" ORDER BY Week DESC",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_CRS_PER_MONTH:
case Sta_CLICKS_GBL_PER_MONTH:
Str_Concat (Query," GROUP BY Month"
" ORDER BY Month DESC",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_CRS_PER_YEAR:
case Sta_CLICKS_GBL_PER_YEAR:
Str_Concat (Query," GROUP BY Year"
" ORDER BY Year DESC",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_CRS_PER_HOUR:
case Sta_CLICKS_GBL_PER_HOUR:
Str_Concat (Query," GROUP BY Hour"
" ORDER BY Hour",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_CRS_PER_MINUTE:
case Sta_CLICKS_GBL_PER_MINUTE:
Str_Concat (Query," GROUP BY Minute"
" ORDER BY Minute",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_CRS_PER_ACTION:
case Sta_CLICKS_GBL_PER_ACTION:
sprintf (SubQuery," GROUP BY %s.ActCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_GBL_PER_PLUGIN:
Str_Concat (Query," GROUP BY log_api.PlgCod"
" ORDER BY Num DESC",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_GBL_PER_API_FUNCTION:
Str_Concat (Query," GROUP BY log_api.FunCod"
" ORDER BY Num DESC",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_GBL_PER_BANNER:
Str_Concat (Query," GROUP BY log_banners.BanCod"
" ORDER BY Num DESC",
Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_GBL_PER_COUNTRY:
sprintf (SubQuery," GROUP BY %s.CtyCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_GBL_PER_INSTITUTION:
sprintf (SubQuery," GROUP BY %s.InsCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_GBL_PER_CENTER:
sprintf (SubQuery," GROUP BY %s.CtrCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_GBL_PER_DEGREE:
sprintf (SubQuery," GROUP BY %s.DegCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
break;
case Sta_CLICKS_GBL_PER_COURSE:
sprintf (SubQuery," GROUP BY %s.CrsCod"
" ORDER BY Num DESC",
LogTable);
Str_Concat (Query,SubQuery,Sta_DB_MAX_BYTES_QUERY);
break;
}
/***** Write query for debug *****/
/*
if (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM)
Ale_ShowAlert (Ale_INFO,Query);
*/
/***** Make the query *****/
NumHits = (unsigned)
DB_QuerySELECT (mysql_res,"can not get clicks",
"%s",
Query);
/* Free memory for the query */
free (Query);
return NumHits;
}

52
swad_statistic_database.h Normal file
View File

@ -0,0 +1,52 @@
// swad_statistic_database.h: statistics, operations with database
#ifndef _SWAD_STA_DB
#define _SWAD_STA_DB
/*
SWAD (Shared Workspace At a Distance in Spanish),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2021 Antonio Cañas Vargas
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#include <mysql/mysql.h> // To access MySQL databases
// #include "swad_indicator.h"
// #include "swad_photo.h"
// #include "swad_user.h"
#include "swad_statistic.h"
/*****************************************************************************/
/************************** Public types and constants ***********************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Public prototypes *****************************/
/*****************************************************************************/
unsigned Sta_DB_GetHits (MYSQL_RES **mysql_res,
const struct Sta_Stats *Stats,
const char *LogTable,
const char BrowserTimeZone[Dat_MAX_BYTES_TIME_ZONE + 1],
unsigned NumUsrsInList,
const long LstSelectedUsrCods[]);
#endif

View File

@ -6343,7 +6343,7 @@ void Usr_CreateSubqueryUsrCods (long LstSelectedUsrCods[],
size_t MaxLength;
/***** Allocate space for subquery *****/
MaxLength = NumUsrsInList * (1 + Cns_MAX_DECIMAL_DIGITS_LONG);
MaxLength = (size_t) NumUsrsInList * (size_t) (1 + Cns_MAX_DECIMAL_DIGITS_LONG);
if ((*UsrsSubQuery = malloc (MaxLength + 1)) == NULL)
Err_NotEnoughMemoryExit ();
(*UsrsSubQuery)[0] = '\0';
@ -7221,7 +7221,7 @@ void Usr_ListAllDataStds (void)
/***** Allocate memory for the string with the list of group names where student belongs to *****/
if (Gbl.Scope.Current == HieLvl_CRS)
{
Length = (Grp_MAX_BYTES_GROUP_NAME + 2) * Gbl.Crs.Grps.GrpTypes.NumGrpsTotal;
Length = (size_t) (Grp_MAX_BYTES_GROUP_NAME + 2) * (size_t) Gbl.Crs.Grps.GrpTypes.NumGrpsTotal;
if ((GroupNames = malloc (Length + 1)) == NULL)
Err_NotEnoughMemoryExit ();
}