diff --git a/Makefile b/Makefile index 776cd7bc..6c0bc4bc 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ OBJS = swad_account.o swad_action.o swad_announcement.o swad_assignment.o \ swad_calendar.o swad_centre.o swad_chat.o swad_config.o \ swad_connected.o swad_country.o swad_course.o swad_cryptography.o \ swad_database.o swad_date.o swad_degree.o swad_degree_type.o \ - swad_department.o \ + swad_department.o swad_duplicate.o \ swad_enrollment.o swad_exam.o \ swad_file.o swad_file_browser.o swad_follow.o swad_forum.o \ swad_global.o swad_group.o \ diff --git a/swad_account.c b/swad_account.c index 87a33fb0..c4f4685d 100644 --- a/swad_account.c +++ b/swad_account.c @@ -746,7 +746,7 @@ void Acc_CompletelyEliminateAccount (struct UsrData *UsrDat, DB_QueryDELETE (Query,"can not remove user's requests for inscription"); /***** Remove user from possible duplicate users *****/ - Usr_RemoveUsrFromDuplicated (UsrDat->UsrCod); + Dup_RemoveUsrFromDuplicated (UsrDat->UsrCod); /***** Remove user from the table of courses and users *****/ sprintf (Query,"DELETE FROM crs_usr" diff --git a/swad_action.c b/swad_action.c index 4d7ca24f..2ef0e575 100644 --- a/swad_action.c +++ b/swad_action.c @@ -2451,7 +2451,7 @@ struct Act_Actions Act_Actions[Act_NUM_ACTIONS] = /* ActReqRemOldUsr */{ 590,-1,TabUsr,ActLstOth ,0x100,0x100,0x100,Act_CONTENT_NORM,Act_MAIN_WINDOW,NULL ,Enr_AskRemoveOldUsrs ,NULL}, /* ActRemOldUsr */{ 773,-1,TabUsr,ActLstOth ,0x100,0x100,0x100,Act_CONTENT_NORM,Act_MAIN_WINDOW,NULL ,Enr_RemoveOldUsrs ,NULL}, - /* ActLstDupUsr */{1578,-1,TabUsr,ActLstOth ,0x100,0x100,0x100,Act_CONTENT_NORM,Act_MAIN_WINDOW,NULL ,Usr_ListDuplicateUsrs ,NULL}, + /* ActLstDupUsr */{1578,-1,TabUsr,ActLstOth ,0x100,0x100,0x100,Act_CONTENT_NORM,Act_MAIN_WINDOW,NULL ,Dup_ListDuplicateUsrs ,NULL}, /* ActLstClk */{ 989,-1,TabUsr,ActLstCon ,0x1FE,0x1FE,0x1FE,Act_CONTENT_NORM,Act_MAIN_WINDOW,NULL ,Con_ShowLastClicks ,NULL}, diff --git a/swad_changelog.h b/swad_changelog.h index 89f69354..8dea0fd5 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -128,13 +128,14 @@ /****************************** Public constants *****************************/ /*****************************************************************************/ -#define Log_PLATFORM_VERSION "SWAD 15.225.11 (2016-06-16)" +#define Log_PLATFORM_VERSION "SWAD 15.225.12 (2016-06-16)" #define CSS_FILE "swad15.225.11.css" #define JS_FILE "swad15.216.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 15.225.12:Jun 16, 2016 New module swad_duplicate for possible duplicate users. (202758 lines) Version 15.225.11:Jun 16, 2016 Listing possible duplicate users. (202667 lines) Version 15.225.10:Jun 15, 2016 Listing possible duplicate users. (202626 lines) Version 15.225.9: Jun 15, 2016 Code refactoring in list of students and teachers. (202636 lines) diff --git a/swad_duplicate.c b/swad_duplicate.c new file mode 100644 index 00000000..63ac3061 --- /dev/null +++ b/swad_duplicate.c @@ -0,0 +1,236 @@ +// swad_duplicate.c: duplicate users + +/* + 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-2016 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 3 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 . +*/ +/*****************************************************************************/ +/*********************************** Headers *********************************/ +/*****************************************************************************/ + +// #include // For isalnum, isdigit, etc. +// #include // For maximum values +// #include // For PATH_MAX +// #include // For NULL +// #include // For exit, system, malloc, free, rand, etc. +// #include // For string functions +// #include // For the macro WEXITSTATUS +// #include // For access, lstat, getpid, chdir, symlink, unlink + +#include "swad_database.h" +#include "swad_global.h" +#include "swad_layout.h" +#include "swad_role.h" +#include "swad_user.h" + +/*****************************************************************************/ +/****************************** Public constants *****************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/***************************** Private constants *****************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/****************************** Internal types *******************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/************** External global variables from others modules ****************/ +/*****************************************************************************/ + +extern struct Globals Gbl; + +/*****************************************************************************/ +/************************* Internal global variables *************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/***************************** Private prototypes ****************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/******************** Report a user as possible duplicate ********************/ +/*****************************************************************************/ + +void Dup_ReportUsrAsPossibleDuplicate (void) + { + extern const char *Txt_Thank_you_for_reporting_a_possible_duplicate_user; + extern const char *Txt_User_not_found_or_you_do_not_have_permission_; + char Query[256]; + bool ItsMe; + + /***** Get user to be reported as possible duplicate *****/ + if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) + { + /* Check if it's allowed to me to report users as possible duplicatedr */ + ItsMe = (Gbl.Usrs.Me.UsrDat.UsrCod == Gbl.Usrs.Other.UsrDat.UsrCod); + if (!ItsMe && Gbl.Usrs.Me.LoggedRole >= Rol_TEACHER) + { + /***** Insert possible duplicate into database *****/ + sprintf (Query,"REPLACE INTO usr_duplicated (UsrCod,InformerCod,InformTime)" + " VALUES ('%ld','%ld',NOW())", + Gbl.Usrs.Other.UsrDat.UsrCod, + Gbl.Usrs.Me.UsrDat.UsrCod); + DB_QueryINSERT (Query,"can not report duplicate"); + + /***** Show feedback message *****/ + Lay_ShowAlert (Lay_SUCCESS,Txt_Thank_you_for_reporting_a_possible_duplicate_user); + } + else + Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); + } + else + Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); + } + +/*****************************************************************************/ +/************ Put a link (form) to list possible duplicate users *************/ +/*****************************************************************************/ + +void Dup_PutLinkToListDupUsrs (void) + { + extern const char *Txt_Duplicate_USERS; + + /***** Put form to remove old users *****/ + Lay_PutContextualLink (ActLstDupUsr,NULL,"usrs64x64.gif", + Txt_Duplicate_USERS,Txt_Duplicate_USERS); + } + +/*****************************************************************************/ +/*********************** List possible duplicate users ***********************/ +/*****************************************************************************/ + +void Dup_ListDuplicateUsrs (void) + { + extern const char *Usr_UsrDatMainFieldNames[Usr_NUM_MAIN_FIELDS_DATA_USR]; + extern const char *Txt_Possibly_duplicate_users; + extern const char *Txt_Informants; + extern const char *Txt_No_users_found[Rol_NUM_ROLES]; + char Query[1024]; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumCol; + unsigned NumUsrs; + unsigned NumUsr; + struct UsrData UsrDat; + unsigned NumInformants; + + /***** Start frame with list of possible duplicate users *****/ + Lay_StartRoundFrame (NULL,Txt_Possibly_duplicate_users,NULL); + + /***** Build query *****/ + sprintf (Query,"SELECT UsrCod,COUNT(*) AS N,MIN(UNIX_TIMESTAMP(InformTime)) AS T" + " FROM usr_duplicated" + " GROUP BY UsrCod" + " ORDER BY N DESC,T DESC"); + NumUsrs = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get requests for enrollment"); + + /***** List possible duplicated users *****/ + if (NumUsrs) + { + /***** Initialize field names *****/ + Usr_SetUsrDatMainFieldNames (); + + /***** Initialize structure with user's data *****/ + Usr_UsrDataConstructor (&UsrDat); + + /***** Start table *****/ + fprintf (Gbl.F.Out,""); + + /***** Heading row with column names *****/ + /* Start row */ + fprintf (Gbl.F.Out,""); + for (NumCol = 0; + NumCol < Usr_NUM_MAIN_FIELDS_DATA_USR; + NumCol++) + fprintf (Gbl.F.Out,"", + Usr_UsrDatMainFieldNames[NumCol]); + + /* End row */ + fprintf (Gbl.F.Out,""); + + /***** List users *****/ + for (NumUsr = 0, Gbl.RowEvenOdd = 0; + NumUsr < NumUsrs; + NumUsr++) + { + row = mysql_fetch_row (mysql_res); + + /* Get user code (row[0]) */ + UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]); + if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat)) + { + UsrDat.Accepted = false; // TODO: Get this from database + + /* Write data of this user */ + Usr_WriteRowUsrMainData (NumUsrs - NumUsr,&UsrDat,false); + + /* Write number of informants (row[1]) if greater than 1 */ + if (sscanf (row[1],"%u",&NumInformants) != 1) + Lay_ShowErrorAndExit ("Wrong number of informers."); + if (NumInformants > 1) + fprintf (Gbl.F.Out,"" + "" + "" + "", + Usr_NUM_MAIN_FIELDS_DATA_USR-2, + Txt_Informants, + NumInformants); + + /* Write all the courses this user belongs to */ + Crs_GetAndWriteCrssOfAUsr (&UsrDat,Rol_TEACHER); + Crs_GetAndWriteCrssOfAUsr (&UsrDat,Rol_STUDENT); + + Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; + } + else // User does not exists ==> + // remove user from table of possible duplicate users + Dup_RemoveUsrFromDuplicated (UsrDat.UsrCod); + } + + /***** End table *****/ + fprintf (Gbl.F.Out,"
" + "%s " + "
%s: %u
"); + + /***** Free memory used for user's data *****/ + Usr_UsrDataDestructor (&UsrDat); + } + else // There are no users + Lay_ShowAlert (Lay_INFO,Txt_No_users_found[Rol_UNKNOWN]); + + /***** End frame *****/ + Lay_EndRoundFrame (); + } + +/*****************************************************************************/ +/********************* Remove a request for enrollment ***********************/ +/*****************************************************************************/ + +void Dup_RemoveUsrFromDuplicated (long UsrCod) + { + char Query[128]; + + /***** Remove enrollment request *****/ + sprintf (Query,"DELETE FROM usr_duplicated WHERE UsrCod='%ld'", + UsrCod); + DB_QueryDELETE (Query,"can not remove a user from possible duplicates"); + } diff --git a/swad_duplicate.h b/swad_duplicate.h new file mode 100644 index 00000000..f14a1b7c --- /dev/null +++ b/swad_duplicate.h @@ -0,0 +1,47 @@ +// swad_duplicate.h: duplicate users + +#ifndef _SWAD_DUP +#define _SWAD_DUP +/* + 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-2016 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 . +*/ +/*****************************************************************************/ +/********************************** Headers **********************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/****************************** Public constants *****************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/******************************** Public types *******************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/****************************** Public prototypes ****************************/ +/*****************************************************************************/ + +void Dup_ReportUsrAsPossibleDuplicate (void); +void Dup_PutLinkToListDupUsrs (void); +void Dup_ListDuplicateUsrs (void); +void Dup_RemoveUsrFromDuplicated (long UsrCod); + +#endif diff --git a/swad_enrollment.c b/swad_enrollment.c index a2c4f6ff..8392c6c9 100644 --- a/swad_enrollment.c +++ b/swad_enrollment.c @@ -3750,7 +3750,7 @@ void Enr_ModifyUsr (void) break; case Enr_REPORT_USR_AS_POSSIBLE_DUPLICATE: if (!ItsMe && Gbl.Usrs.Me.LoggedRole >= Rol_TEACHER) - Usr_ReportUsrAsPossibleDuplicate (); + Dup_ReportUsrAsPossibleDuplicate (); else Error = true; break; diff --git a/swad_user.c b/swad_user.c index 73fe7a60..e2592ab1 100644 --- a/swad_user.c +++ b/swad_user.c @@ -157,7 +157,6 @@ static Usr_Sex_t Usr_GetSexOfUsrsLst (struct ListUsers *LstUsrs); static void Usr_PutCheckboxToSelectUser (struct UsrData *UsrDat,bool UsrIsTheMsgSender); static void Usr_PutCheckboxListWithPhotos (void); -static void Usr_SetUsrDatMainFieldNames (void); static void Usr_ListMainDataGsts (bool PutCheckBoxToSelectUsr); static void Usr_ListMainDataStds (bool PutCheckBoxToSelectUsr); static void Usr_ListMainDataTchs (bool PutCheckBoxToSelectUsr); @@ -5072,7 +5071,7 @@ static void Usr_PutCheckboxListWithPhotos (void) /*********************** Set field names of user's data **********************/ /*****************************************************************************/ -static void Usr_SetUsrDatMainFieldNames (void) +void Usr_SetUsrDatMainFieldNames (void) { extern const char *Txt_No_INDEX; extern const char *Txt_Photo; @@ -5937,7 +5936,7 @@ void Usr_ListDataAdms (void) Enr_PutLinkToAdminOneUsr (ActReqMdfOneOth); /* Put link to list possible duplicate users */ - Usr_PutLinkToListDupUsrs (); + Dup_PutLinkToListDupUsrs (); /* Put link to remove old users */ Enr_PutLinkToRemOldUsrs (); @@ -7686,172 +7685,3 @@ void Usr_RemoveUsrFromUsrBanned (long UsrCod) UsrCod); DB_QueryDELETE (Query,"can not remove user from users banned"); } - -/*****************************************************************************/ -/******************** Report a user as possible duplicate ********************/ -/*****************************************************************************/ - -void Usr_ReportUsrAsPossibleDuplicate (void) - { - extern const char *Txt_Thank_you_for_reporting_a_possible_duplicate_user; - extern const char *Txt_User_not_found_or_you_do_not_have_permission_; - char Query[256]; - bool ItsMe; - - /***** Get user to be reported as possible duplicate *****/ - if (Usr_GetParamOtherUsrCodEncryptedAndGetUsrData ()) - { - /* Check if it's allowed to me to report users as possible duplicatedr */ - ItsMe = (Gbl.Usrs.Me.UsrDat.UsrCod == Gbl.Usrs.Other.UsrDat.UsrCod); - if (!ItsMe && Gbl.Usrs.Me.LoggedRole >= Rol_TEACHER) - { - /***** Insert possible duplicate into database *****/ - sprintf (Query,"REPLACE INTO usr_duplicated (UsrCod,InformerCod,InformTime)" - " VALUES ('%ld','%ld',NOW())", - Gbl.Usrs.Other.UsrDat.UsrCod, - Gbl.Usrs.Me.UsrDat.UsrCod); - DB_QueryINSERT (Query,"can not report duplicate"); - - /***** Show feedback message *****/ - Lay_ShowAlert (Lay_SUCCESS,Txt_Thank_you_for_reporting_a_possible_duplicate_user); - } - else - Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); - } - else - Lay_ShowAlert (Lay_WARNING,Txt_User_not_found_or_you_do_not_have_permission_); - } - -/*****************************************************************************/ -/************ Put a link (form) to list possible duplicate users *************/ -/*****************************************************************************/ - -void Usr_PutLinkToListDupUsrs (void) - { - extern const char *Txt_Duplicate_USERS; - - /***** Put form to remove old users *****/ - Lay_PutContextualLink (ActLstDupUsr,NULL,"usrs64x64.gif", - Txt_Duplicate_USERS,Txt_Duplicate_USERS); - } - -/*****************************************************************************/ -/*********************** List possible duplicate users ***********************/ -/*****************************************************************************/ - -void Usr_ListDuplicateUsrs (void) - { - extern const char *Txt_Possibly_duplicate_users; - extern const char *Txt_User[Usr_NUM_SEXS]; - extern const char *Txt_Informants; - extern const char *Txt_No_users_found[Rol_NUM_ROLES]; - char Query[1024]; - MYSQL_RES *mysql_res; - MYSQL_ROW row; - unsigned NumCol; - unsigned NumUsrs; - unsigned NumUsr; - struct UsrData UsrDat; - unsigned NumInformants; - - /***** Start frame with list of possible duplicate users *****/ - Lay_StartRoundFrame (NULL,Txt_Possibly_duplicate_users,NULL); - - /***** Build query *****/ - sprintf (Query,"SELECT UsrCod,COUNT(*) AS N,MIN(UNIX_TIMESTAMP(InformTime)) AS T" - " FROM usr_duplicated" - " GROUP BY UsrCod" - " ORDER BY N DESC,T DESC"); - NumUsrs = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get requests for enrollment"); - - /***** List possible duplicated users *****/ - if (NumUsrs) - { - /***** Initialize field names *****/ - Usr_SetUsrDatMainFieldNames (); - - /***** Initialize structure with user's data *****/ - Usr_UsrDataConstructor (&UsrDat); - - /***** Start table *****/ - fprintf (Gbl.F.Out,""); - - /***** Heading row with column names *****/ - /* Start row */ - fprintf (Gbl.F.Out,""); - for (NumCol = 0; - NumCol < Usr_NUM_MAIN_FIELDS_DATA_USR; - NumCol++) - fprintf (Gbl.F.Out,"", - Usr_UsrDatMainFieldNames[NumCol]); - - /* End row */ - fprintf (Gbl.F.Out,""); - - /***** List users *****/ - for (NumUsr = 0, Gbl.RowEvenOdd = 0; - NumUsr < NumUsrs; - NumUsr++) - { - row = mysql_fetch_row (mysql_res); - - /* Get user code (row[0]) */ - UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]); - if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat)) - { - UsrDat.Accepted = false; // TODO: Get this from database - - /* Write data of this user */ - Usr_WriteRowUsrMainData (NumUsrs - NumUsr,&UsrDat,false); - - /* Write number of informants (row[1]) if greater than 1 */ - if (sscanf (row[1],"%u",&NumInformants) != 1) - Lay_ShowErrorAndExit ("Wrong number of informers."); - if (NumInformants > 1) - fprintf (Gbl.F.Out,"" - "" - "" - "", - Usr_NUM_MAIN_FIELDS_DATA_USR-2, - Txt_Informants, - NumInformants); - - /* Write all the courses this user belongs to */ - Crs_GetAndWriteCrssOfAUsr (&UsrDat,Rol_TEACHER); - Crs_GetAndWriteCrssOfAUsr (&UsrDat,Rol_STUDENT); - - Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd; - } - else // User does not exists ==> - // remove user from table of possible duplicate users - Usr_RemoveUsrFromDuplicated (UsrDat.UsrCod); - } - - /***** End table *****/ - fprintf (Gbl.F.Out,"
" - "%s " - "
%s: %u
"); - - /***** Free memory used for user's data *****/ - Usr_UsrDataDestructor (&UsrDat); - } - else // There are no users - Lay_ShowAlert (Lay_INFO,Txt_No_users_found[Rol_UNKNOWN]); - - /***** End frame *****/ - Lay_EndRoundFrame (); - } - -/*****************************************************************************/ -/********************* Remove a request for enrollment ***********************/ -/*****************************************************************************/ - -void Usr_RemoveUsrFromDuplicated (long UsrCod) - { - char Query[128]; - - /***** Remove enrollment request *****/ - sprintf (Query,"DELETE FROM usr_duplicated WHERE UsrCod='%ld'", - UsrCod); - DB_QueryDELETE (Query,"can not remove a user from possible duplicates"); - } diff --git a/swad_user.h b/swad_user.h index aed609f7..803e0073 100644 --- a/swad_user.h +++ b/swad_user.h @@ -315,6 +315,8 @@ void Usr_FreeListOtherRecipients (void); void Usr_ShowFormsToSelectUsrListType (Act_Action_t NextAction); void Usr_PutCheckboxToSelectAllTheUsers (Rol_Role_t Role); unsigned Usr_GetColumnsForSelectUsrs (void); +void Usr_SetUsrDatMainFieldNames (void); + void Usr_PutExtraParamsUsrList (Act_Action_t NextAction); void Usr_ListUsersToSelect (Rol_Role_t Role); @@ -350,9 +352,9 @@ void Usr_GetAndShowNumUsrsInPlatform (Rol_Role_t Role); bool Usr_CheckIfUsrBanned (long UsrCod); void Usr_RemoveUsrFromUsrBanned (long UsrCod); -void Usr_ReportUsrAsPossibleDuplicate (void); -void Usr_PutLinkToListDupUsrs (void); -void Usr_ListDuplicateUsrs (void); -void Usr_RemoveUsrFromDuplicated (long UsrCod); +void Dup_ReportUsrAsPossibleDuplicate (void); +void Dup_PutLinkToListDupUsrs (void); +void Dup_ListDuplicateUsrs (void); +void Dup_RemoveUsrFromDuplicated (long UsrCod); #endif