Version 15.234

This commit is contained in:
Antonio Cañas Vargas 2016-06-29 18:27:49 +02:00
parent 9ebfc85f69
commit f104cf00de
9 changed files with 330 additions and 196 deletions

View File

@ -410,9 +410,11 @@ int swad__getTests (char *wsKey,int courseCode,long beginTime,
int swad__getTrivialQuestion (char *wsKey,char *degrees,float lowerScore,float upperScore,
struct swad__getTrivialQuestionOutput *getTrivialQuestionOut);
/* List of users of a course / group */
int swad__getUsers (char *wsKey,int courseCode,int groupCode,int userRole,
/* List of users */
int swad__getUsers (char *wsKey,int courseCode,char *groups,int userRole,
struct swad__getUsersOutput *getUsersOut);
int swad__findUsers (char *wsKey,int courseCode,char *filter,int userRole,
struct swad__getUsersOutput *getUsersOut);
/* Control of attendance */
int swad__getAttendanceEvents (char *wsKey,int courseCode,

View File

@ -70,7 +70,6 @@ typedef enum
static bool ID_CheckIfUsrIDIsValidUsingMinDigits (const char *UsrID,unsigned MinDigits);
static bool ID_ICanSeeAnotherUsrID (struct UsrData *UsrDat);
static void ID_PutButtonToReqConfirmID (struct UsrData *UsrDat,unsigned NumID);
static void ID_PutButtonToConfirmID (struct UsrData *UsrDat,unsigned NumID);
@ -405,7 +404,7 @@ void ID_WriteUsrIDs (struct UsrData *UsrDat)
/*****************************************************************************/
// This function should not be called when UsrDat->UsrCod == Gbl.Usrs.Me.UsrDat.UsrCod
static bool ID_ICanSeeAnotherUsrID (struct UsrData *UsrDat)
bool ID_ICanSeeAnotherUsrID (struct UsrData *UsrDat)
{
/***** Check if I have permission to see another user's IDs *****/
switch (Gbl.Usrs.Me.LoggedRole)

View File

@ -65,6 +65,7 @@ bool ID_CheckIfUsrIDIsValid (const char *UsrID);
bool ID_CheckIfUsrIDSeemsAValidID (const char *UsrID);
void ID_WriteUsrIDs (struct UsrData *UsrDat);
bool ID_ICanSeeAnotherUsrID (struct UsrData *UsrDat);
void ID_PutLinkToChangeUsrIDs (void);
void ID_ShowFormOthIDs (void);

View File

@ -121,6 +121,11 @@
// TODO: Messages in msg_content_deleted older than a certain time should be deleted to ensure the protection of personal data
// TODO: FIX BUG: A teacher uploads a document in course documents zone, then he/she unregister from course, then he/she search for his/her documents, a document is shown in results but he/she can not view it
// TODO: Add Stack Exchange to webs/networks
// TODO: Optimize slow query searching messages received
// TODO: FIX BUG: Searching messages received gives unordered list
// TODO: Add file size to summary in notifications of new files.
// TODO: Put Raúl Hinojosa (iSWAD developer) in a row of marks file of EC (B,C) and publish file
// TODO: Modify WS function getUsers changing: userRole to indicate all users, and a new parameter filter (search string (name, @nickname, mail)) to restring number of users
// TODO: Add a new WS function to count the nunmber of users to return in call to function getUsers
@ -129,13 +134,14 @@
/****************************** Public constants *****************************/
/*****************************************************************************/
#define Log_PLATFORM_VERSION "SWAD 15.233.4 (2016-06-27)"
#define Log_PLATFORM_VERSION "SWAD 15.234 (2016-06-29)"
#define CSS_FILE "swad15.229.css"
#define JS_FILE "swad15.226.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.234: Jun 29, 2015 New web service functions getUsers and findUsers. (203169 lines)
Version 15.233.4: Jun 27, 2015 Changes in links in list of notifications. (203065 lines)
Version 15.233.3: Jun 27, 2015 Fixed bug in list of admins. (203074 lines)
Version 15.233.2: Jun 27, 2015 Code refactoring in search of users. (203072 lines)

View File

@ -41,11 +41,8 @@
/***************************** Internal constants ****************************/
/*****************************************************************************/
#define Sch_MAX_WORDS_IN_SEARCH 10
#define Sch_MAX_LENGTH_SEARCH_WORD 255
#define Sch_MIN_LENGTH_LONGEST_WORD 3
#define Sch_MIN_LENGTH_TOTAL 7 // "A An Ann" is not valid; "A An Ann Anna" is valid
#define Sch_MAX_LENGTH_SEARCH_QUERY (10*Sch_MAX_LENGTH_STRING_TO_FIND)
/*****************************************************************************/
/****************************** Internal types *******************************/
@ -77,8 +74,6 @@ static unsigned Sch_SearchUsrsInDB (Rol_Role_t Role);
static unsigned Sch_SearchOpenDocumentsInDB (const char *RangeQuery);
static unsigned Sch_SearchDocumentsInMyCoursesInDB (const char *RangeQuery);
static unsigned Sch_SearchMyDocumentsInDB (const char *RangeQuery);
static bool Sch_BuildSearchQuery (char *SearchQuery,const char *FieldName,
const char *CharSet,const char *Collate);
static void Sch_SaveLastSearchIntoSession (void);
@ -793,25 +788,29 @@ static unsigned Sch_SearchCoursesInDB (const char *RangeQuery)
}
/*****************************************************************************/
/************************* Search teachers in database ***********************/
/*************************** Search users in database ************************/
/*****************************************************************************/
// Returns number of teachers found
// Returns number of users found
static unsigned Sch_SearchUsrsInDB (Rol_Role_t Role)
{
extern const char *Txt_The_search_text_must_be_longer;
static bool WarningMessageWritten = false;
char SearchQuery[Sch_MAX_LENGTH_SEARCH_QUERY+1];
/***** Check user's permission *****/
if (Sch_CheckIfIHavePermissionToSearch ( Role == Rol_UNKNOWN ? Sch_SEARCH_USERS :
(Role == Rol_TEACHER ? Sch_SEARCH_TEACHERS :
(Role == Rol_STUDENT ? Sch_SEARCH_STUDENTS :
Sch_SEARCH_GUESTS))))
/***** Split user string into words *****/
if (Sch_BuildSearchQuery (SearchQuery,
"CONCAT_WS(' ',usr_data.FirstName,usr_data.Surname1,usr_data.Surname2)",
NULL,NULL))
/***** Query database and list users found *****/
return Usr_ListUsrsFound (Role,SearchQuery);
/***** Split user string into words *****/
if (Sch_BuildSearchQuery (SearchQuery,
"CONCAT_WS(' ',FirstName,Surname1,Surname2)",
NULL,NULL))
/***** Query database and list users found *****/
return Usr_ListUsrsFound (Role,SearchQuery);
else
// Too short
if (!WarningMessageWritten) // To avoid repetitions
{
Lay_ShowAlert (Lay_WARNING,Txt_The_search_text_must_be_longer);
WarningMessageWritten = true;
}
return 0;
}
@ -1215,11 +1214,9 @@ static unsigned Sch_SearchMyDocumentsInDB (const char *RangeQuery)
// Returns true if a valid search query is built
// Returns false when no valid search query
static bool Sch_BuildSearchQuery (char *SearchQuery,const char *FieldName,
const char *CharSet,const char *Collate)
bool Sch_BuildSearchQuery (char *SearchQuery,const char *FieldName,
const char *CharSet,const char *Collate)
{
extern const char *Txt_The_search_text_must_be_longer;
static bool WarningMessageWritten = false;
const char *Ptr;
unsigned NumWords;
unsigned NumWord;
@ -1229,74 +1226,71 @@ static bool Sch_BuildSearchQuery (char *SearchQuery,const char *FieldName,
char SearchWords[Sch_MAX_WORDS_IN_SEARCH][Sch_MAX_LENGTH_SEARCH_WORD+1];
bool SearchWordIsValid = true;
SearchQuery[0] = '\0';
Ptr = Gbl.Search.Str;
for (NumWords = 0;
NumWords < Sch_MAX_WORDS_IN_SEARCH && *Ptr;
NumWords++)
if (Gbl.Search.Str[0])
{
/* Get next word */
Str_GetNextStringUntilSpace (&Ptr,SearchWords[NumWords],Sch_MAX_LENGTH_SEARCH_WORD);
/* Is this word valid? */
switch (Gbl.Search.WhatToSearch)
{
case Sch_SEARCH_OPEN_DOCUMENTS:
case Sch_SEARCH_DOCUM_IN_MY_COURSES:
case Sch_SEARCH_MY_DOCUMENTS:
SearchWordIsValid = Str_ConvertFilFolLnkNameToValid (SearchWords[NumWords]);
break;
default:
SearchWordIsValid = true;
break;
}
/* Check if this word is repeated (case insensitive) */
for (NumWord = 0;
SearchWordIsValid && NumWord < NumWords;
NumWord++)
if (!strcasecmp (SearchWords[NumWord],SearchWords[NumWords]))
SearchWordIsValid = false;
/* Concatenate word to search string */
if (SearchWordIsValid)
SearchQuery[0] = '\0';
Ptr = Gbl.Search.Str;
for (NumWords = 0;
NumWords < Sch_MAX_WORDS_IN_SEARCH && *Ptr;
NumWords++)
{
LengthWord = strlen (SearchWords[NumWords]);
LengthTotal += LengthWord;
if (LengthWord > MaxLengthWord)
MaxLengthWord = LengthWord;
if (strlen (SearchQuery) + LengthWord + 512 > Sch_MAX_LENGTH_SEARCH_QUERY) // Prevent string overflow
break;
if (NumWords)
strcat (SearchQuery," AND ");
strcat (SearchQuery,FieldName);
strcat (SearchQuery," LIKE ");
if (CharSet)
if (CharSet[0])
strcat (SearchQuery,CharSet);
strcat (SearchQuery,"'%");
strcat (SearchQuery,SearchWords[NumWords]);
strcat (SearchQuery,"%'");
if (Collate)
if (Collate[0])
strcat (SearchQuery,Collate);
}
}
/* Get next word */
Str_GetNextStringUntilSpace (&Ptr,SearchWords[NumWords],Sch_MAX_LENGTH_SEARCH_WORD);
/***** If search string valid? *****/
if (LengthTotal < Sch_MIN_LENGTH_TOTAL ||
MaxLengthWord < Sch_MIN_LENGTH_LONGEST_WORD)
{
// Too short
if (!WarningMessageWritten) // To avoid repetitions
{
Lay_ShowAlert (Lay_WARNING,Txt_The_search_text_must_be_longer);
WarningMessageWritten = true;
/* Is this word valid? */
switch (Gbl.Search.WhatToSearch)
{
case Sch_SEARCH_OPEN_DOCUMENTS:
case Sch_SEARCH_DOCUM_IN_MY_COURSES:
case Sch_SEARCH_MY_DOCUMENTS:
SearchWordIsValid = Str_ConvertFilFolLnkNameToValid (SearchWords[NumWords]);
break;
default:
SearchWordIsValid = true;
break;
}
/* Check if this word is repeated (case insensitive) */
for (NumWord = 0;
SearchWordIsValid && NumWord < NumWords;
NumWord++)
if (!strcasecmp (SearchWords[NumWord],SearchWords[NumWords]))
SearchWordIsValid = false;
/* Concatenate word to search string */
if (SearchWordIsValid)
{
LengthWord = strlen (SearchWords[NumWords]);
LengthTotal += LengthWord;
if (LengthWord > MaxLengthWord)
MaxLengthWord = LengthWord;
if (strlen (SearchQuery) + LengthWord + 512 > Sch_MAX_LENGTH_SEARCH_QUERY) // Prevent string overflow
break;
if (NumWords)
strcat (SearchQuery," AND ");
strcat (SearchQuery,FieldName);
strcat (SearchQuery," LIKE ");
if (CharSet)
if (CharSet[0])
strcat (SearchQuery,CharSet);
strcat (SearchQuery,"'%");
strcat (SearchQuery,SearchWords[NumWords]);
strcat (SearchQuery,"%'");
if (Collate)
if (Collate[0])
strcat (SearchQuery,Collate);
}
}
return false;
}
else
/***** If search string valid? *****/
if (LengthTotal < Sch_MIN_LENGTH_TOTAL ||
MaxLengthWord < Sch_MIN_LENGTH_LONGEST_WORD)
return false;
return true;
}
return false;
}
/*****************************************************************************/

View File

@ -31,7 +31,10 @@
/****************************** Public constants *****************************/
/*****************************************************************************/
#define Sch_MAX_LENGTH_STRING_TO_FIND 255
#define Sch_MAX_LENGTH_STRING_TO_FIND 255
#define Sch_MAX_WORDS_IN_SEARCH 10
#define Sch_MAX_LENGTH_SEARCH_WORD 255
#define Sch_MAX_LENGTH_SEARCH_QUERY (Sch_MAX_WORDS_IN_SEARCH*Sch_MAX_LENGTH_SEARCH_WORD)
/*****************************************************************************/
/******************************** Public types *******************************/
@ -78,4 +81,7 @@ void Sch_CtrSearch (void);
void Sch_DegSearch (void);
void Sch_CrsSearch (void);
bool Sch_BuildSearchQuery (char *SearchQuery,const char *FieldName,
const char *CharSet,const char *Collate);
#endif

View File

@ -142,9 +142,6 @@ static void Usr_WriteUsrData (const char *BgColor,
bool NonBreak,bool Accepted);
static void Usr_BuildQueryToGetUsrsLstCrs (Rol_Role_t Role,char *Query);
static void Usr_SearchListUsrs (Rol_Role_t Role);
static void Usr_CreateTmpTableAndSearchCandidateUsrs (const char *UsrQuery);
static void Usr_DropTmpTableWithCandidateUsrs (void);
static void Usr_GetAdmsLst (Sco_Scope_t Scope);
static void Usr_GetGstsLst (Sco_Scope_t Scope);
@ -3802,7 +3799,7 @@ void Usr_GetListUsrs (Rol_Role_t Role,Sco_Scope_t Scope)
/********* Search list of users with a given role in current scope ***********/
/*****************************************************************************/
static void Usr_SearchListUsrs (Rol_Role_t Role)
void Usr_SearchListUsrs (Rol_Role_t Role)
{
char Query[4*1024];
const char *OrderQuery = "candidate_users.UsrCod=usr_data.UsrCod"
@ -4011,7 +4008,7 @@ static void Usr_SearchListUsrs (Rol_Role_t Role)
/*************** Create temporary table with candidate users *****************/
/*****************************************************************************/
static void Usr_CreateTmpTableAndSearchCandidateUsrs (const char *UsrQuery)
void Usr_CreateTmpTableAndSearchCandidateUsrs (const char *SearchQuery)
{
char Query[16*1024];
@ -4024,7 +4021,7 @@ static void Usr_CreateTmpTableAndSearchCandidateUsrs (const char *UsrQuery)
sprintf (Query,"CREATE TEMPORARY TABLE candidate_users"
" (UsrCod INT NOT NULL,UNIQUE INDEX(UsrCod)) ENGINE=MEMORY"
" SELECT UsrCod FROM usr_data WHERE %s",
UsrQuery);
SearchQuery);
if (mysql_query (&Gbl.mysql,Query))
DB_ExitOnMySQLError ("can not create temporary table");
}
@ -4033,7 +4030,7 @@ static void Usr_CreateTmpTableAndSearchCandidateUsrs (const char *UsrQuery)
/***************** Drop temporary table with candidate users *****************/
/*****************************************************************************/
static void Usr_DropTmpTableWithCandidateUsrs (void)
void Usr_DropTmpTableWithCandidateUsrs (void)
{
char Query[128];
@ -5802,24 +5799,24 @@ void Usr_ListAllDataTchs (void)
/*****************************************************************************/
// Returns number of users found
unsigned Usr_ListUsrsFound (Rol_Role_t Role,const char *UsrQuery)
unsigned Usr_ListUsrsFound (Rol_Role_t Role,const char *SearchQuery)
{
extern const char *Txt_user[Usr_NUM_SEXS];
extern const char *Txt_users[Usr_NUM_SEXS];
extern const char *Txt_ROLES_PLURAL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
extern const char *Txt_ROLES_SINGUL_abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
extern const char *Txt_ROLES_PLURAL_abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
Usr_Sex_t Sex;
unsigned NumUsrs;
unsigned NumUsr;
struct UsrData UsrDat;
unsigned NumUsrs;
Usr_Sex_t Sex;
/***** Initialize field names *****/
Usr_SetUsrDatMainFieldNames ();
/***** Create temporary table with candidate users *****/
// Search is faster (aproximately x2) using temporary tables
Usr_CreateTmpTableAndSearchCandidateUsrs (UsrQuery);
Usr_CreateTmpTableAndSearchCandidateUsrs (SearchQuery);
/***** Search for users *****/
Usr_SearchListUsrs (Role);
@ -5884,7 +5881,7 @@ unsigned Usr_ListUsrsFound (Rol_Role_t Role,const char *UsrQuery)
/***** Free memory for teachers list *****/
Usr_FreeUsrsList (Role);
/***** Drop temporary tables *****/
/***** Drop temporary table with candidate users *****/
Usr_DropTmpTableWithCandidateUsrs ();
return NumUsrs;

View File

@ -305,6 +305,10 @@ unsigned Usr_GetNumberOfTeachersInCentre (long CtrCod);
void Usr_GetListUsrs (Rol_Role_t Role,Sco_Scope_t Scope);
void Usr_SearchListUsrs (Rol_Role_t Role);
void Usr_CreateTmpTableAndSearchCandidateUsrs (const char *UsrQuery);
void Usr_DropTmpTableWithCandidateUsrs (void);
void Usr_GetUnorderedStdsCodesInDeg (long DegCod);
void Usr_FreeUsrsList (Rol_Role_t Role);
bool Usr_GetIfShowBigList (unsigned NumUsrs);
@ -332,7 +336,7 @@ void Usr_ListAllDataGsts (void);
void Usr_ListAllDataStds (void);
void Usr_ListUsrsForSelection (Rol_Role_t Role);
void Usr_ListAllDataTchs (void);
unsigned Usr_ListUsrsFound (Rol_Role_t Role,const char *UsrQuery);
unsigned Usr_ListUsrsFound (Rol_Role_t Role,const char *SearchQuery);
void Usr_ListDataAdms (void);
void Usr_GetAndUpdatePrefsAboutUsrList (void);

View File

@ -109,6 +109,7 @@ cp -f /home/acanas/swad/swad/swad /var/www/cgi-bin/
#include "swad_notice.h"
#include "swad_notification.h"
#include "swad_password.h"
#include "swad_search.h"
#include "swad_user.h"
#include "swad_web_service.h"
@ -179,13 +180,15 @@ static int Svc_CheckParamsNewAccount (char *NewNicknameWithArroba, // Input
char *NewPlainPassword, // Input
char *NewEncryptedPassword); // Output
static void Svc_CopyListUsers (Rol_Role_t Role,struct swad__getUsersOutput *getUsersOut);
static void Svc_CopyUsrData (struct swad__user *Usr,struct UsrData *UsrDat,bool UsrIDIsVisible);
static void Svc_GetListGrpsInAttendanceEvent (long AttCod,char **ListGroups);
static void Svc_GetListGrpsInAttendanceEventFromDB (long AttCod,char **ListGroups);
static void Svc_GetLstGrpsSel (const char *Groups);
static int Svc_GetMyLanguage (void);
static int Svc_sendMessageToUsr (long OriginalMsgCod,long SenderUsrCod,long ReplyUsrCod,long RecipientUsrCod,bool NotifyByEmail,const char *Subject,const char *Content);
static int Svc_SendMessageToUsr (long OriginalMsgCod,long SenderUsrCod,long ReplyUsrCod,long RecipientUsrCod,bool NotifyByEmail,const char *Subject,const char *Content);
static int Svc_GetTstConfig (long CrsCod);
static int Svc_GetNumTestQuestionsInCrs (long CrsCod);
@ -1340,25 +1343,20 @@ int swad__getCourseInfo (struct soap *soap,
}
/*****************************************************************************/
/********************** Return students in a course **************************/
/************* Get users in a course (and optionally in groups) **************/
/*****************************************************************************/
// If groupCode <= 0 ==> get users from the whole course
int swad__getUsers (struct soap *soap,
char *wsKey,int courseCode,int groupCode,int userRole, // input
char *wsKey,int courseCode,char *groups,int userRole, // input
struct swad__getUsersOutput *getUsersOut) // output
{
int ReturnCode;
char Query[512];
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRow,NumRows;
bool UsrIDIsVisible;
Rol_Role_t Role;
Gbl.soap = soap;
Gbl.WebService.Function = Svc_getUsers;
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
Gbl.CurrentCrs.Grps.GrpCod = (long) groupCode;
Gbl.CurrentCrs.Crs.CrsCod = (courseCode > 0) ? (long) courseCode :
-1L;
/***** Check web service key *****/
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
@ -1368,8 +1366,8 @@ int swad__getUsers (struct soap *soap,
"Bad web service key",
"Web service key does not exist in database");
/***** Check course and group codes *****/
if ((ReturnCode = Svc_CheckCourseAndGroupCodes (Gbl.CurrentCrs.Crs.CrsCod,Gbl.CurrentCrs.Grps.GrpCod)) != SOAP_OK)
/***** Check course *****/
if ((ReturnCode = Svc_CheckCourseAndGroupCodes (Gbl.CurrentCrs.Crs.CrsCod,-1L)) != SOAP_OK)
return ReturnCode;
/***** Get some of my data *****/
@ -1382,78 +1380,194 @@ int swad__getUsers (struct soap *soap,
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
return soap_receiver_fault (Gbl.soap,
"Request forbidden",
"Requester must belong to course");
"Request forbidden",
"Requester must belong to course");
/***** Get degree of current course *****/
if ((ReturnCode = Svc_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK)
if ((ReturnCode = Svc_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK) // TODO: Is this necessary?
return ReturnCode;
/***** Check requested users' type *****/
if (userRole != 2 && // student
userRole != 3) // teacher
{
sprintf (Gbl.Message,"Only students (user's type = %u) or teachers (user's type = %u) are allowed",
(unsigned) 2, // student
(unsigned) 3); // teacher
/***** Check requested users' role *****/
if (userRole < 2 || // Students
userRole > 3) // Teachers
return soap_sender_fault (Gbl.soap,
"Bad requested users' type",
Gbl.Message);
}
"User roles allowed are 2 (students) or 3 (teachers)");
Role = (Rol_Role_t) userRole;
/***** Query users beloging to course or group from database *****/
if (groupCode <= 0) // Users belonging to the whole course
sprintf (Query,"SELECT usr_data.UsrCod"
" FROM crs_usr,usr_data"
" WHERE crs_usr.CrsCod='%ld' AND crs_usr.UsrCod=usr_data.UsrCod AND crs_usr.Role='%d'"
" ORDER BY usr_data.Surname1,usr_data.Surname2,usr_data.FirstName,usr_data.UsrCod",
(long) courseCode,
userRole == 2 ? (unsigned) Rol_STUDENT :
(unsigned) Rol_TEACHER);
else // Users belonging to the group
sprintf (Query,"SELECT usr_data.UsrCod"
" FROM crs_grp_usr,crs_usr,usr_data"
" WHERE crs_grp_usr.GrpCod='%ld' AND crs_grp_usr.UsrCod=crs_usr.UsrCod AND crs_grp_usr.UsrCod=usr_data.UsrCod AND crs_usr.Role='%d'"
" ORDER BY usr_data.Surname1,usr_data.Surname2,usr_data.FirstName,usr_data.UsrCod",
(long) groupCode,
userRole == 2 ? (unsigned) Rol_STUDENT :
(unsigned) Rol_TEACHER);
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get users");
/***** Create a list of groups selected *****/
Svc_GetLstGrpsSel (groups);
if (Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps)
/***** Get list of groups types and groups in current course *****/
Grp_GetListGrpTypesInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
getUsersOut->numUsers = (int) NumRows;
getUsersOut->usersArray.__size = (int) NumRows;
/***** Get list of users *****/
Usr_GetListUsrs (Role,Sco_SCOPE_CRS);
Svc_CopyListUsers (Role,getUsersOut);
Usr_FreeUsrsList (Role);
if (NumRows == 0)
getUsersOut->usersArray.__ptr = NULL;
else // Users found
if (Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps)
{
getUsersOut->usersArray.__ptr = soap_malloc (Gbl.soap,(getUsersOut->usersArray.__size) * sizeof (*(getUsersOut->usersArray.__ptr)));
/***** Free list of groups types and groups in current course *****/
Grp_FreeListGrpTypesAndGrps ();
/***** Users' IDs are visible? *****/
UsrIDIsVisible = (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB == Rol_STUDENT &&
userRole == 2); // get students in the course
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next user */
row = mysql_fetch_row (mysql_res);
/* Get user's code (row[0]) */
if ((Gbl.Usrs.Other.UsrDat.UsrCod = (long) Str_ConvertStrCodToLongCod (row[0])) > 0)
/* Get user's data */
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat))
/* Copy user's data into output structure */
Svc_CopyUsrData (&(getUsersOut->usersArray.__ptr[NumRow]),&Gbl.Usrs.Other.UsrDat,UsrIDIsVisible);
}
/***** Free memory for list of selected groups *****/
Grp_FreeListCodSelectedGrps ();
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
int swad__findUsers (struct soap *soap,
char *wsKey,int courseCode,char *filter,int userRole, // input
struct swad__getUsersOutput *getUsersOut) // output
{
int ReturnCode;
char SearchQuery[Sch_MAX_LENGTH_SEARCH_QUERY+1];
Rol_Role_t Role;
bool FilterTooShort = false;
Gbl.soap = soap;
Gbl.WebService.Function = Svc_getUsers;
Gbl.CurrentCrs.Crs.CrsCod = (courseCode > 0) ? (long) courseCode :
-1L;
/***** Check web service key *****/
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
return soap_receiver_fault (Gbl.soap,
"Bad web service key",
"Web service key does not exist in database");
if (Gbl.CurrentCrs.Crs.CrsCod > 0)
/***** Check course *****/
if ((ReturnCode = Svc_CheckCourseAndGroupCodes (Gbl.CurrentCrs.Crs.CrsCod,-1L)) != SOAP_OK)
return ReturnCode;
/***** Get some of my data *****/
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
return ReturnCode;
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
if (Gbl.CurrentCrs.Crs.CrsCod > 0)
/***** Check if I am a student or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
return soap_receiver_fault (Gbl.soap,
"Request forbidden",
"Requester must belong to course");
if (Gbl.CurrentCrs.Crs.CrsCod > 0)
{
/***** Get degree of current course *****/
if ((ReturnCode = Svc_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK) // TODO: Is this necessary?
return ReturnCode;
}
/***** Check requested users' role *****/
if (userRole < 0 ||
userRole > 3)
return soap_sender_fault (Gbl.soap,
"Bad requested users' type",
"User roles allowed are 0 (all),1 (guests), 2 (students) or 3 (teachers)");
Role = (Rol_Role_t) userRole;
/***** Query users beloging to course or group from database *****/
strncpy (Gbl.Search.Str,filter,Sch_MAX_LENGTH_STRING_TO_FIND);
Gbl.Search.Str[Sch_MAX_LENGTH_STRING_TO_FIND] = '\0';
if (Gbl.Search.Str[0]) // Search some users
{
Gbl.Scope.Current = (Gbl.CurrentCrs.Crs.CrsCod > 0) ? Sco_SCOPE_CRS :
Sco_SCOPE_SYS;
if (Sch_BuildSearchQuery (SearchQuery,
"CONCAT_WS(' ',FirstName,Surname1,Surname2)",
NULL,NULL))
{
/***** Create temporary table with candidate users *****/
// Search is faster (aproximately x2) using temporary tables
Usr_CreateTmpTableAndSearchCandidateUsrs (SearchQuery);
/***** Search for users *****/
Usr_SearchListUsrs (Role);
Svc_CopyListUsers (Role,getUsersOut);
Usr_FreeUsrsList (Role);
/***** Drop temporary table with candidate users *****/
Usr_DropTmpTableWithCandidateUsrs ();
}
else
FilterTooShort = true;
}
else
FilterTooShort = true;
/***** Return error in filter? *****/
if (FilterTooShort)
{
getUsersOut->numUsers = -1; // < 0 ==> filter too short
getUsersOut->usersArray.__size = 0;
getUsersOut->usersArray.__ptr = NULL;
}
return SOAP_OK;
}
/*****************************************************************************/
/***************************** Copy users from list **************************/
/*****************************************************************************/
static void Svc_CopyListUsers (Rol_Role_t Role,struct swad__getUsersOutput *getUsersOut)
{
unsigned NumUsrs;
unsigned NumUsr;
struct UsrData UsrDat;
bool ICanSeeUsrID;
/***** Initialize result *****/
getUsersOut->numUsers = 0;
getUsersOut->usersArray.__size = 0;
getUsersOut->usersArray.__ptr = NULL;
NumUsrs = Gbl.Usrs.LstUsrs[Role].NumUsrs;
if (NumUsrs)
{
getUsersOut->numUsers = (int) NumUsrs;
getUsersOut->usersArray.__size = (int) NumUsrs;
getUsersOut->usersArray.__ptr = soap_malloc (Gbl.soap,(getUsersOut->usersArray.__size) * sizeof (*(getUsersOut->usersArray.__ptr)));
/***** Initialize structure with user's data *****/
Usr_UsrDataConstructor (&UsrDat);
/***** List data of users *****/
for (NumUsr = 0;
NumUsr < NumUsrs;
NumUsr++)
{
UsrDat.UsrCod = Gbl.Usrs.LstUsrs[Role].Lst[NumUsr].UsrCod;
/* Get user's data */
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat)) // If user's data exist...
{
UsrDat.Accepted = Gbl.Usrs.LstUsrs[Role].Lst[NumUsr].Accepted;
if (Gbl.Usrs.Me.UsrDat.UsrCod == UsrDat.UsrCod) // It's me
ICanSeeUsrID = true;
else // A user distinct than me
ICanSeeUsrID = ID_ICanSeeAnotherUsrID (&UsrDat);
/* Copy user's data into output structure */
Svc_CopyUsrData (&(getUsersOut->usersArray.__ptr[NumUsr]),&UsrDat,ICanSeeUsrID);
}
}
/***** Free memory used for user's data *****/
Usr_UsrDataDestructor (&UsrDat);
}
}
/*****************************************************************************/
/********************** Return group types in a course ***********************/
/*****************************************************************************/
@ -2026,7 +2140,7 @@ int swad__getAttendanceEvents (struct soap *soap,
row[6]);
/* Get list of groups for this attendance event */
Svc_GetListGrpsInAttendanceEvent (AttCod,&(getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].groups));
Svc_GetListGrpsInAttendanceEventFromDB (AttCod,&(getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].groups));
}
}
@ -2040,7 +2154,7 @@ int swad__getAttendanceEvents (struct soap *soap,
/**************** Get lists of groups of an attendance event *****************/
/*****************************************************************************/
static void Svc_GetListGrpsInAttendanceEvent (long AttCod,char **ListGroups)
static void Svc_GetListGrpsInAttendanceEventFromDB (long AttCod,char **ListGroups)
{
char Query[128];
MYSQL_RES *mysql_res;
@ -2093,9 +2207,6 @@ int swad__sendAttendanceEvent (struct soap *soap,
int ReturnCode;
struct AttendanceEvent Att;
bool ItsANewAttEvent;
const char *Ptr;
char LongStr[1+10+1];
unsigned NumGrp;
Gbl.soap = soap;
Gbl.WebService.Function = Svc_sendAttendanceEvent;
@ -2168,8 +2279,35 @@ int swad__sendAttendanceEvent (struct soap *soap,
strncpy (Att.Title,title,Att_MAX_LENGTH_ATTENDANCE_EVENT_TITLE);
Att.Title[Att_MAX_LENGTH_ATTENDANCE_EVENT_TITLE] = '\0';
/* Create a list of groups selected */
Svc_GetLstGrpsSel (groups);
/***** Create or update attendance event *****/
if (ItsANewAttEvent)
Att_CreateAttEvent (&Att,text); // Add new attendance event to database
else
Att_UpdateAttEvent (&Att,text); // Modify existing attendance event
/***** Free memory for list of selected groups *****/
Grp_FreeListCodSelectedGrps ();
sendAttendanceEventOut->attendanceEventCode = Att.AttCod;
return SOAP_OK;
}
/*****************************************************************************/
/********************** Create a list of groups selected *********************/
/*****************************************************************************/
static void Svc_GetLstGrpsSel (const char *Groups)
{
const char *Ptr;
char LongStr[1+10+1];
unsigned NumGrp;
/***** Count number of groups *****/
for (Ptr = groups, NumGrp = 0;
for (Ptr = Groups, NumGrp = 0;
*Ptr;
NumGrp++)
Str_GetNextStringUntilComma (&Ptr,LongStr,1+10);
@ -2184,7 +2322,7 @@ int swad__sendAttendanceEvent (struct soap *soap,
if ((Gbl.CurrentCrs.Grps.LstGrpsSel.GrpCod = (long *) calloc (Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps,sizeof (long))) == NULL)
Lay_ShowErrorAndExit ("Not enough memory to store the codes of the selected groups.");
for (Ptr = groups, NumGrp = 0;
for (Ptr = Groups, NumGrp = 0;
*Ptr;
)
{
@ -2195,19 +2333,6 @@ int swad__sendAttendanceEvent (struct soap *soap,
}
Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps = NumGrp; // Update number of groups
}
/***** Create or update attendance event *****/
if (ItsANewAttEvent)
Att_CreateAttEvent (&Att,text); // Add new attendance event to database
else
Att_UpdateAttEvent (&Att,text); // Modify existing attendance event
/***** Free memory for list of selected groups *****/
Grp_FreeListCodSelectedGrps ();
sendAttendanceEventOut->attendanceEventCode = Att.AttCod;
return SOAP_OK;
}
/*****************************************************************************/
@ -2991,7 +3116,7 @@ int swad__sendMessage (struct soap *soap,
(Gbl.Usrs.Other.UsrDat.Prefs.EmailNtfEvents & (1 << Ntf_EVENT_MESSAGE)));
/* Send message to this user */
if ((ReturnCode = Svc_sendMessageToUsr ((long) messageCode,Gbl.Usrs.Me.UsrDat.UsrCod,ReplyUsrCod,Gbl.Usrs.Other.UsrDat.UsrCod,NotifyByEmail,subject,body)) != SOAP_OK)
if ((ReturnCode = Svc_SendMessageToUsr ((long) messageCode,Gbl.Usrs.Me.UsrDat.UsrCod,ReplyUsrCod,Gbl.Usrs.Other.UsrDat.UsrCod,NotifyByEmail,subject,body)) != SOAP_OK)
{
DB_FreeMySQLResult (&mysql_res);
return ReturnCode;
@ -3013,7 +3138,7 @@ int swad__sendMessage (struct soap *soap,
/************************* Send a message to one user ************************/
/*****************************************************************************/
static int Svc_sendMessageToUsr (long OriginalMsgCod,long SenderUsrCod,long ReplyUsrCod,long RecipientUsrCod,bool NotifyByEmail,const char *Subject,const char *Content)
static int Svc_SendMessageToUsr (long OriginalMsgCod,long SenderUsrCod,long ReplyUsrCod,long RecipientUsrCod,bool NotifyByEmail,const char *Subject,const char *Content)
{
static bool MsgAlreadyInserted = false;
static long NewMsgCod;