diff --git a/sql/swad.sql b/sql/swad.sql index 2faadfc26..30f0c59a4 100644 --- a/sql/swad.sql +++ b/sql/swad.sql @@ -1326,7 +1326,7 @@ CREATE TABLE IF NOT EXISTS usr_nicknames ( CREATE TABLE IF NOT EXISTS usr_report ( RepCod INT NOT NULL AUTO_INCREMENT, UsrCod INT NOT NULL, - ReportTime DATETIME NOT NULL, + ReportTimeUTC DATETIME NOT NULL, UniqueDirL CHAR(2) NOT NULL, UniqueDirR CHAR(41) NOT NULL, Filename VARCHAR(255) NOT NULL, diff --git a/swad_changelog.h b/swad_changelog.h index 11a2ea6f9..d11af99ef 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -146,13 +146,14 @@ /****************************** Public constants *****************************/ /*****************************************************************************/ -#define Log_PLATFORM_VERSION "SWAD 16.15 (2016-10-06)" +#define Log_PLATFORM_VERSION "SWAD 16.15.1 (2016-10-06)" #define CSS_FILE "swad15.229.css" #define JS_FILE "swad15.238.1.js" // 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 /* + Version 16.15.1: Oct 06, 2016 User's usage reports are stored into database. (205950 lines) Version 16.15: Oct 06, 2016 New database table to store user's usage reports. (205896 lines) Version 16.14: Oct 06, 2016 By default, teachers see (do not edit) documents. Now they must click on small edit icon to edit. (205875 lines) Version 16.13.2: Oct 05, 2016 User's usage report is open to any logged user. (205907 lines) diff --git a/swad_database.c b/swad_database.c index 88949cc03..aa75fa99f 100644 --- a/swad_database.c +++ b/swad_database.c @@ -2801,7 +2801,7 @@ mysql> DESCRIBE usr_report; DB_CreateTable ("CREATE TABLE IF NOT EXISTS usr_report (" "RepCod INT NOT NULL AUTO_INCREMENT," "UsrCod INT NOT NULL," - "ReportTime DATETIME NOT NULL," + "ReportTimeUTC DATETIME NOT NULL," "UniqueDirL CHAR(2) NOT NULL," // 2 leftmost chars from a unique 43 chars base64url codified from a unique SHA-256 string "UniqueDirR CHAR(41) NOT NULL," // 41 rightmost chars from a unique 43 chars base64url codified from a unique SHA-256 string "Filename VARCHAR(255) NOT NULL," // Report filename diff --git a/swad_report.c b/swad_report.c index 1292445ac..5431f07f7 100644 --- a/swad_report.c +++ b/swad_report.c @@ -93,40 +93,44 @@ static void Req_TitleReport (struct CurrentTimeUTC *CurrentTimeUTC); static void Rep_GetCurrentDateTimeUTC (struct CurrentTimeUTC *CurrentTimeUTC); -static void Rep_WriteHeader (struct CurrentTimeUTC *CurrentTimeUTC, +static void Rep_CreateNewReportFile (const struct CurrentTimeUTC *CurrentTimeUTC, + char *FilenameReport,char *Permalink); +static void Rep_CreateNewReportEntryIntoDB (const char *FilenameReport, + const char *Permalink); +static void Rep_WriteHeader (const struct CurrentTimeUTC *CurrentTimeUTC, const char *Permalink); static void Rep_WriteSectionPlatform (void); static void Rep_WriteSectionUsrInfo (void); -static void Rep_WriteSectionUsrFigures (struct UsrFigures *UsrFigures, - struct tm *tm_FirstClickTime, - struct CurrentTimeUTC *CurrentTimeUTC); -static void Rep_WriteSectionGlobalHits (struct UsrFigures *UsrFigures, - struct tm *tm_FirstClickTime); -static void Rep_WriteSectionCurrentCourses (struct UsrFigures *UsrFigures, - struct tm *tm_FirstClickTime, - struct CurrentTimeUTC *CurrentTimeUTC, +static void Rep_WriteSectionUsrFigures (const struct UsrFigures *UsrFigures, + const struct tm *tm_FirstClickTime, + const struct CurrentTimeUTC *CurrentTimeUTC); +static void Rep_WriteSectionGlobalHits (const struct UsrFigures *UsrFigures, + const struct tm *tm_FirstClickTime); +static void Rep_WriteSectionCurrentCourses (const struct UsrFigures *UsrFigures, + const struct tm *tm_FirstClickTime, + const struct CurrentTimeUTC *CurrentTimeUTC, unsigned long MaxHitsPerYear); -static void Rep_WriteSectionHistoricCourses (struct UsrFigures *UsrFigures, - struct tm *tm_FirstClickTime, +static void Rep_WriteSectionHistoricCourses (const struct UsrFigures *UsrFigures, + const struct tm *tm_FirstClickTime, unsigned long MaxHitsPerYear); static unsigned long Rep_GetMaxHitsPerYear (time_t FirstClickTimeUTC); static void Rep_GetAndWriteCurrentCrssOfAUsr (const struct UsrData *UsrDat,Rol_Role_t Role, time_t FirstClickTimeUTC, - struct tm *tm_FirstClickTime, + const struct tm *tm_FirstClickTime, unsigned long MaxHitsPerYear); static void Rep_GetAndWriteHistoricCrssOfAUsr (const struct UsrData *UsrDat,Rol_Role_t Role, time_t FirstClickTimeUTC, - struct tm *tm_FirstClickTime, + const struct tm *tm_FirstClickTime, unsigned long MaxHitsPerYear); static void Rep_WriteRowCrsData (long CrsCod,Rol_Role_t Role, time_t FirstClickTimeUTC, - struct tm *tm_FirstClickTime, + const struct tm *tm_FirstClickTime, unsigned long MaxHitsPerYear); static void Rep_ShowMyHitsPerYear (bool AnyCourse,long CrsCod,Rol_Role_t Role, time_t FirstClickTimeUTC, - struct tm *tm_FirstClickTime, + const struct tm *tm_FirstClickTime, unsigned long MaxHitsPerYear); static void Rep_DrawBarNumHits (float HitsNum,float HitsMax, unsigned MaxBarWidth); @@ -188,9 +192,6 @@ static void Rep_CreateMyUsageReport (struct CurrentTimeUTC *CurrentTimeUTC, { extern const char *Txt_Report_of_use_of_PLATFORM; struct UsrFigures UsrFigures; - char PathReports[PATH_MAX+1]; - char PathDirReport[PATH_MAX+1]; - char PathFileReport[PATH_MAX+1]; struct tm tm_FirstClickTime; bool GetUsrFiguresAgain; unsigned long MaxHitsPerYear; @@ -198,40 +199,11 @@ static void Rep_CreateMyUsageReport (struct CurrentTimeUTC *CurrentTimeUTC, /***** Get current date-time *****/ Rep_GetCurrentDateTimeUTC (CurrentTimeUTC); - /***** Path for reports *****/ - sprintf (PathReports,"%s/%s", - Cfg_PATH_SWAD_PUBLIC,Cfg_FOLDER_REP); - Fil_CreateDirIfNotExists (PathReports); + /***** Create a new report file *****/ + Rep_CreateNewReportFile (CurrentTimeUTC,FilenameReport,Permalink); - /***** Create a new report directory *****/ - /* Path of the public directory for the file with the report */ - sprintf (PathReports,"%s/%s/%c%c", - Cfg_PATH_SWAD_PUBLIC,Cfg_FOLDER_REP, - Gbl.UniqueNameEncrypted[0], - Gbl.UniqueNameEncrypted[1]); - Fil_CreateDirIfNotExists (PathReports); - sprintf (PathDirReport,"%s/%s", - PathReports, - &Gbl.UniqueNameEncrypted[2]); - if (mkdir (PathDirReport,(mode_t) 0xFFF)) - Lay_ShowErrorAndExit ("Can not create directory for report."); - - /* Path of the public file with the report */ - sprintf (FilenameReport,"%s_%06u_%06u.html", - Rep_FILENAME_ROOT,CurrentTimeUTC->Date,CurrentTimeUTC->Time); - sprintf (PathFileReport,"%s/%s", - PathDirReport,FilenameReport); - if ((Gbl.F.Rep = fopen (PathFileReport,"wb")) == NULL) - Lay_ShowErrorAndExit ("Can not create report file."); - - /* Permalink */ - sprintf (Permalink,"%s/%s/%c%c/%s/%s", - Cfg_URL_SWAD_PUBLIC, - Cfg_FOLDER_REP, - Gbl.UniqueNameEncrypted[0], - Gbl.UniqueNameEncrypted[1], - &Gbl.UniqueNameEncrypted[2], - FilenameReport); + /***** Store report entry into database *****/ + Rep_CreateNewReportEntryIntoDB (FilenameReport,Permalink); /***** Start file *****/ Lay_StartHTMLFile (Gbl.F.Rep,FilenameReport); @@ -378,11 +350,83 @@ static void Rep_GetCurrentDateTimeUTC (struct CurrentTimeUTC *CurrentTimeUTC) } } +/*****************************************************************************/ +/*************** Create a new file for user's usage report *******************/ +/*****************************************************************************/ + +static void Rep_CreateNewReportFile (const struct CurrentTimeUTC *CurrentTimeUTC, + char *FilenameReport,char *Permalink) + { + char PathReports[PATH_MAX+1]; + char PathUniqueDirL[PATH_MAX+1]; + char PathUniqueDirR[PATH_MAX+1]; + char PathFileReport[PATH_MAX+1]; + + /***** Path for reports *****/ + sprintf (PathReports,"%s/%s", + Cfg_PATH_SWAD_PUBLIC,Cfg_FOLDER_REP); + Fil_CreateDirIfNotExists (PathReports); + + /***** Unique directory for the file with the report *****/ + /* 1. Create a directory using the leftmost 2 chars of a unique name */ + sprintf (PathUniqueDirL,"%s/%s/%c%c", + Cfg_PATH_SWAD_PUBLIC,Cfg_FOLDER_REP, + Gbl.UniqueNameEncrypted[0], + Gbl.UniqueNameEncrypted[1]); + Fil_CreateDirIfNotExists (PathUniqueDirL); + + /* 2. Create a directory using the rightmost 41 chars of a unique name */ + sprintf (PathUniqueDirR,"%s/%s", + PathUniqueDirL, + &Gbl.UniqueNameEncrypted[2]); + if (mkdir (PathUniqueDirR,(mode_t) 0xFFF)) + Lay_ShowErrorAndExit ("Can not create directory for report."); + + /***** Path of the public file with the report */ + sprintf (FilenameReport,"%s_%06u_%06u.html", + Rep_FILENAME_ROOT,CurrentTimeUTC->Date,CurrentTimeUTC->Time); + sprintf (PathFileReport,"%s/%s", + PathUniqueDirR,FilenameReport); + if ((Gbl.F.Rep = fopen (PathFileReport,"wb")) == NULL) + Lay_ShowErrorAndExit ("Can not create report file."); + + /***** Permalink *****/ + sprintf (Permalink,"%s/%s/%c%c/%s/%s", + Cfg_URL_SWAD_PUBLIC, + Cfg_FOLDER_REP, + Gbl.UniqueNameEncrypted[0], + Gbl.UniqueNameEncrypted[1], + &Gbl.UniqueNameEncrypted[2], + FilenameReport); + } + +/*****************************************************************************/ +/************** Insert a new user's usage report into database ***************/ +/*****************************************************************************/ + +static void Rep_CreateNewReportEntryIntoDB (const char *FilenameReport, + const char *Permalink) + { + char Query[1024+PATH_MAX*2]; + + /***** Insert a new user's usage report into database *****/ + sprintf (Query,"INSERT INTO usr_report" + " (UsrCod,ReportTimeUTC,UniqueDirL,UniqueDirR,Filename,Permalink)" + " VALUES" + " ('%ld',UTC_TIMESTAMP(),'%c%c','%s','%s','%s')", + Gbl.Usrs.Me.UsrDat.UsrCod, + Gbl.UniqueNameEncrypted[0], // 2 leftmost chars from a unique 43 chars base64url codified from a unique SHA-256 string + Gbl.UniqueNameEncrypted[1], + &Gbl.UniqueNameEncrypted[2], // 41 rightmost chars from a unique 43 chars base64url codified from a unique SHA-256 string + FilenameReport,Permalink); + DB_QueryINSERT (Query,"can not create new report"); + } + /*****************************************************************************/ /******************** Write header of user's usage report ********************/ /*****************************************************************************/ -static void Rep_WriteHeader (struct CurrentTimeUTC *CurrentTimeUTC, +static void Rep_WriteHeader (const struct CurrentTimeUTC *CurrentTimeUTC, const char *Permalink) { extern const char *Txt_Report_of_use_of_PLATFORM; @@ -411,7 +455,6 @@ static void Rep_WriteHeader (struct CurrentTimeUTC *CurrentTimeUTC, CurrentTimeUTC->StrTime); /***** Permalink *****/ - /* fprintf (Gbl.F.Rep,"
  • %s: " "" @@ -420,7 +463,6 @@ static void Rep_WriteHeader (struct CurrentTimeUTC *CurrentTimeUTC, "
  • ", Txt_Permalink, Permalink,Permalink); - */ /***** End of header *****/ fprintf (Gbl.F.Rep,"" @@ -515,9 +557,9 @@ static void Rep_WriteSectionUsrInfo (void) /********* Write section for user's figures in user's usage report ***********/ /*****************************************************************************/ -static void Rep_WriteSectionUsrFigures (struct UsrFigures *UsrFigures, - struct tm *tm_FirstClickTime, - struct CurrentTimeUTC *CurrentTimeUTC) +static void Rep_WriteSectionUsrFigures (const struct UsrFigures *UsrFigures, + const struct tm *tm_FirstClickTime, + const struct CurrentTimeUTC *CurrentTimeUTC) { extern const char *Txt_Figures; extern const char *Txt_TIME_Since; @@ -686,8 +728,8 @@ static void Rep_WriteSectionUsrFigures (struct UsrFigures *UsrFigures, /******** Write section for user's global hits in user's usage report ********/ /*****************************************************************************/ -static void Rep_WriteSectionGlobalHits (struct UsrFigures *UsrFigures, - struct tm *tm_FirstClickTime) +static void Rep_WriteSectionGlobalHits (const struct UsrFigures *UsrFigures, + const struct tm *tm_FirstClickTime) { extern const char *Txt_Hits; @@ -711,9 +753,9 @@ static void Rep_WriteSectionGlobalHits (struct UsrFigures *UsrFigures, /****** Write section for user's current courses in user's usage report ******/ /*****************************************************************************/ -static void Rep_WriteSectionCurrentCourses (struct UsrFigures *UsrFigures, - struct tm *tm_FirstClickTime, - struct CurrentTimeUTC *CurrentTimeUTC, +static void Rep_WriteSectionCurrentCourses (const struct UsrFigures *UsrFigures, + const struct tm *tm_FirstClickTime, + const struct CurrentTimeUTC *CurrentTimeUTC, unsigned long MaxHitsPerYear) { extern const char *Txt_Courses; @@ -746,8 +788,8 @@ static void Rep_WriteSectionCurrentCourses (struct UsrFigures *UsrFigures, /***** Write section for user's historic courses in user's usage report ******/ /*****************************************************************************/ -static void Rep_WriteSectionHistoricCourses (struct UsrFigures *UsrFigures, - struct tm *tm_FirstClickTime, +static void Rep_WriteSectionHistoricCourses (const struct UsrFigures *UsrFigures, + const struct tm *tm_FirstClickTime, unsigned long MaxHitsPerYear) { extern const char *Txt_Courses; @@ -820,7 +862,7 @@ static unsigned long Rep_GetMaxHitsPerYear (time_t FirstClickTimeUTC) static void Rep_GetAndWriteCurrentCrssOfAUsr (const struct UsrData *UsrDat,Rol_Role_t Role, time_t FirstClickTimeUTC, - struct tm *tm_FirstClickTime, + const struct tm *tm_FirstClickTime, unsigned long MaxHitsPerYear) { extern const char *Txt_USER_in_COURSE; @@ -901,7 +943,7 @@ static void Rep_GetAndWriteCurrentCrssOfAUsr (const struct UsrData *UsrDat,Rol_R static void Rep_GetAndWriteHistoricCrssOfAUsr (const struct UsrData *UsrDat,Rol_Role_t Role, time_t FirstClickTimeUTC, - struct tm *tm_FirstClickTime, + const struct tm *tm_FirstClickTime, unsigned long MaxHitsPerYear) { extern const char *Txt_Hits_as_a_USER; @@ -965,7 +1007,7 @@ static void Rep_GetAndWriteHistoricCrssOfAUsr (const struct UsrData *UsrDat,Rol_ static void Rep_WriteRowCrsData (long CrsCod,Rol_Role_t Role, time_t FirstClickTimeUTC, - struct tm *tm_FirstClickTime, + const struct tm *tm_FirstClickTime, unsigned long MaxHitsPerYear) { extern const char *Txt_YEAR_OF_DEGREE[1+Deg_MAX_YEARS_PER_DEGREE]; @@ -1027,7 +1069,7 @@ static void Rep_WriteRowCrsData (long CrsCod,Rol_Role_t Role, static void Rep_ShowMyHitsPerYear (bool AnyCourse,long CrsCod,Rol_Role_t Role, time_t FirstClickTimeUTC, - struct tm *tm_FirstClickTime, + const struct tm *tm_FirstClickTime, unsigned long MaxHitsPerYear) { char Query[512];