swad-core/swad_API.c

6312 lines
237 KiB
C
Raw Normal View History

2019-05-16 14:02:06 +02:00
// swad_API.c: SWAD web API provided to external plugins
2014-12-01 23:55:08 +01:00
/*
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.
2021-02-09 12:43:45 +01:00
Copyright (C) 1999-2021 Antonio Ca<EFBFBD>as Vargas
2014-12-01 23:55:08 +01:00
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/>.
*/
/*****************************************************************************/
/******* How to use the gSOAP toolkit to create a web-service server *********/
/*****************************************************************************/
/*
This code uses the gSOAP toolkit:
http://www.cs.fsu.edu/~engelen/soap.html
http://gsoap2.sourceforge.net/
Version 2.8.8 (19/02/2012)
To install the toolkit:
1. Install g++ if not installed: yum -y install gcc-c++
2. Install yacc if not installed: yum -y install byacc
3. Install flex if not installed: yum -y install flex
4. Install bison if not installed: yum -y install bison
5. Install bison-devel if not installed: yum -y install bison-devel
6. unzip gsoap_2.8.8.zip
7. cd gsoap-2.8
8. ./configure
9. make
10. make install
Steps to generate swad.wsdl:
1. Go to directory soap
cd /home/acanas/swad/swad/soap
2. Inside soap, create a C header file with the web service. Example swad_web_service.h:
----------
// File: swad_web_service.h
//gsoap swad service name: swad
//gsoap swad service namespace: urn:swad
//gsoap swad service location: https://swad.ugr.es/
...
----------
3. Inside soap, execute soapcpp2 compiler:
soapcpp2 -c -S swad_web_service.h
4. Copy generated WSDL file (swad.wsdl) to public location (probably you must be root):
cp -f /home/acanas/swad/swad/soap/swad.wsdl /var/www/html/ws/
5. Put a '#include "soap/soapH.h"' line into the code of the web-service server (this file).
6. Put a '#include "soap/swad.nsmap"' into the code of the web-service server (this file).
7. Compile swad including the web service.
The makefile must include -lgsoap, and compile soapC.c and soapServer.c files generated by soapcpp2 in step 2
Example of Makefile:
---------------------
2016-10-09 22:22:47 +02:00
OBJS = list of swad object files
2014-12-01 23:55:08 +01:00
SOAPOBJS = soap/soapC.o soap/soapServer.o
CC = gcc
LIBS = -lmysqlclient -lz -L/usr/lib64/mysql -lm -lgsoap
CFLAGS = -Wall -O2 -s
swad: $(OBJS) $(SOAPOBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(SOAPOBJS) $(LIBS)
chmod a+x $@
---------------------
8. Copy CGI (swad) to the cgi directory:
cp -f /home/acanas/swad/swad/swad /var/www/cgi-bin/
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
// In Eclipse, add to include path /usr/include, /usr/local/include, /usr/include/i386-linux-gnu
2015-12-21 14:43:52 +01:00
#include <dirent.h> // For scandir, etc.
2014-12-01 23:55:08 +01:00
#include <linux/limits.h> // For PATH_MAX
2019-12-29 12:39:00 +01:00
#include <stddef.h> // For NULL
2014-12-01 23:55:08 +01:00
#include <string.h>
#include <stdsoap2.h>
2019-12-29 12:39:00 +01:00
#include <sys/stat.h> // For lstat
2014-12-01 23:55:08 +01:00
#include "soap/soapH.h" // gSOAP header
#include "soap/swad.nsmap" // Namespaces map used
2015-07-13 12:34:26 +02:00
#include "swad_account.h"
2019-05-16 14:02:06 +02:00
#include "swad_API.h"
#include "swad_attendance_database.h"
#include "swad_browser.h"
#include "swad_browser_database.h"
2014-12-01 23:55:08 +01:00
#include "swad_database.h"
#include "swad_error.h"
2020-04-14 17:15:17 +02:00
#include "swad_forum.h"
2014-12-01 23:55:08 +01:00
#include "swad_global.h"
#include "swad_group_database.h"
2016-11-14 16:47:46 +01:00
#include "swad_hierarchy.h"
#include "swad_hierarchy_level.h"
2014-12-01 23:55:08 +01:00
#include "swad_ID.h"
2019-12-02 09:57:17 +01:00
#include "swad_match.h"
#include "swad_nickname_database.h"
2014-12-01 23:55:08 +01:00
#include "swad_notice.h"
#include "swad_notification.h"
#include "swad_password.h"
2020-08-23 11:22:41 +02:00
#include "swad_role.h"
2016-06-29 18:27:49 +02:00
#include "swad_search.h"
2020-03-21 15:41:25 +01:00
#include "swad_test_config.h"
2020-02-18 09:19:33 +01:00
#include "swad_test_visibility.h"
2014-12-01 23:55:08 +01:00
#include "swad_user.h"
2016-06-30 18:14:09 +02:00
#include "swad_xml.h"
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
2019-03-15 15:25:31 +01:00
extern const char Str_BIN_TO_BASE64URL[64 + 1];
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/***************************** Private constants *****************************/
/*****************************************************************************/
// Add new functions at the end
2019-05-16 14:02:06 +02:00
static const char *API_Functions[1 + API_NUM_FUNCTIONS] =
2014-12-01 23:55:08 +01:00
{
2020-08-23 11:22:41 +02:00
[API_unknown ] = "?", // 0 ==> unknown function
[API_loginBySessionKey ] = "loginBySession", // 1
[API_loginByUserPassword ] = "loginByUserPassword", // 2 (deprecated)
[API_loginByUserPasswordKey ] = "loginByUserPasswordKey", // 3
[API_getCourses ] = "getCourses", // 4
[API_getUsers ] = "getUsers", // 5
[API_getNotifications ] = "getNotifications", // 6
[API_getTestConfig ] = "getTestConfig", // 7
[API_getTests ] = "getTests", // 8
[API_sendMessage ] = "sendMessage", // 9
[API_sendNotice ] = "sendNotice", // 10
[API_getDirectoryTree ] = "getDirectoryTree", // 11
[API_getGroups ] = "getGroups", // 12
[API_getGroupTypes ] = "getGroupTypes", // 13
[API_sendMyGroups ] = "sendMyGroups", // 14
[API_getFile ] = "getFile", // 15
[API_markNotificationsAsRead ] = "markNotificationsAsRead", // 16
[API_getNewPassword ] = "getNewPassword", // 17
[API_getCourseInfo ] = "getCourseInfo", // 18
[API_getAttendanceEvents ] = "getAttendanceEvents", // 19
[API_sendAttendanceEvent ] = "sendAttendanceEvent", // 20
[API_getAttendanceUsers ] = "getAttendanceUsers", // 21
[API_sendAttendanceUsers ] = "sendAttendanceUsers", // 22
[API_createAccount ] = "createAccount", // 23
[API_getMarks ] = "getMarks", // 24
[API_getTrivialQuestion ] = "getTrivialQuestion", // 25
[API_findUsers ] = "findUsers", // 26
[API_removeAttendanceEvent ] = "removeAttendanceEvent", // 27
[API_getGames ] = "getGames", // 28
[API_getMatches ] = "getMatches", // 29
[API_getMatchStatus ] = "getMatchStatus", // 30
[API_answerMatchQuestion ] = "answerMatchQuestion", // 31
[API_getLocation ] = "getLocation", // 32
[API_sendMyLocation ] = "sendMyLocation", // 33
[API_getLastLocation ] = "getLastLocation", // 34
[API_getAvailableRoles ] = "getAvailableRoles", // 35
2014-12-01 23:55:08 +01:00
};
2016-07-04 10:46:32 +02:00
/* Web service roles (they do not match internal swad-core roles) */
2019-05-16 14:02:06 +02:00
#define API_NUM_ROLES 4
2016-07-04 10:26:44 +02:00
typedef enum
{
2020-05-03 20:58:03 +02:00
API_ROLE_UNKNOWN = 0, // User not logged in (do not change this constant to any value other than 0)
2019-05-16 14:02:06 +02:00
API_ROLE__GUEST_ = 1, // User not belonging to any course
API_ROLE_STUDENT = 2, // Student in current course
API_ROLE_TEACHER = 3, // Teacher in current course
} API_Role_t;
2016-07-04 10:26:44 +02:00
2016-07-04 10:46:32 +02:00
/* Translation from service-web-role to swad-core-role */
2019-11-21 11:39:30 +01:00
static const Rol_Role_t API_SvcRole_to_RolRole[API_NUM_ROLES] =
2016-07-04 10:26:44 +02:00
{
2019-11-20 17:53:51 +01:00
[API_ROLE_UNKNOWN] = Rol_UNK,
[API_ROLE__GUEST_] = Rol_GST,
[API_ROLE_STUDENT] = Rol_STD,
[API_ROLE_TEACHER] = Rol_TCH, // TODO: Create new web service role for non-editing teachers
2016-07-04 10:26:44 +02:00
};
2016-07-04 10:46:32 +02:00
/* Translation from swad-core-role to service-web-role */
2019-11-21 11:39:30 +01:00
static const API_Role_t API_RolRole_to_SvcRole[Rol_NUM_ROLES] =
2016-07-04 10:26:44 +02:00
{
2020-05-03 20:58:03 +02:00
[Rol_GST] = API_ROLE__GUEST_,
[Rol_STD] = API_ROLE_STUDENT,
[Rol_NET] = API_ROLE_TEACHER, // TODO: Create new web service role for non-editing teachers
[Rol_TCH] = API_ROLE_TEACHER,
2016-07-04 10:26:44 +02:00
};
2019-05-16 14:02:06 +02:00
#define API_BYTES_WS_KEY Cry_BYTES_ENCRYPTED_STR_SHA256_BASE64
2017-01-15 18:02:52 +01:00
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static void API_Set_gSOAP_RuntimeEnv (struct soap *soap);
2020-02-24 20:34:06 +01:00
static void API_FreeSoapContext (struct soap *soap);
2020-02-24 19:31:55 +01:00
static int API_GetPlgCodFromAppKey (struct soap *soap,
const char *appKey);
static int API_CheckIdSession (struct soap *soap,
const char *IdSession);
2019-05-16 14:02:06 +02:00
static int API_CheckWSKey (char WSKey[API_BYTES_WS_KEY + 1]);
2014-12-01 23:55:08 +01:00
2020-02-24 19:31:55 +01:00
static int API_CheckCourseAndGroupCodes (struct soap *soap,
long CrsCod,long GrpCod);
static int API_GenerateNewWSKey (struct soap *soap,
long UsrCod,
2019-05-16 14:02:06 +02:00
char WSKey[API_BYTES_WS_KEY + 1]);
2020-02-24 19:31:55 +01:00
static int API_RemoveOldWSKeys (struct soap *soap);
2019-05-16 14:02:06 +02:00
static int API_GetCurrentDegCodFromCurrentCrsCod (void);
static bool API_GetSomeUsrDataFromUsrCod (struct UsrData *UsrDat,long CrsCod);
2015-07-13 12:34:26 +02:00
static int API_CheckParamsNewAccount (char *NewNickWithArr, // Input
char NewNickWithoutArr[Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1], // Output
2015-07-13 12:34:26 +02:00
char *NewEmail, // Input-output
char *NewPlainPassword, // Input
char NewEncryptedPassword[Pwd_BYTES_ENCRYPTED_PASSWORD + 1]); // Output
2015-07-13 12:34:26 +02:00
2020-02-24 19:31:55 +01:00
static int API_WriteSyllabusIntoHTMLBuffer (struct soap *soap,
2020-04-12 02:47:32 +02:00
struct Syl_Syllabus *Syllabus,
2020-02-24 19:31:55 +01:00
char **HTMLBuffer);
static int API_WritePlainTextIntoHTMLBuffer (struct soap *soap,
char **HTMLBuffer);
static int API_WritePageIntoHTMLBuffer (struct soap *soap,
char **HTMLBuffer);
static void API_CopyListUsers (struct soap *soap,
Rol_Role_t Role,
struct swad__getUsersOutput *getUsersOut);
static void API_CopyUsrData (struct soap *soap,
struct swad__user *Usr,struct UsrData *UsrDat,
bool UsrIDIsVisible);
static void API_GetListGrpsInAttendanceEventFromDB (struct soap *soap,
long AttCod,char **ListGroups);
2019-05-16 14:02:06 +02:00
static void API_GetLstGrpsSel (const char *Groups);
2014-12-01 23:55:08 +01:00
2020-02-24 19:31:55 +01:00
static int API_GetMyLanguage (struct soap *soap);
2014-12-01 23:55:08 +01:00
2019-05-16 14:02:06 +02:00
static int API_SendMessageToUsr (long OriginalMsgCod,long SenderUsrCod,long ReplyUsrCod,long RecipientUsrCod,bool NotifyByEmail,const char *Subject,const char *Content);
2014-12-01 23:55:08 +01:00
2019-05-16 14:02:06 +02:00
static int API_GetTstConfig (long CrsCod);
static unsigned API_GetNumTestQuestionsInCrs (long CrsCod);
2020-02-24 19:31:55 +01:00
static int API_GetTstTags (struct soap *soap,
long CrsCod,struct swad__getTestsOutput *getTestsOut);
static int API_GetTstQuestions (struct soap *soap,
long CrsCod,long BeginTime,
struct swad__getTestsOutput *getTestsOut);
static int API_GetTstAnswers (struct soap *soap,
long CrsCod,long BeginTime,
struct swad__getTestsOutput *getTestsOut);
static int API_GetTstQuestionTags (struct soap *soap,
long CrsCod,long BeginTime,
struct swad__getTestsOutput *getTestsOut);
static void API_GetListGrpsInGameFromDB (struct soap *soap,
long MchCod,char **ListGroups);
2019-05-16 14:02:06 +02:00
static void API_ListDir (unsigned Level,const char *Path,const char *PathInTree);
static bool API_WriteRowFileBrowser (unsigned Level,Brw_FileType_t FileType,const char *FileName);
static void API_IndentXMLLine (unsigned Level);
2014-12-01 23:55:08 +01:00
2020-05-30 18:11:53 +02:00
static void API_GetDataOfLocation (struct soap *soap,
struct swad__location *location,
time_t *CheckInTime,
MYSQL_RES **mysql_res,
unsigned NumLocs);
static void API_ResetLocation (struct soap *soap,
struct swad__location *location);
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/******* Function called when a web service if required by a plugin **********/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static struct soap *API_soap = NULL; // gSOAP runtime environment
static void API_Set_gSOAP_RuntimeEnv (struct soap *soap)
{
API_soap = soap;
}
struct soap *API_Get_gSOAP_RuntimeEnv (void)
{
return API_soap;
}
/*****************************************************************************/
/******* Function called when a web service if required by a plugin **********/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
void API_WebService (void)
2014-12-01 23:55:08 +01:00
{
struct soap *soap;
if ((soap = soap_new ())) // Allocate and initialize runtime context
{
soap_serve (soap);
2020-02-24 20:34:06 +01:00
API_FreeSoapContext (soap);
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/******* Function called to exit on error when executing web service *********/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
void API_Exit (const char *DetailErrorMessage)
2014-12-01 23:55:08 +01:00
{
2020-02-24 19:31:55 +01:00
struct soap *soap = API_Get_gSOAP_RuntimeEnv ();
int ReturnCode = 0;
if (soap)
{
ReturnCode = (DetailErrorMessage ? soap_receiver_fault (soap,
"Error in swad web service",
DetailErrorMessage) :
0);
2014-12-01 23:55:08 +01:00
2020-02-24 20:34:06 +01:00
API_FreeSoapContext (soap);
2020-02-24 19:31:55 +01:00
}
2014-12-01 23:55:08 +01:00
exit (ReturnCode);
}
/*****************************************************************************/
2020-02-24 20:34:06 +01:00
/****************************** Free SOAP context ****************************/
/*****************************************************************************/
static void API_FreeSoapContext (struct soap *soap)
{
soap_destroy (soap); // delete managed C++ objects
soap_end (soap); // delete managed memory
soap_free (soap); // free the context
API_Set_gSOAP_RuntimeEnv (NULL); // set pointer to NULL in order to not try to free the context again
}
/*****************************************************************************/
2014-12-01 23:55:08 +01:00
/****** Check if the application key of the requester of a web service *******/
/****** is one of the application keys allowed in the plugins *******/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static int API_GetPlgCodFromAppKey (struct soap *soap,
const char *appKey)
2014-12-01 23:55:08 +01:00
{
/***** Get number of plugins with a IP address *****/
Gbl.WebService.PlgCod = DB_QuerySELECTCode ("can not check application key",
"SELECT PlgCod"
" FROM plg_plugins"
" WHERE AppKey='%s'",
appKey); // Session found in table of sessions
2014-12-01 23:55:08 +01:00
if (Gbl.WebService.PlgCod < 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Unknown application key",
"Unknown application");
return SOAP_OK;
}
/*****************************************************************************/
/****** Get the name of a web service function given the function code *******/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
const char *API_GetFunctionNameFromFunCod (long FunCod)
2014-12-01 23:55:08 +01:00
{
2019-05-16 14:02:06 +02:00
if (FunCod < 0 || FunCod > API_NUM_FUNCTIONS)
return API_Functions[0];
return API_Functions[FunCod];
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****** Check if a session identifier is valid and exists in database ********/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static int API_CheckIdSession (struct soap *soap,
const char *IdSession)
2014-12-01 23:55:08 +01:00
{
const char *Ptr;
unsigned i;
/***** Check if pointer is NULL *****/
if (IdSession == NULL)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad session identifier",
"Session identifier is a null pointer");
/***** Check length of session identifier *****/
2018-10-17 01:08:42 +02:00
if (strlen (IdSession) != Cns_BYTES_SESSION_ID)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad session identifier",
"The length of the session identifier is wrong");
/***** Check if session identifier is in base64url *****/
for (Ptr = IdSession;
*Ptr;
Ptr++)
{
for (i = 0;
i < 64;
i++) // Check if this character is one of the allowed characters
if (*Ptr == Str_BIN_TO_BASE64URL[i])
break;
if (i == 64) // Character not found
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad session identifier",
"The session identifier must contain only base64url characters");
}
/***** Query if session identifier already exists in database *****/
2018-11-03 22:08:45 +01:00
if (DB_QueryCOUNT ("can not get session data",
"SELECT COUNT(*)"
" FROM ses_sessions"
2018-11-04 20:51:38 +01:00
" WHERE SessionId='%s'",
2018-11-03 22:08:45 +01:00
IdSession) != 1)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad session identifier",
"Session identifier does not exist in database");
return SOAP_OK;
}
/*****************************************************************************/
/************** Check if a web service key exists in database ****************/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
static int API_CheckWSKey (char WSKey[API_BYTES_WS_KEY + 1])
2014-12-01 23:55:08 +01:00
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
/***** Set default user's code *****/
Gbl.Usrs.Me.UsrDat.UsrCod = -1L;
Gbl.Usrs.Me.Logged = false;
Gbl.WebService.PlgCod = -1L;
/***** Check that key does not exist in database *****/
2018-11-02 01:23:05 +01:00
if (DB_QuerySELECT (&mysql_res,"can not get existence of key",
"SELECT UsrCod," // row[0]
"PlgCod" // row[1]
" FROM api_keys"
" WHERE WSKey='%s'",
2018-11-02 01:23:05 +01:00
WSKey)) // Session found in table of sessions
2014-12-01 23:55:08 +01:00
{
row = mysql_fetch_row (mysql_res);
Gbl.Usrs.Me.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
Gbl.Usrs.Me.Logged = true;
Gbl.WebService.PlgCod = Str_ConvertStrCodToLongCod (row[1]);
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/** Check if a course code and a group code are valid and exist in database **/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static int API_CheckCourseAndGroupCodes (struct soap *soap,
long CrsCod,long GrpCod)
2014-12-01 23:55:08 +01:00
{
/***** Check if course code is correct *****/
if (CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad course code",
"Course code must be a integer greater than 0");
/***** Query if course code already exists in database *****/
2018-11-03 22:08:45 +01:00
if (DB_QueryCOUNT ("can not get course",
"SELECT COUNT(*)"
" FROM crs_courses"
2018-11-04 20:51:38 +01:00
" WHERE CrsCod=%ld",
2018-11-03 22:08:45 +01:00
CrsCod) != 1)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad course code",
"Course code does not exist in database");
/***** Course code exists in database, so check if group code exists in database and belongs to course *****/
if (GrpCod > 0) // <=0 means "the whole course"
{
/***** Query if group code already exists in database *****/
2018-11-03 22:08:45 +01:00
if (DB_QueryCOUNT ("can not get group",
"SELECT COUNT(*)"
" FROM grp_types,"
"grp_groups"
" WHERE grp_types.CrsCod=%ld"
" AND grp_types.GrpTypCod=grp_groups.GrpTypCod"
" AND grp_groups.GrpCod=%ld",
2018-11-03 22:08:45 +01:00
CrsCod,GrpCod) != 1)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad group code",
"Group code does not exist in database or it's not a group of the specified course");
}
return SOAP_OK;
}
/*****************************************************************************/
/***** Generate a key used in subsequents calls to other web services ********/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static int API_GenerateNewWSKey (struct soap *soap,
long UsrCod,
2019-05-16 14:02:06 +02:00
char WSKey[API_BYTES_WS_KEY + 1])
2014-12-01 23:55:08 +01:00
{
int ReturnCode;
/***** Remove expired web service keys *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_RemoveOldWSKeys (soap)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Create a unique name for the key *****/
Str_Copy (WSKey,Gbl.UniqueNameEncrypted,API_BYTES_WS_KEY);
2014-12-01 23:55:08 +01:00
/***** Check that key does not exist in database *****/
2018-11-03 22:08:45 +01:00
if (DB_QueryCOUNT ("can not get existence of key",
"SELECT COUNT(*)"
" FROM api_keys"
2018-11-04 20:51:38 +01:00
" WHERE WSKey='%s'",
2018-11-03 22:08:45 +01:00
WSKey))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Error when generating key",
"Generated key already existed in database");
/***** Insert key into database *****/
2018-11-02 19:37:11 +01:00
DB_QueryINSERT ("can not insert new key",
"INSERT INTO api_keys"
2018-11-02 19:37:11 +01:00
" (WSKey,UsrCod,PlgCod,LastTime)"
" VALUES"
" ('%s',%ld,%ld,NOW())",
WSKey,
UsrCod,
Gbl.WebService.PlgCod);
2014-12-01 23:55:08 +01:00
return SOAP_OK;
}
/*****************************************************************************/
/************************ Remove old web service keys ************************/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static int API_RemoveOldWSKeys (struct soap *soap)
2014-12-01 23:55:08 +01:00
{
char Query[512];
/***** Remove expired sessions *****/
/* A session expire when last click (LastTime) is too old,
or when there was at least one refresh (navigator supports AJAX) and last refresh is too old (browser probably was closed) */
sprintf (Query,"DELETE LOW_PRIORITY FROM api_keys"
2019-02-13 13:32:11 +01:00
" WHERE LastTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-%lu)",
2015-12-21 00:53:56 +01:00
Cfg_TIME_TO_DELETE_WEB_SERVICE_KEY);
2014-12-01 23:55:08 +01:00
if (mysql_query (&Gbl.mysql,Query))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Can not remove old web service keys from database",
mysql_error (&Gbl.mysql));
return SOAP_OK;
}
/*****************************************************************************/
/********************* Get degree code from course code **********************/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
static int API_GetCurrentDegCodFromCurrentCrsCod (void)
2014-12-01 23:55:08 +01:00
{
/***** Check that key does not exist in database *****/
Gbl.Hierarchy.Deg.DegCod = DB_QuerySELECTCode ("can not get the degree of a course",
"SELECT DegCod"
" FROM crs_courses"
" WHERE CrsCod=%ld",
Gbl.Hierarchy.Crs.CrsCod); // Course found in table of courses
2014-12-01 23:55:08 +01:00
return SOAP_OK;
}
/*****************************************************************************/
/************ Get user's data from database giving a user's code *************/
/*****************************************************************************/
2016-07-20 20:24:16 +02:00
// Return false if UsrDat->UsrCod does not exist ini database
2014-12-01 23:55:08 +01:00
2019-05-16 14:02:06 +02:00
static bool API_GetSomeUsrDataFromUsrCod (struct UsrData *UsrDat,long CrsCod)
2014-12-01 23:55:08 +01:00
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2016-07-20 20:24:16 +02:00
/***** Check if user's code is valid *****/
if (UsrDat->UsrCod <= 0)
return false;
2014-12-01 23:55:08 +01:00
/***** Get some user's data *****/
2018-11-02 01:23:05 +01:00
if (DB_QuerySELECT (&mysql_res,"can not get user's data",
"SELECT Surname1," // row[0]
"Surname2," // row[1]
"FirstName," // row[2]
"Photo," // row[3]
"DATE_FORMAT(Birthday,'%%Y%%m%%d')" // row[4]
" FROM usr_data"
" WHERE UsrCod=%ld",
2018-11-02 01:23:05 +01:00
UsrDat->UsrCod) != 1)
2016-07-20 20:24:16 +02:00
return false;
2014-12-01 23:55:08 +01:00
/* Read some user's data */
row = mysql_fetch_row (mysql_res);
/* Get user's name (row[0], row[1], row[2]) and photo (row[3]) */
Str_Copy (UsrDat->Surname1,row[0],sizeof (UsrDat->Surname1) - 1);
Str_Copy (UsrDat->Surname2,row[1],sizeof (UsrDat->Surname2) - 1);
Str_Copy (UsrDat->FrstName,row[2],sizeof (UsrDat->FrstName) - 1);
Str_Copy (UsrDat->Photo ,row[3],sizeof (UsrDat->Photo ) - 1);
2014-12-01 23:55:08 +01:00
/* Get user's brithday (row[4]) */
2017-01-15 22:58:26 +01:00
Dat_GetDateFromYYYYMMDD (&(UsrDat->Birthday),row[4]);
2014-12-01 23:55:08 +01:00
/* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res);
/***** Get list of user's IDs *****/
ID_GetListIDsFromUsrCod (UsrDat);
/***** Get user's nickname *****/
Nck_DB_GetNicknameFromUsrCod (UsrDat->UsrCod,UsrDat->Nickname);
2014-12-01 23:55:08 +01:00
/***** Get user's role *****/
if (CrsCod > 0)
2016-07-20 20:24:16 +02:00
/* Get the role in the given course */
UsrDat->Roles.InCurrentCrs =
DB_QuerySELECTRole ("can not get user's role",
"SELECT Role"
" FROM crs_users"
" WHERE CrsCod=%ld"
" AND UsrCod=%ld",
CrsCod,
UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
else
2016-07-20 20:24:16 +02:00
/* Get the maximum role in any course */
UsrDat->Roles.InCurrentCrs =
DB_QuerySELECTRole ("can not get user's role",
"SELECT MAX(Role)"
" FROM crs_users"
" WHERE UsrCod=%ld",
UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
return true;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************************** Get info of my marks ***************************/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
#define API_CHECK_NEW_ACCOUNT_OK 0
#define API_CHECK_NEW_ACCOUNT_NICKNAME_NOT_VALID -1
#define API_CHECK_NEW_ACCOUNT_NICKNAME_REGISTERED_BY_ANOTHER_USER -2
#define API_CHECK_NEW_ACCOUNT_EMAIL_NOT_VALID -3
#define API_CHECK_NEW_ACCOUNT_EMAIL_REGISTERED_BY_ANOTHER_USER -4
#define API_CHECK_NEW_ACCOUNT_PASSWORD_NOT_VALID -5
2015-07-13 12:34:26 +02:00
2014-12-01 23:55:08 +01:00
int swad__createAccount (struct soap *soap,
2015-07-13 12:34:26 +02:00
char *userNickname,char *userEmail,char *userPassword,char *appKey, // input
2016-11-08 00:58:32 +01:00
struct swad__createAccountOutput *createAccountOut) // output
2014-12-01 23:55:08 +01:00
{
char NewNickWithoutArr[Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1];
2017-03-13 14:22:36 +01:00
char NewEncryptedPassword[Pwd_BYTES_ENCRYPTED_PASSWORD + 1];
2015-07-13 12:34:26 +02:00
int Result;
2014-12-01 23:55:08 +01:00
int ReturnCode;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_createAccount;
2014-12-01 23:55:08 +01:00
2015-07-13 12:34:26 +02:00
/***** Allocate space for strings *****/
createAccountOut->wsKey = soap_malloc (soap,API_BYTES_WS_KEY + 1);
2015-07-13 12:34:26 +02:00
/***** Default values returned on error *****/
createAccountOut->userCode = 0; // Undefined error
createAccountOut->wsKey[0] = '\0';
2014-12-01 23:55:08 +01:00
/***** Get plugin code *****/
if ((ReturnCode = API_GetPlgCodFromAppKey (soap,appKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
2015-07-13 12:34:26 +02:00
/***** Check parameters used to create the new account *****/
2019-05-16 14:02:06 +02:00
Result = API_CheckParamsNewAccount (userNickname, // Input
NewNickWithoutArr, // Output
2015-07-13 12:34:26 +02:00
userEmail, // Input-output
userPassword, // Input
NewEncryptedPassword); // Output
if (Result < 0)
{
createAccountOut->userCode = Result;
return SOAP_OK;
}
2014-12-01 23:55:08 +01:00
2015-07-13 12:34:26 +02:00
/***** User's has no ID *****/
Gbl.Usrs.Me.UsrDat.IDs.Num = 0;
Gbl.Usrs.Me.UsrDat.IDs.List = NULL;
2014-12-01 23:55:08 +01:00
2015-07-13 12:34:26 +02:00
/***** Set password to the password typed by the user *****/
2017-01-15 22:58:26 +01:00
Str_Copy (Gbl.Usrs.Me.UsrDat.Password,NewEncryptedPassword,
sizeof (Gbl.Usrs.Me.UsrDat.Password) - 1);
2014-12-01 23:55:08 +01:00
2015-07-13 12:34:26 +02:00
/***** User does not exist in the platform, so create him/her! *****/
2016-11-08 00:58:32 +01:00
Acc_CreateNewUsr (&Gbl.Usrs.Me.UsrDat,
true); // I am creating my own account
2014-12-01 23:55:08 +01:00
2015-07-13 12:34:26 +02:00
/***** Save nickname *****/
Nck_DB_UpdateNick (Gbl.Usrs.Me.UsrDat.UsrCod,NewNickWithoutArr);
Str_Copy (Gbl.Usrs.Me.UsrDat.Nickname,NewNickWithoutArr,
sizeof (Gbl.Usrs.Me.UsrDat.Nickname) - 1);
2014-12-01 23:55:08 +01:00
2016-11-16 23:19:52 +01:00
/***** Save email *****/
2015-07-13 12:34:26 +02:00
if (Mai_UpdateEmailInDB (&Gbl.Usrs.Me.UsrDat,userEmail))
{
2016-11-16 23:19:52 +01:00
/* Email updated sucessfully */
2017-01-17 03:10:43 +01:00
Str_Copy (Gbl.Usrs.Me.UsrDat.Email,userEmail,
sizeof (Gbl.Usrs.Me.UsrDat.Email) - 1);
2015-07-13 12:34:26 +02:00
Gbl.Usrs.Me.UsrDat.EmailConfirmed = false;
}
2014-12-01 23:55:08 +01:00
2015-07-13 12:34:26 +02:00
/***** Copy new user's code *****/
createAccountOut->userCode = Gbl.Usrs.Me.UsrDat.UsrCod;
/***** Generate a key used in subsequents calls to other web services *****/
2020-02-24 19:31:55 +01:00
return API_GenerateNewWSKey (soap,
(long) createAccountOut->userCode,
2015-07-13 12:34:26 +02:00
createAccountOut->wsKey);
}
/*****************************************************************************/
/************* Get parameters for the creation of a new account **************/
/*****************************************************************************/
// Return false on error
//char *userNickname,char *userEmail,char *userID,char *userPassword
static int API_CheckParamsNewAccount (char *NewNickWithArr, // Input
char NewNickWithoutArr[Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1], // Output
2015-07-13 12:34:26 +02:00
char *NewEmail, // Input-output
char *NewPlainPassword, // Input
char NewEncryptedPassword[Pwd_BYTES_ENCRYPTED_PASSWORD + 1]) // Output
2015-07-13 12:34:26 +02:00
{
char CopyOfNewNick[Nck_MAX_BYTES_NICK_WITH_ARROBA + 1];
2015-07-13 12:34:26 +02:00
/***** Step 1/3: Check new nickname *****/
/* Make a copy without possible starting arrobas */
if (Nck_CheckIfNickWithArrIsValid (NewNickWithArr)) // If new nickname is valid
2015-07-13 12:34:26 +02:00
{
/***** Remove leading arrobas *****/
Str_Copy (CopyOfNewNick,NewNickWithArr,sizeof (CopyOfNewNick) - 1);
Str_RemoveLeadingArrobas (CopyOfNewNick);
2015-07-13 12:34:26 +02:00
/***** Check if the new nickname matches any of the nicknames of other users *****/
2018-11-03 22:08:45 +01:00
if (DB_QueryCOUNT ("can not check if nickname already existed",
"SELECT COUNT(*)"
" FROM usr_nicknames"
" WHERE Nickname='%s'", // A nickname of another user is the same that this nickname
CopyOfNewNick)) // Already without leading arrobas
2019-05-16 14:02:06 +02:00
return API_CHECK_NEW_ACCOUNT_NICKNAME_REGISTERED_BY_ANOTHER_USER;
/***** Output value of nickname without leading arrobas *****/
Str_Copy (NewNickWithoutArr,CopyOfNewNick,Nck_MAX_BYTES_NICK_WITHOUT_ARROBA);
2015-07-13 12:34:26 +02:00
}
else // New nickname is not valid
2019-05-16 14:02:06 +02:00
return API_CHECK_NEW_ACCOUNT_NICKNAME_NOT_VALID;
2015-07-13 12:34:26 +02:00
2016-11-16 23:19:52 +01:00
/***** Step 2/3: Check new email *****/
if (Mai_CheckIfEmailIsValid (NewEmail)) // New email is valid
2015-07-13 12:34:26 +02:00
{
2016-11-16 23:19:52 +01:00
/***** Check if the new email matches any of the confirmed emails of other users *****/
2018-11-03 22:08:45 +01:00
if (DB_QueryCOUNT ("can not check if email already existed",
"SELECT COUNT(*)"
" FROM usr_emails"
" WHERE E_mail='%s'"
" AND Confirmed='Y'",
2018-11-03 22:08:45 +01:00
NewEmail)) // An email of another user is the same that my email
2019-05-16 14:02:06 +02:00
return API_CHECK_NEW_ACCOUNT_EMAIL_REGISTERED_BY_ANOTHER_USER;
2015-07-13 12:34:26 +02:00
}
2016-11-16 23:19:52 +01:00
else // New email is not valid
2019-05-16 14:02:06 +02:00
return API_CHECK_NEW_ACCOUNT_EMAIL_NOT_VALID;
2015-07-13 12:34:26 +02:00
/***** Step 3/3: Check new password *****/
Cry_EncryptSHA512Base64 (NewPlainPassword,NewEncryptedPassword);
if (!Pwd_SlowCheckIfPasswordIsGood (NewPlainPassword,NewEncryptedPassword,-1L)) // New password is good?
2019-05-16 14:02:06 +02:00
return API_CHECK_NEW_ACCOUNT_PASSWORD_NOT_VALID;
2015-07-13 12:34:26 +02:00
2019-05-16 14:02:06 +02:00
return API_CHECK_NEW_ACCOUNT_OK;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** Login user by user, password and key *********************/
/*****************************************************************************/
int swad__loginByUserPasswordKey (struct soap *soap,
char *userID,char *userPassword,char *appKey, // input
struct swad__loginByUserPasswordKeyOutput *loginByUserPasswordKeyOut) // output
{
char UsrIDNickOrEmail[Cns_MAX_BYTES_USR_LOGIN + 1];
2014-12-01 23:55:08 +01:00
int ReturnCode;
2017-03-07 01:56:41 +01:00
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
2016-07-20 20:24:16 +02:00
bool UsrFound;
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_loginByUserPasswordKey;
2014-12-01 23:55:08 +01:00
/***** Allocate space for strings *****/
loginByUserPasswordKeyOut->wsKey = soap_malloc (soap,API_BYTES_WS_KEY + 1);
loginByUserPasswordKeyOut->userNickname = soap_malloc (soap,Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1);
loginByUserPasswordKeyOut->userID = soap_malloc (soap,ID_MAX_BYTES_USR_ID + 1);
loginByUserPasswordKeyOut->userFirstname = soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
loginByUserPasswordKeyOut->userSurname1 = soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
loginByUserPasswordKeyOut->userSurname2 = soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
loginByUserPasswordKeyOut->userPhoto = soap_malloc (soap,Cns_MAX_BYTES_WWW + 1);
loginByUserPasswordKeyOut->userBirthday = soap_malloc (soap,Dat_LENGTH_YYYYMMDD + 1);
2014-12-01 23:55:08 +01:00
/***** Default values returned on error *****/
loginByUserPasswordKeyOut->userCode = -1;
loginByUserPasswordKeyOut->wsKey[0] = '\0';
loginByUserPasswordKeyOut->userNickname[0] = '\0';
loginByUserPasswordKeyOut->userID[0] = '\0';
loginByUserPasswordKeyOut->userFirstname[0] = '\0';
loginByUserPasswordKeyOut->userSurname1[0] = '\0';
loginByUserPasswordKeyOut->userSurname2[0] = '\0';
loginByUserPasswordKeyOut->userPhoto[0] = '\0';
loginByUserPasswordKeyOut->userBirthday[0] = '\0';
loginByUserPasswordKeyOut->userRole = 0; // unknown
/***** Get plugin code *****/
if ((ReturnCode = API_GetPlgCodFromAppKey (soap,appKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
2016-11-16 23:19:52 +01:00
/***** Check if user's email, @nickname or ID are valid *****/
Str_Copy (UsrIDNickOrEmail,userID,sizeof (UsrIDNickOrEmail) - 1);
if (Nck_CheckIfNickWithArrIsValid (UsrIDNickOrEmail)) // 1: It's a nickname
2014-12-01 23:55:08 +01:00
{
Str_RemoveLeadingArrobas (UsrIDNickOrEmail);
/* User has typed a nickname */
Gbl.Usrs.Me.UsrDat.UsrCod = DB_QuerySELECTCode ("can not get user's data",
"SELECT usr_nicknames.UsrCod"
" FROM usr_nicknames,"
"usr_data"
" WHERE usr_nicknames.Nickname='%s'"
" AND usr_nicknames.UsrCod=usr_data.UsrCod"
" AND usr_data.Password='%s'",
UsrIDNickOrEmail,
userPassword);
2014-12-01 23:55:08 +01:00
}
2020-04-06 23:18:02 +02:00
else if (Mai_CheckIfEmailIsValid (UsrIDNickOrEmail)) // 2: It's an email
2014-12-01 23:55:08 +01:00
{
2016-11-16 23:19:52 +01:00
/* User has typed an email */
2014-12-01 23:55:08 +01:00
// TODO: Get only if email confirmed?
Gbl.Usrs.Me.UsrDat.UsrCod = DB_QuerySELECTCode ("can not get user's data",
"SELECT usr_emails.UsrCod"
" FROM usr_emails,usr_data"
" WHERE usr_emails.E_mail='%s'"
" AND usr_emails.UsrCod=usr_data.UsrCod"
" AND usr_data.Password='%s'",
UsrIDNickOrEmail,
userPassword);
2014-12-01 23:55:08 +01:00
}
2016-11-16 23:19:52 +01:00
else // 3: It's not a nickname nor email
2014-12-01 23:55:08 +01:00
{
// Users' IDs are always stored internally in capitals and without leading zeros
Str_RemoveLeadingZeros (UsrIDNickOrEmail);
Str_ConvertToUpperText (UsrIDNickOrEmail);
if (ID_CheckIfUsrIDIsValid (UsrIDNickOrEmail))
{
/* User has typed a valid user's ID (existing or not) */
// TODO: Get only if ID confirmed?
Gbl.Usrs.Me.UsrDat.UsrCod = DB_QuerySELECTCode ("can not get user's data",
"SELECT usr_ids.UsrCod"
" FROM usr_ids,"
"usr_data"
" WHERE usr_ids.UsrID='%s'"
" AND usr_ids.UsrCod=usr_data.UsrCod"
" AND usr_data.Password='%s'",
UsrIDNickOrEmail,
userPassword);
2014-12-01 23:55:08 +01:00
}
2016-11-16 23:19:52 +01:00
else // String is not a valid user's nickname, email or ID
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad log in",
"User's ID or nickname don't exist or password is wrong");
}
/***** Get user's data from database *****/
if (Gbl.Usrs.Me.UsrDat.UsrCod > 0) // User found in table of users' data
2016-07-20 20:24:16 +02:00
/***** Get user's data *****/
2019-05-16 14:02:06 +02:00
UsrFound = API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L); // Get some user's data from database
2016-07-20 20:24:16 +02:00
else
UsrFound = false;
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
if (UsrFound)
{
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
loginByUserPasswordKeyOut->userCode = (int) Gbl.Usrs.Me.UsrDat.UsrCod;
2014-12-01 23:55:08 +01:00
2017-01-15 18:02:52 +01:00
Str_Copy (loginByUserPasswordKeyOut->userNickname,
Gbl.Usrs.Me.UsrDat.Nickname,Nck_MAX_BYTES_NICK_WITHOUT_ARROBA);
2014-12-01 23:55:08 +01:00
2016-07-24 12:17:03 +02:00
if (Gbl.Usrs.Me.UsrDat.IDs.Num)
2017-01-15 18:02:52 +01:00
Str_Copy (loginByUserPasswordKeyOut->userID,
2017-01-17 03:10:43 +01:00
Gbl.Usrs.Me.UsrDat.IDs.List[0].ID, // TODO: What user's ID?
2017-03-07 01:56:41 +01:00
ID_MAX_BYTES_USR_ID);
2014-12-01 23:55:08 +01:00
2017-01-15 18:02:52 +01:00
Str_Copy (loginByUserPasswordKeyOut->userSurname1,
Gbl.Usrs.Me.UsrDat.Surname1,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
2017-01-15 18:02:52 +01:00
Str_Copy (loginByUserPasswordKeyOut->userSurname2,
Gbl.Usrs.Me.UsrDat.Surname2,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
2017-01-15 18:02:52 +01:00
Str_Copy (loginByUserPasswordKeyOut->userFirstname,
Gbl.Usrs.Me.UsrDat.FrstName,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,PhotoURL);
Str_Copy (loginByUserPasswordKeyOut->userPhoto,PhotoURL,Cns_MAX_BYTES_WWW);
2014-12-01 23:55:08 +01:00
2017-01-15 18:02:52 +01:00
Str_Copy (loginByUserPasswordKeyOut->userBirthday,
Gbl.Usrs.Me.UsrDat.Birthday.YYYYMMDD,Dat_LENGTH_YYYYMMDD);
2016-07-20 20:24:16 +02:00
loginByUserPasswordKeyOut->userRole =
API_RolRole_to_SvcRole[Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs];
2014-12-01 23:55:08 +01:00
/***** Generate a key used in subsequents calls to other web services *****/
2020-02-24 19:31:55 +01:00
return API_GenerateNewWSKey (soap,
(long) loginByUserPasswordKeyOut->userCode,
2015-07-13 12:34:26 +02:00
loginByUserPasswordKeyOut->wsKey);
2016-07-20 20:24:16 +02:00
}
2014-12-01 23:55:08 +01:00
else
2016-07-20 20:24:16 +02:00
{
loginByUserPasswordKeyOut->userCode = -1;
loginByUserPasswordKeyOut->userID = NULL;
loginByUserPasswordKeyOut->userSurname1 = NULL;
loginByUserPasswordKeyOut->userSurname2 = NULL;
loginByUserPasswordKeyOut->userFirstname = NULL;
loginByUserPasswordKeyOut->userPhoto = NULL;
loginByUserPasswordKeyOut->userRole = 0;
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad log in",
"User's ID or nickname don't exist or password is wrong");
2016-07-20 20:24:16 +02:00
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************** Login user by session ****************************/
/*****************************************************************************/
int swad__loginBySessionKey (struct soap *soap,
char *sessionID,char *appKey, // input
struct swad__loginBySessionKeyOutput *loginBySessionKeyOut) // output
{
int ReturnCode;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRows;
2017-03-07 01:56:41 +01:00
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
2016-07-20 20:24:16 +02:00
bool UsrFound;
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_loginBySessionKey;
2014-12-01 23:55:08 +01:00
/***** Allocate space for strings *****/
loginBySessionKeyOut->wsKey = soap_malloc (soap,API_BYTES_WS_KEY + 1);
loginBySessionKeyOut->userNickname = soap_malloc (soap,Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1);
loginBySessionKeyOut->userID = soap_malloc (soap,ID_MAX_BYTES_USR_ID + 1);
loginBySessionKeyOut->userFirstname = soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
loginBySessionKeyOut->userSurname1 = soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
loginBySessionKeyOut->userSurname2 = soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
loginBySessionKeyOut->userPhoto = soap_malloc (soap,Cns_MAX_BYTES_WWW + 1);
loginBySessionKeyOut->userBirthday = soap_malloc (soap,Dat_LENGTH_YYYYMMDD + 1);
loginBySessionKeyOut->degreeName = soap_malloc (soap,Cns_HIERARCHY_MAX_BYTES_FULL_NAME + 1);
loginBySessionKeyOut->courseName = soap_malloc (soap,Cns_HIERARCHY_MAX_BYTES_FULL_NAME + 1);
2014-12-01 23:55:08 +01:00
/***** Default values returned on error *****/
loginBySessionKeyOut->userCode = -1;
loginBySessionKeyOut->degreeCode = -1;
loginBySessionKeyOut->courseCode = -1;
loginBySessionKeyOut->wsKey[0] = '\0';
loginBySessionKeyOut->userNickname[0] = '\0';
loginBySessionKeyOut->userID[0] = '\0';
loginBySessionKeyOut->userFirstname[0] = '\0';
loginBySessionKeyOut->userSurname1[0] = '\0';
loginBySessionKeyOut->userSurname2[0] = '\0';
loginBySessionKeyOut->userPhoto[0] = '\0';
loginBySessionKeyOut->userBirthday[0] = '\0';
2017-05-18 19:13:41 +02:00
loginBySessionKeyOut->userRole = Rol_UNK;
2014-12-01 23:55:08 +01:00
loginBySessionKeyOut->degreeName[0] = '\0';
loginBySessionKeyOut->courseName[0] = '\0';
/***** Get plugin code *****/
if ((ReturnCode = API_GetPlgCodFromAppKey (soap,appKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Check length of session identifier *****/
if (sessionID == NULL)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"SessionID is null",
"Login by session");
/***** Check session identifier coming from an external plugin *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_CheckIdSession (soap,sessionID)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
// Now, we know that sessionID is a valid session identifier
/***** Query data of the session from database *****/
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get session data",
"SELECT UsrCod," // row[0]
"DegCod," // row[1]
"CrsCod" // row[2]
" FROM ses_sessions"
" WHERE SessionId='%s'",
sessionID);
2018-11-02 01:23:05 +01:00
if (NumRows == 1) // Session found in table of sessions
2014-12-01 23:55:08 +01:00
{
row = mysql_fetch_row (mysql_res);
/***** Get course (row[2]) *****/
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = Str_ConvertStrCodToLongCod (row[2]);
2020-01-05 14:09:28 +01:00
Crs_GetDataOfCourseByCod (&Gbl.Hierarchy.Crs);
2019-04-04 10:45:15 +02:00
loginBySessionKeyOut->courseCode = (int) Gbl.Hierarchy.Crs.CrsCod;
Str_Copy (loginBySessionKeyOut->courseName,Gbl.Hierarchy.Crs.FullName,
2021-02-11 22:57:09 +01:00
Cns_HIERARCHY_MAX_BYTES_FULL_NAME);
2014-12-01 23:55:08 +01:00
/***** Get user code (row[0]) *****/
Gbl.Usrs.Me.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
2019-05-16 14:02:06 +02:00
UsrFound = API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod); // Get some user's data from database
2014-12-01 23:55:08 +01:00
/***** Get degree (row[1]) *****/
2019-04-03 20:57:04 +02:00
Gbl.Hierarchy.Deg.DegCod = Str_ConvertStrCodToLongCod (row[1]);
2020-01-05 12:52:03 +01:00
Deg_GetDataOfDegreeByCod (&Gbl.Hierarchy.Deg);
2019-04-03 20:57:04 +02:00
loginBySessionKeyOut->degreeCode = (int) Gbl.Hierarchy.Deg.DegCod;
Str_Copy (loginBySessionKeyOut->degreeName,Gbl.Hierarchy.Deg.FullName,
2021-02-11 22:57:09 +01:00
Cns_HIERARCHY_MAX_BYTES_FULL_NAME);
2014-12-01 23:55:08 +01:00
}
2016-07-20 20:24:16 +02:00
else
UsrFound = false;
2014-12-01 23:55:08 +01:00
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
/***** Get degree of current course *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
2016-07-20 20:24:16 +02:00
if (UsrFound)
{
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2016-07-20 20:24:16 +02:00
loginBySessionKeyOut->userCode = (int) Gbl.Usrs.Me.UsrDat.UsrCod;
2017-01-15 18:02:52 +01:00
Str_Copy (loginBySessionKeyOut->userNickname,Gbl.Usrs.Me.UsrDat.Nickname,
Nck_MAX_BYTES_NICK_WITHOUT_ARROBA);
2016-07-20 20:24:16 +02:00
2016-07-24 12:17:03 +02:00
if (Gbl.Usrs.Me.UsrDat.IDs.Num)
2017-01-15 18:02:52 +01:00
Str_Copy (loginBySessionKeyOut->userID,
Gbl.Usrs.Me.UsrDat.IDs.List[0].ID, // TODO: What user's ID?
2017-03-07 01:56:41 +01:00
ID_MAX_BYTES_USR_ID);
2016-07-20 20:24:16 +02:00
2017-01-15 18:02:52 +01:00
Str_Copy (loginBySessionKeyOut->userSurname1,
Gbl.Usrs.Me.UsrDat.Surname1,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
2017-01-15 18:02:52 +01:00
Str_Copy (loginBySessionKeyOut->userSurname2,
Gbl.Usrs.Me.UsrDat.Surname2,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
2017-01-15 18:02:52 +01:00
Str_Copy (loginBySessionKeyOut->userFirstname,
Gbl.Usrs.Me.UsrDat.FrstName,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
2016-07-20 20:24:16 +02:00
Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,PhotoURL);
Str_Copy (loginBySessionKeyOut->userPhoto,PhotoURL,Cns_MAX_BYTES_WWW);
2016-07-20 20:24:16 +02:00
2017-01-15 18:02:52 +01:00
Str_Copy (loginBySessionKeyOut->userBirthday,
Gbl.Usrs.Me.UsrDat.Birthday.YYYYMMDD,Dat_LENGTH_YYYYMMDD);
2016-07-20 20:24:16 +02:00
loginBySessionKeyOut->userRole = API_RolRole_to_SvcRole[Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs];
2016-07-20 20:24:16 +02:00
2014-12-01 23:55:08 +01:00
/***** Generate a key used in subsequents calls to other web services *****/
2020-02-24 19:31:55 +01:00
return API_GenerateNewWSKey (soap,
(long) loginBySessionKeyOut->userCode,
2015-07-13 12:34:26 +02:00
loginBySessionKeyOut->wsKey);
2016-07-20 20:24:16 +02:00
}
2014-12-01 23:55:08 +01:00
else
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad session identifier",
"Session identifier does not exist in database");
}
2020-08-23 11:22:41 +02:00
/*****************************************************************************/
/***************** Get available roles in the current course *****************/
/*****************************************************************************/
/*
With this function, SWADroid is able to check if user can see the button to show the MAC address of the nearest WiFi access point
*/
int swad__getAvailableRoles (struct soap *soap,
2020-09-22 00:02:03 +02:00
char *wsKey,int courseCode, // input
2020-08-23 11:22:41 +02:00
struct swad__getAvailableRolesOutput *getAvailableRolesOut) // output
{
int ReturnCode;
/***** Initializations *****/
API_Set_gSOAP_RuntimeEnv (soap);
Gbl.WebService.Function = API_getAvailableRoles;
2020-09-25 12:43:21 +02:00
/***** Initialize hierarchy *****/
2020-09-22 00:02:03 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2020-09-25 12:43:21 +02:00
Hie_InitHierarchy ();
2020-08-23 11:22:41 +02:00
/***** Default value returned on error *****/
getAvailableRolesOut->roles = 0; // error
/***** Check web service key *****/
if ((ReturnCode = API_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 (soap,
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2020-08-23 11:22:41 +02:00
/***** Return available roles *****/
Rol_SetMyRoles ();
getAvailableRolesOut->roles = Gbl.Usrs.Me.Role.Available;
2020-08-23 11:22:41 +02:00
return SOAP_OK;
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2016-11-16 23:19:52 +01:00
/*********************** Send a new password by email ************************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
int swad__getNewPassword (struct soap *soap,
char *userID,char *appKey, // input
struct swad__getNewPasswordOutput *getNewPasswordOut) // output
{
int ReturnCode;
char UsrIDNickOrEmail[Cns_MAX_BYTES_USR_LOGIN + 1];
2017-03-07 01:56:41 +01:00
char NewRandomPlainPassword[Pwd_MAX_BYTES_PLAIN_PASSWORD + 1];
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getNewPassword;
2014-12-01 23:55:08 +01:00
2020-08-23 11:22:41 +02:00
/***** Default value returned on error *****/
2014-12-01 23:55:08 +01:00
getNewPasswordOut->success = 0; // error
/***** Get plugin code *****/
if ((ReturnCode = API_GetPlgCodFromAppKey (soap,appKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
2016-11-16 23:19:52 +01:00
/***** Check if user's email, @nickname or ID are valid *****/
Str_Copy (UsrIDNickOrEmail,userID,sizeof (UsrIDNickOrEmail) - 1);
if (Nck_CheckIfNickWithArrIsValid (UsrIDNickOrEmail)) // 1: It's a nickname
2014-12-01 23:55:08 +01:00
{
Str_RemoveLeadingArrobas (UsrIDNickOrEmail);
/* User has typed a nickname */
Gbl.Usrs.Me.UsrDat.UsrCod = DB_QuerySELECTCode ("can not get user's data",
"SELECT UsrCod"
" FROM usr_nicknames"
" WHERE Nickname='%s'",
UsrIDNickOrEmail);
2014-12-01 23:55:08 +01:00
}
2016-11-16 23:19:52 +01:00
else if (Mai_CheckIfEmailIsValid (Gbl.Usrs.Me.UsrIdLogin)) // 2: It's an email
/* User has typed an email */
2014-12-01 23:55:08 +01:00
// TODO: Get only if email confirmed?
Gbl.Usrs.Me.UsrDat.UsrCod = DB_QuerySELECTCode ("can not get user's data",
"SELECT UsrCod"
" FROM usr_emails"
" WHERE E_mail='%s'",
UsrIDNickOrEmail);
2016-11-16 23:19:52 +01:00
else // 3: It's not a nickname nor email
2014-12-01 23:55:08 +01:00
{
// Users' IDs are always stored internally in capitals and without leading zeros
Str_RemoveLeadingZeros (UsrIDNickOrEmail);
Str_ConvertToUpperText (UsrIDNickOrEmail);
if (ID_CheckIfUsrIDIsValid (UsrIDNickOrEmail))
/* User has typed a valid user's ID (existing or not) */
// TODO: Get only if ID confirmed?
Gbl.Usrs.Me.UsrDat.UsrCod = DB_QuerySELECTCode ("can not get user's data",
"SELECT UsrCod"
" FROM usr_ids"
" WHERE UsrID='%s'",
UsrIDNickOrEmail);
2016-11-16 23:19:52 +01:00
else // String is not a valid user's nickname, email or ID
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad log in",
2016-11-16 23:19:52 +01:00
"User's email, nickname or ID don't exist");
2014-12-01 23:55:08 +01:00
}
/***** Get user's data from database *****/
if (Gbl.Usrs.Me.UsrDat.UsrCod > 0) // One unique user found in table of users' data
2014-12-01 23:55:08 +01:00
{
Usr_GetUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat, // Get my data
Usr_DONT_GET_PREFS,
Usr_DONT_GET_ROLE_IN_CURRENT_CRS);
2014-12-01 23:55:08 +01:00
if (Gbl.Usrs.Me.UsrDat.Email[0])
if (Pwd_SendNewPasswordByEmail (NewRandomPlainPassword) == 0) // Message sent successfully
{
Pwd_SetMyPendingPassword (NewRandomPlainPassword);
getNewPasswordOut->success = 1;
}
}
return SOAP_OK;
}
/*****************************************************************************/
/************************ Return courses of a user ***************************/
/*****************************************************************************/
int swad__getCourses (struct soap *soap,
char *wsKey, // input
struct swad__getCoursesOutput *getCoursesOut) // output
{
int ReturnCode;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2017-01-15 18:02:52 +01:00
unsigned NumRow;
unsigned NumRows;
2014-12-01 23:55:08 +01:00
Rol_Role_t Role;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getCourses;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Query my courses from database *****/
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get user's courses",
"SELECT crs_courses.CrsCod," // row[0]
"crs_courses.ShortName," // row[1]
"crs_courses.FullName," // row[2]
"crs_users.Role" // row[3]
" FROM crs_users,"
"crs_courses"
" WHERE crs_users.UsrCod=%ld"
" AND crs_users.CrsCod=crs_courses.CrsCod"
" ORDER BY crs_courses.FullName",
Gbl.Usrs.Me.UsrDat.UsrCod);
2014-12-01 23:55:08 +01:00
getCoursesOut->numCourses = (int) NumRows;
getCoursesOut->coursesArray.__size = (int) NumRows;
if (NumRows == 0)
getCoursesOut->coursesArray.__ptr = NULL;
else // Courses found
{
2020-02-24 19:31:55 +01:00
getCoursesOut->coursesArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getCoursesOut->coursesArray.__size) *
sizeof (*(getCoursesOut->coursesArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next course */
row = mysql_fetch_row (mysql_res);
/* Get course code (row[0]) */
getCoursesOut->coursesArray.__ptr[NumRow].courseCode = (int) Str_ConvertStrCodToLongCod (row[0]);
/* Get course short name (row[1]) */
2019-12-06 11:53:14 +01:00
getCoursesOut->coursesArray.__ptr[NumRow].courseShortName =
soap_malloc (soap,Cns_HIERARCHY_MAX_BYTES_SHRT_NAME + 1);
Str_Copy (getCoursesOut->coursesArray.__ptr[NumRow].courseShortName,
row[1],Cns_HIERARCHY_MAX_BYTES_SHRT_NAME);
2014-12-01 23:55:08 +01:00
/* Get course full name (row[2]) */
2019-12-06 11:53:14 +01:00
getCoursesOut->coursesArray.__ptr[NumRow].courseFullName =
soap_malloc (soap,Cns_HIERARCHY_MAX_BYTES_FULL_NAME + 1);
Str_Copy (getCoursesOut->coursesArray.__ptr[NumRow].courseFullName,
row[2],Cns_HIERARCHY_MAX_BYTES_FULL_NAME);
2014-12-01 23:55:08 +01:00
/* Get role (row[3]) */
if (sscanf (row[3],"%u",&Role) != 1) // Role in this course
2017-05-18 19:13:41 +02:00
Role = Rol_UNK;
2019-05-16 14:02:06 +02:00
getCoursesOut->coursesArray.__ptr[NumRow].userRole = API_RolRole_to_SvcRole[Role];
2014-12-01 23:55:08 +01:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/************************ Return course information **************************/
/*****************************************************************************/
// TODO: Not completely implemented
int swad__getCourseInfo (struct soap *soap,
char *wsKey,int courseCode,char *infoType, // input
struct swad__getCourseInfoOutput *getCourseInfo) // output
{
int ReturnCode;
2020-04-12 02:47:32 +02:00
struct Syl_Syllabus Syllabus;
Inf_Type_t InfoType;
2017-01-15 22:58:26 +01:00
size_t Length;
struct Inf_FromDB FromDB;
2014-12-01 23:55:08 +01:00
int Result = SOAP_OK;
const char *NamesInWSForInfoType[Inf_NUM_TYPES] =
2014-12-01 23:55:08 +01:00
{
2019-12-15 01:10:36 +01:00
[Inf_INTRODUCTION ] = "introduction",
[Inf_TEACHING_GUIDE] = "guide",
[Inf_LECTURES ] = "lectures",
[Inf_PRACTICALS ] = "practicals",
[Inf_BIBLIOGRAPHY ] = "bibliography",
[Inf_FAQ ] = "FAQ",
[Inf_LINKS ] = "links",
[Inf_ASSESSMENT ] = "assessment",
2014-12-01 23:55:08 +01:00
};
const char *NamesInWSForInfoSrc[Inf_NUM_SOURCES] =
2014-12-01 23:55:08 +01:00
{
[Inf_NONE ] = "none",
[Inf_EDITOR ] = "editor",
[Inf_PLAIN_TEXT] = "plainText",
[Inf_RICH_TEXT ] = "richText",
[Inf_PAGE ] = "page",
[Inf_URL ] = "URL",
2014-12-01 23:55:08 +01:00
};
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getCourseInfo;
2020-09-25 12:43:21 +02:00
/***** Initialize hierarchy *****/
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2020-09-25 12:43:21 +02:00
Hie_InitHierarchy ();
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Check course and group codes *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
-1L)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to course");
2020-04-12 02:47:32 +02:00
/***** Reset syllabus context *****/
Syl_ResetSyllabus (&Syllabus);
2014-12-01 23:55:08 +01:00
/***** Get info source *****/
for (InfoType = (Inf_Type_t) 0;
InfoType <= (Inf_Type_t) (Inf_NUM_TYPES - 1);
2014-12-01 23:55:08 +01:00
InfoType++)
if (!strcmp (infoType,NamesInWSForInfoType[InfoType]))
break;
if (InfoType == Inf_NUM_TYPES) // Not found!
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad info type",
"Unknown requested info type");
2019-04-04 10:45:15 +02:00
Gbl.Crs.Info.Type = InfoType;
2020-04-12 02:47:32 +02:00
Inf_GetAndCheckInfoSrcFromDB (&Syllabus,
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Crs.Info.Type,
&FromDB);
Length = strlen (NamesInWSForInfoSrc[FromDB.Src]);
getCourseInfo->infoSrc = soap_malloc (soap,Length + 1);
Str_Copy (getCourseInfo->infoSrc,NamesInWSForInfoSrc[FromDB.Src],Length);
2014-12-01 23:55:08 +01:00
/***** Get info text *****/
getCourseInfo->infoTxt = NULL;
switch (FromDB.Src)
2014-12-01 23:55:08 +01:00
{
case Inf_NONE: // No info available
2014-12-01 23:55:08 +01:00
break;
case Inf_EDITOR: // Internal editor (only for syllabus)
2019-04-04 10:45:15 +02:00
switch (Gbl.Crs.Info.Type)
2014-12-01 23:55:08 +01:00
{
case Inf_LECTURES: // Syllabus (lectures)
case Inf_PRACTICALS: // Syllabys (practicals)
2020-04-12 02:47:32 +02:00
Result = API_WriteSyllabusIntoHTMLBuffer (soap,&Syllabus,&(getCourseInfo->infoTxt));
2014-12-01 23:55:08 +01:00
break;
default:
break;
}
break;
case Inf_PLAIN_TEXT: // Plain text
case Inf_RICH_TEXT: // Rich text (not yet available)
2020-02-24 19:31:55 +01:00
Result = API_WritePlainTextIntoHTMLBuffer (soap,&(getCourseInfo->infoTxt));
2014-12-01 23:55:08 +01:00
break;
case Inf_PAGE: // Web page hosted in SWAD server
2020-02-24 19:31:55 +01:00
Result = API_WritePageIntoHTMLBuffer (soap,&(getCourseInfo->infoTxt));
2014-12-01 23:55:08 +01:00
break;
case Inf_URL: // Link to a web page
getCourseInfo->infoTxt = soap_malloc (soap,Cns_MAX_BYTES_WWW + 1);
2016-03-17 10:39:23 +01:00
Inf_WriteURLIntoTxtBuffer (getCourseInfo->infoTxt);
2014-12-01 23:55:08 +01:00
break;
}
/***** Return empty text if pointer is null *****/
if (getCourseInfo->infoTxt == NULL)
{
getCourseInfo->infoTxt = soap_malloc (soap,1);
2014-12-01 23:55:08 +01:00
getCourseInfo->infoTxt[0] = '\0';
}
return Result;
}
2020-02-24 19:31:55 +01:00
/*****************************************************************************/
/************** Write the syllabus into a temporary HTML file ****************/
/*****************************************************************************/
static int API_WriteSyllabusIntoHTMLBuffer (struct soap *soap,
2020-04-12 02:47:32 +02:00
struct Syl_Syllabus *Syllabus,
2020-02-24 19:31:55 +01:00
char **HTMLBuffer)
{
extern struct LstItemsSyllabus Syl_LstItemsSyllabus;
char FileNameHTMLTmp[PATH_MAX + 1];
FILE *FileHTMLTmp;
size_t Length;
/***** Initialize buffer *****/
*HTMLBuffer = NULL;
/***** Load syllabus from XML file to list of items in memory *****/
2020-04-12 02:47:32 +02:00
Syl_LoadListItemsSyllabusIntoMemory (Syllabus,Gbl.Hierarchy.Crs.CrsCod);
2020-02-24 19:31:55 +01:00
if (Syl_LstItemsSyllabus.NumItems)
{
/***** Create a unique name for the file *****/
snprintf (FileNameHTMLTmp,sizeof (FileNameHTMLTmp),"%s/%s_syllabus.html",
2020-02-24 19:31:55 +01:00
Cfg_PATH_OUT_PRIVATE,Gbl.UniqueNameEncrypted);
/***** Create a new temporary file for writing and reading *****/
if ((FileHTMLTmp = fopen (FileNameHTMLTmp,"w+b")) == NULL)
{
Syl_FreeListItemsSyllabus ();
return soap_receiver_fault (soap,
"Syllabus can not be copied into buffer",
"Can not create temporary file");
}
/***** Write syllabus in HTML into a temporary file *****/
Syl_WriteSyllabusIntoHTMLTmpFile (FileHTMLTmp);
/***** Write syllabus from list of items in memory to text buffer *****/
/* Compute length of file */
Length = (size_t) ftell (FileHTMLTmp);
/* Allocate memory for buffer */
if ((*HTMLBuffer = malloc (Length + 1)) == NULL)
2020-02-24 19:31:55 +01:00
{
fclose (FileHTMLTmp);
unlink (FileNameHTMLTmp);
Syl_FreeListItemsSyllabus ();
return soap_receiver_fault (soap,
"Syllabus can not be copied into buffer",
"Not enough memory for buffer");
}
/* Copy file content into buffer */
fseek (FileHTMLTmp,0L,SEEK_SET);
if (fread (*HTMLBuffer,sizeof (char),Length,FileHTMLTmp) != Length)
{
fclose (FileHTMLTmp);
unlink (FileNameHTMLTmp);
Syl_FreeListItemsSyllabus ();
return soap_receiver_fault (soap,
"Syllabus can not be copied into buffer",
"Error reading file into buffer");
}
(*HTMLBuffer)[Length] = '\0';
/***** Close and remove temporary file *****/
fclose (FileHTMLTmp);
unlink (FileNameHTMLTmp);
}
/***** Free list of items *****/
Syl_FreeListItemsSyllabus ();
return SOAP_OK;
}
/*****************************************************************************/
/************* Check if exists and write page into HTML buffer ***************/
/*****************************************************************************/
static int API_WritePlainTextIntoHTMLBuffer (struct soap *soap,
char **HTMLBuffer)
{
extern const char *Txt_INFO_TITLE[Inf_NUM_TYPES];
2020-02-24 19:31:55 +01:00
char TxtHTML[Cns_MAX_BYTES_LONG_TEXT + 1];
char FileNameHTMLTmp[PATH_MAX + 1];
FILE *FileHTMLTmp;
size_t Length;
/***** Initialize buffer *****/
*HTMLBuffer = NULL;
/***** Get info text from database *****/
Inf_GetInfoTxtFromDB (Gbl.Hierarchy.Crs.CrsCod,Gbl.Crs.Info.Type,
TxtHTML,NULL);
if (TxtHTML[0])
{
/***** Create a unique name for the file *****/
snprintf (FileNameHTMLTmp,sizeof (FileNameHTMLTmp),"%s/%s_info.html",
2020-02-24 19:31:55 +01:00
Cfg_PATH_OUT_PRIVATE,Gbl.UniqueNameEncrypted);
/***** Create a new temporary file for writing and reading *****/
if ((FileHTMLTmp = fopen (FileNameHTMLTmp,"w+b")) == NULL)
return soap_receiver_fault (soap,
"Plain text can not be copied into buffer",
"Can not create temporary file");
/***** Write start of HTML code *****/
Lay_BeginHTMLFile (FileHTMLTmp,Txt_INFO_TITLE[Gbl.Crs.Info.Type]);
2020-02-24 19:31:55 +01:00
fprintf (FileHTMLTmp,"<body>\n"
"<div class=\"DAT LM\">\n");
/***** Write plain text into text buffer *****/
/* Convert to respectful HTML and insert links */
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
TxtHTML,Cns_MAX_BYTES_LONG_TEXT,false); // Convert from HTML to recpectful HTML
Str_InsertLinks (TxtHTML,Cns_MAX_BYTES_LONG_TEXT,60); // Insert links
/* Write text */
fprintf (FileHTMLTmp,"%s",TxtHTML);
/***** Write end of page into file *****/
fprintf (FileHTMLTmp,"</div>\n"
"</html>\n"
"</body>\n");
/***** Compute length of file *****/
Length = (size_t) ftell (FileHTMLTmp);
/***** Allocate memory for buffer *****/
if ((*HTMLBuffer = malloc (Length + 1)) == NULL)
2020-02-24 19:31:55 +01:00
{
fclose (FileHTMLTmp);
unlink (FileNameHTMLTmp);
return soap_receiver_fault (soap,
"Plain text can not be copied into buffer",
"Not enough memory for buffer");
}
/***** Copy file content into buffer *****/
fseek (FileHTMLTmp,0L,SEEK_SET);
if (fread (*HTMLBuffer,sizeof (char),Length,FileHTMLTmp) != Length)
{
fclose (FileHTMLTmp);
unlink (FileNameHTMLTmp);
return soap_receiver_fault (soap,
"Plain text can not be copied into buffer",
"Error reading file into buffer");
}
(*HTMLBuffer)[Length] = '\0';
/***** Close and remove temporary file *****/
fclose (FileHTMLTmp);
unlink (FileNameHTMLTmp);
}
return SOAP_OK;
}
/*****************************************************************************/
/************* Check if exists and write page into HTML buffer ***************/
/*****************************************************************************/
static int API_WritePageIntoHTMLBuffer (struct soap *soap,
char **HTMLBuffer)
{
char PathRelDirHTML[PATH_MAX + 1];
char PathRelFileHTML[PATH_MAX + 1 + 10 + 1];
FILE *FileHTML;
bool FileExists = false;
size_t Length;
/***** Initialize buffer *****/
*HTMLBuffer = NULL;
/***** Build path of directory containing web page *****/
Inf_BuildPathPage (Gbl.Hierarchy.Crs.CrsCod,Gbl.Crs.Info.Type,PathRelDirHTML);
/***** Open file with web page *****/
/* 1. Check if index.html exists */
snprintf (PathRelFileHTML,sizeof (PathRelFileHTML),"%s/index.html",
2020-02-24 19:31:55 +01:00
PathRelDirHTML);
if (Fil_CheckIfPathExists (PathRelFileHTML)) // TODO: Check if not empty?
FileExists = true;
else
{
/* 2. If index.html not exists, try index.htm */
snprintf (PathRelFileHTML,sizeof (PathRelFileHTML),"%s/index.htm",
2020-02-24 19:31:55 +01:00
PathRelDirHTML);
if (Fil_CheckIfPathExists (PathRelFileHTML)) // TODO: Check if not empty?
FileExists = true;
}
if (FileExists)
{
/***** Write page from file to text buffer *****/
/* Open file */
if ((FileHTML = fopen (PathRelFileHTML,"rb")) == NULL)
Err_FileFolderNotFoundExit ();
2020-02-24 19:31:55 +01:00
/* Compute file size */
fseek (FileHTML,0L,SEEK_END);
Length = (size_t) ftell (FileHTML);
fseek (FileHTML,0L,SEEK_SET);
/* Allocate memory for buffer */
if ((*HTMLBuffer = malloc (Length + 1)) == NULL)
2020-02-24 19:31:55 +01:00
{
fclose (FileHTML);
Err_NotEnoughMemoryExit ();
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
"Web page can not be copied into buffer",
"Not enough memory for buffer");
}
/* Copy file content into buffer */
if (fread (*HTMLBuffer,sizeof (char),Length,FileHTML) != Length)
{
fclose (FileHTML);
return soap_receiver_fault (soap,
"Web page can not be copied into buffer",
"Error reading web page into buffer");
}
(*HTMLBuffer)[Length] = '\0';
/***** Close HTML file *****/
fclose (FileHTML);
}
return SOAP_OK;
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2016-06-29 18:27:49 +02:00
/************* Get users in a course (and optionally in groups) **************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
int swad__getUsers (struct soap *soap,
2016-06-29 18:27:49 +02:00
char *wsKey,int courseCode,char *groups,int userRole, // input
2014-12-01 23:55:08 +01:00
struct swad__getUsersOutput *getUsersOut) // output
{
int ReturnCode;
2016-06-29 18:27:49 +02:00
Rol_Role_t Role;
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getUsers;
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (courseCode > 0) ? (long) courseCode :
2016-06-29 18:27:49 +02:00
-1L;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
2016-06-29 18:27:49 +02:00
/***** Check course *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
-1L)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-06-29 18:27:49 +02:00
"Request forbidden",
"Requester must belong to course");
2014-12-01 23:55:08 +01:00
/***** Get degree of current course *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK) // TODO: Is this necessary?
2014-12-01 23:55:08 +01:00
return ReturnCode;
2016-06-29 18:27:49 +02:00
/***** Check requested users' role *****/
2019-05-16 14:02:06 +02:00
if (userRole != API_ROLE_STUDENT && // Students
userRole != API_ROLE_TEACHER) // Teachers
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad requested users' type",
2016-06-29 18:27:49 +02:00
"User roles allowed are 2 (students) or 3 (teachers)");
2019-05-16 14:02:06 +02:00
Role = API_SvcRole_to_RolRole[userRole];
2016-06-29 18:27:49 +02:00
/***** Create a list of groups selected *****/
2019-05-16 14:02:06 +02:00
API_GetLstGrpsSel (groups);
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps)
2016-06-29 18:27:49 +02:00
/***** Get list of groups types and groups in current course *****/
Grp_GetListGrpTypesInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
/***** Get list of users *****/
Usr_GetListUsrs (HieLvl_CRS,Role);
2020-02-24 19:31:55 +01:00
API_CopyListUsers (soap,
Role,getUsersOut);
2016-06-29 18:27:49 +02:00
Usr_FreeUsrsList (Role);
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps)
2016-06-29 18:27:49 +02:00
{
/***** Free list of groups types and groups in current course *****/
Grp_FreeListGrpTypesAndGrps ();
/***** Free memory for list of selected groups *****/
Grp_FreeListCodSelectedGrps ();
}
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;
2017-03-07 11:03:05 +01:00
char SearchQuery[Sch_MAX_BYTES_SEARCH_QUERY + 1];
2016-06-29 18:27:49 +02:00
Rol_Role_t Role;
bool FilterTooShort = false;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_findUsers;
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (courseCode > 0) ? (long) courseCode :
2016-06-29 18:27:49 +02:00
-1L;
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2016-06-29 18:27:49 +02:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-06-29 18:27:49 +02:00
"Bad web service key",
"Web service key does not exist in database");
if (Gbl.Hierarchy.Level == HieLvl_CRS) // Course selected
2016-06-29 18:27:49 +02:00
/***** Check course *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
-1L)) != SOAP_OK)
2016-06-29 18:27:49 +02:00
return ReturnCode;
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2016-06-29 18:27:49 +02:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2016-06-29 18:27:49 +02:00
if (Gbl.Hierarchy.Level == HieLvl_CRS) // Course selected
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-06-29 18:27:49 +02:00
"Request forbidden",
"Requester must belong to course");
if (Gbl.Hierarchy.Level == HieLvl_CRS)
2016-06-29 18:27:49 +02:00
{
/***** Get degree of current course *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK) // TODO: Is this necessary?
2016-06-29 18:27:49 +02:00
return ReturnCode;
2014-12-01 23:55:08 +01:00
}
2016-06-29 18:27:49 +02:00
/***** Check requested users' role *****/
2019-05-16 14:02:06 +02:00
if (userRole < API_ROLE_UNKNOWN ||
userRole > API_ROLE_TEACHER)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2016-06-29 18:27:49 +02:00
"Bad requested users' type",
2016-07-04 10:26:44 +02:00
"User roles allowed are 0 (all), 1 (guests), 2 (students) or 3 (teachers)");
2019-05-16 14:02:06 +02:00
Role = API_SvcRole_to_RolRole[userRole];
2016-06-29 18:27:49 +02:00
2014-12-01 23:55:08 +01:00
/***** Query users beloging to course or group from database *****/
Str_Copy (Gbl.Search.Str,filter,sizeof (Gbl.Search.Str) - 1);
2014-12-01 23:55:08 +01:00
2016-06-29 18:27:49 +02:00
if (Gbl.Search.Str[0]) // Search some users
2014-12-01 23:55:08 +01:00
{
Gbl.Scope.Current = (Gbl.Hierarchy.Level == HieLvl_CRS) ? HieLvl_CRS :
HieLvl_SYS;
2016-06-29 18:27:49 +02:00
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);
2014-12-01 23:55:08 +01:00
2016-06-29 18:27:49 +02:00
/***** Search for users *****/
Usr_SearchListUsrs (Role);
2020-02-24 19:31:55 +01:00
API_CopyListUsers (soap,
Role,getUsersOut);
2016-06-29 18:27:49 +02:00
Usr_FreeUsrsList (Role);
2014-12-01 23:55:08 +01:00
2016-06-29 18:27:49 +02:00
/***** Drop temporary table with candidate users *****/
Usr_DropTmpTableWithCandidateUsrs ();
2014-12-01 23:55:08 +01:00
}
2016-06-29 18:27:49 +02:00
else
FilterTooShort = true;
2014-12-01 23:55:08 +01:00
}
2016-06-29 18:27:49 +02:00
else
FilterTooShort = true;
2014-12-01 23:55:08 +01:00
2016-06-29 18:27:49 +02:00
/***** Return error in filter? *****/
if (FilterTooShort)
{
getUsersOut->numUsers = -1; // < 0 ==> filter too short
getUsersOut->usersArray.__size = 0;
getUsersOut->usersArray.__ptr = NULL;
}
2014-12-01 23:55:08 +01:00
return SOAP_OK;
}
2016-06-29 18:27:49 +02:00
/*****************************************************************************/
/***************************** Copy users from list **************************/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static void API_CopyListUsers (struct soap *soap,
Rol_Role_t Role,
struct swad__getUsersOutput *getUsersOut)
2016-06-29 18:27:49 +02:00
{
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;
2020-02-24 19:31:55 +01:00
getUsersOut->usersArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getUsersOut->usersArray.__size) *
sizeof (*(getUsersOut->usersArray.__ptr)));
2016-06-29 18:27:49 +02:00
/***** Initialize structure with user's data *****/
Usr_UsrDataConstructor (&UsrDat);
/***** List data of users *****/
for (NumUsr = 0;
NumUsr < NumUsrs;
NumUsr++)
{
2016-07-26 12:48:52 +02:00
/* Copy user's basic data from list */
Usr_CopyBasicUsrDataFromList (&UsrDat,&Gbl.Usrs.LstUsrs[Role].Lst[NumUsr]);
2016-06-29 18:27:49 +02:00
2016-07-26 12:48:52 +02:00
/* Get list of user's IDs */
ID_GetListIDsFromUsrCod (&UsrDat);
2017-01-27 01:02:52 +01:00
ICanSeeUsrID = ID_ICanSeeOtherUsrIDs (&UsrDat);
2016-06-29 18:27:49 +02:00
2016-07-26 12:48:52 +02:00
/* Get nickname */
Nck_DB_GetNicknameFromUsrCod (UsrDat.UsrCod,UsrDat.Nickname);
2016-06-29 18:27:49 +02:00
2016-07-26 12:48:52 +02:00
/* Copy user's data into output structure */
2020-02-24 19:31:55 +01:00
API_CopyUsrData (soap,
&(getUsersOut->usersArray.__ptr[NumUsr]),
&UsrDat,
ICanSeeUsrID);
2016-06-29 18:27:49 +02:00
}
/***** Free memory used for user's data *****/
Usr_UsrDataDestructor (&UsrDat);
}
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/********************** Return group types in a course ***********************/
/*****************************************************************************/
int swad__getGroupTypes (struct soap *soap,
char *wsKey,int courseCode, // input
struct swad__getGroupTypesOutput *getGroupTypesOut) // output
{
int ReturnCode;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2017-01-15 18:02:52 +01:00
unsigned NumRow;
unsigned NumRows;
2014-12-01 23:55:08 +01:00
long OpenTime;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getGroupTypes;
2020-09-25 12:43:21 +02:00
/***** Initialize hierarchy *****/
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2020-09-25 12:43:21 +02:00
Hie_InitHierarchy ();
2014-12-01 23:55:08 +01:00
/***** Open groups of this course that must be opened
if open time is in the past *****/
Grp_OpenGroupsAutomatically ();
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Check if course code is correct *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to course");
/***** Query group types in a course from database *****/
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get group types",
"SELECT GrpTypCod," // row[0]
"GrpTypName," // row[1]
"Mandatory," // row[2]
"Multiple," // row[3]
"UNIX_TIMESTAMP(OpenTime)" // row[4]
" FROM grp_types"
" WHERE CrsCod=%d"
" ORDER BY GrpTypName",
courseCode);
2014-12-01 23:55:08 +01:00
getGroupTypesOut->numGroupTypes = (int) NumRows;
getGroupTypesOut->groupTypesArray.__size = (int) NumRows;
if (NumRows == 0)
getGroupTypesOut->groupTypesArray.__ptr = NULL;
else // Groups found
{
2020-02-24 19:31:55 +01:00
getGroupTypesOut->groupTypesArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getGroupTypesOut->groupTypesArray.__size) *
sizeof (*(getGroupTypesOut->groupTypesArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next group */
row = mysql_fetch_row (mysql_res);
/* Get group type code (row[0]) */
getGroupTypesOut->groupTypesArray.__ptr[NumRow].groupTypeCode = (int) Str_ConvertStrCodToLongCod (row[0]);
/* Get group type name (row[1]) */
2019-12-06 11:53:14 +01:00
getGroupTypesOut->groupTypesArray.__ptr[NumRow].groupTypeName =
soap_malloc (soap,Grp_MAX_BYTES_GROUP_TYPE_NAME + 1);
Str_Copy (getGroupTypesOut->groupTypesArray.__ptr[NumRow].groupTypeName,
row[1],Grp_MAX_BYTES_GROUP_TYPE_NAME);
2014-12-01 23:55:08 +01:00
2017-03-30 11:20:06 +02:00
/* Get whether enrolment is mandatory ('Y') or voluntary ('N') (row[2]) */
2014-12-01 23:55:08 +01:00
getGroupTypesOut->groupTypesArray.__ptr[NumRow].mandatory = (row[2][0] == 'Y') ? 1 :
0;
2017-03-30 11:20:06 +02:00
/* Get whether user can enrol in multiple groups ('Y') or only in one group ('N') (row[3]) */
2014-12-01 23:55:08 +01:00
getGroupTypesOut->groupTypesArray.__ptr[NumRow].multiple = (row[3][0] == 'Y') ? 1 :
0;
/* Get time of opening (row[4]) */
OpenTime = 0L;
if (row[4])
sscanf (row[4],"%ld",&OpenTime);
getGroupTypesOut->groupTypesArray.__ptr[NumRow].openTime = OpenTime;
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/************************** Return groups in a course ************************/
/*****************************************************************************/
int swad__getGroups (struct soap *soap,
char *wsKey,int courseCode, // input
struct swad__getGroupsOutput *getGroupsOut) // output
{
int ReturnCode;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRow,NumRows;
long GrpCod;
unsigned MaxStudents;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getGroups;
2020-09-25 12:43:21 +02:00
/***** Initialize hierarchy *****/
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2020-09-25 12:43:21 +02:00
Hie_InitHierarchy ();
2014-12-01 23:55:08 +01:00
/***** Open groups of this course that must be opened
if open time is in the past *****/
Grp_OpenGroupsAutomatically ();
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Check if course code is correct *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to course");
/***** Query groups in a course from database *****/
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get user's groups",
"SELECT grp_types.GrpTypCod," // row[0]
"grp_types.GrpTypName," // row[1]
"grp_groups.GrpCod," // row[2]
"grp_groups.GrpName," // row[3]
"grp_groups.MaxStudents," // row[4]
"grp_groups.Open, " // row[5]
"grp_groups.FileZones" // row[6]
" FROM grp_types,"
"grp_groups"
" WHERE grp_types.CrsCod=%d"
" AND grp_types.GrpTypCod=grp_groups.GrpTypCod"
" ORDER BY grp_types.GrpTypName,"
"grp_groups.GrpName",
courseCode);
2014-12-01 23:55:08 +01:00
getGroupsOut->numGroups = (int) NumRows;
getGroupsOut->groupsArray.__size = (int) NumRows;
if (NumRows == 0)
getGroupsOut->groupsArray.__ptr = NULL;
else // Groups found
{
2020-02-24 19:31:55 +01:00
getGroupsOut->groupsArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getGroupsOut->groupsArray.__size) *
sizeof (*(getGroupsOut->groupsArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next group */
row = mysql_fetch_row (mysql_res);
/* Get group type code (row[0]) */
getGroupsOut->groupsArray.__ptr[NumRow].groupTypeCode = (int) Str_ConvertStrCodToLongCod (row[0]);
/* Get group type name (row[1]) */
2019-12-06 11:53:14 +01:00
getGroupsOut->groupsArray.__ptr[NumRow].groupTypeName =
soap_malloc (soap,Grp_MAX_BYTES_GROUP_TYPE_NAME + 1);
2017-01-17 03:10:43 +01:00
Str_Copy (getGroupsOut->groupsArray.__ptr[NumRow].groupTypeName,row[1],
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_TYPE_NAME);
2014-12-01 23:55:08 +01:00
/* Get group code (row[2]) */
GrpCod = Str_ConvertStrCodToLongCod (row[2]);
getGroupsOut->groupsArray.__ptr[NumRow].groupCode = (int) GrpCod;
/* Get group name (row[3]) */
2019-12-06 11:53:14 +01:00
getGroupsOut->groupsArray.__ptr[NumRow].groupName =
soap_malloc (soap,Grp_MAX_BYTES_GROUP_NAME + 1);
2017-01-17 03:10:43 +01:00
Str_Copy (getGroupsOut->groupsArray.__ptr[NumRow].groupName,row[3],
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_NAME);
2014-12-01 23:55:08 +01:00
/* Get max number of students of group (row[4]) and number of current students */
MaxStudents = Grp_ConvertToNumMaxStdsGrp (row[4]);
getGroupsOut->groupsArray.__ptr[NumRow].maxStudents = (MaxStudents > Grp_MAX_STUDENTS_IN_A_GROUP) ? -1 :
(int) MaxStudents;
/* Get number of current students */
getGroupsOut->groupsArray.__ptr[NumRow].numStudents = (int) Grp_DB_CountNumUsrsInGrp (Rol_STD,GrpCod);
2014-12-01 23:55:08 +01:00
/* Get whether group is open ('Y') or closed ('N') (row[5]) */
getGroupsOut->groupsArray.__ptr[NumRow].open = (row[5][0] == 'Y') ? 1 :
0;
/* Get whether group have file zones ('Y') or not ('N') (row[6]) */
getGroupsOut->groupsArray.__ptr[NumRow].fileZones = (row[6][0] == 'Y') ? 1 :
0;
/* Get whether I belong to this group or not */
getGroupsOut->groupsArray.__ptr[NumRow].member = Grp_GetIfIBelongToGrp (GrpCod) ? 1 :
0;
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/************************* Send my groups in a course ************************/
/*****************************************************************************/
int swad__sendMyGroups (struct soap *soap,
char *wsKey,int courseCode,char *myGroups, // input
struct swad__sendMyGroupsOutput *SendMyGroupsOut) // output
{
int ReturnCode;
struct ListCodGrps LstGrpsIWant;
const char *Ptr;
2019-11-08 01:10:32 +01:00
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2014-12-01 23:55:08 +01:00
unsigned NumGrp;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2018-11-02 01:23:05 +01:00
unsigned NumRow;
unsigned NumRows;
2014-12-01 23:55:08 +01:00
long GrpCod;
unsigned MaxStudents;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_sendMyGroups;
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Check if course code is correct *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to course");
/***** Get the group codes which I want to join to *****/
LstGrpsIWant.NumGrps = 0;
2017-01-19 20:55:31 +01:00
LstGrpsIWant.GrpCods = NULL;
2014-12-01 23:55:08 +01:00
if (myGroups[0])
{
/***** Count number of desired groups *****/
for (NumGrp = 0, Ptr = myGroups;
*Ptr;
NumGrp++)
2019-11-08 01:10:32 +01:00
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2014-12-01 23:55:08 +01:00
LstGrpsIWant.NumGrps = NumGrp;
if (LstGrpsIWant.NumGrps) // If I have selected groups...
{
/***** Create a list of groups selected from myGroups *****/
if ((LstGrpsIWant.GrpCods = calloc (LstGrpsIWant.NumGrps,
sizeof (*LstGrpsIWant.GrpCods))) == NULL)
Err_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
for (NumGrp = 0, Ptr = myGroups;
*Ptr;
NumGrp++)
{
/* Find next string in text until comma (leading and trailing spaces are removed) */
2019-11-08 01:10:32 +01:00
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2017-01-19 20:55:31 +01:00
LstGrpsIWant.GrpCods[NumGrp] = Str_ConvertStrCodToLongCod (LongStr);
2014-12-01 23:55:08 +01:00
}
}
}
/***** Change my groups *****/
SendMyGroupsOut->success = Grp_ChangeMyGrpsAtomically (&LstGrpsIWant);
/***** Free memory with the list of groups which I want to belong to *****/
Grp_FreeListCodGrp (&LstGrpsIWant);
/***** Query groups in a course from database *****/
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get user's groups",
"SELECT grp_types.GrpTypCod," // row[0]
"grp_types.GrpTypName," // row[1]
"grp_groups.GrpCod," // row[2]
"grp_groups.GrpName," // row[3]
"grp_groups.MaxStudents," // row[4]
"grp_groups.Open," // row[5]
"grp_groups.FileZones" // row[6]
" FROM grp_types,"
"grp_groups"
" WHERE grp_types.CrsCod=%d"
" AND grp_types.GrpTypCod=grp_groups.GrpTypCod"
" ORDER BY grp_types.GrpTypName,"
"grp_groups.GrpName",
courseCode);
2014-12-01 23:55:08 +01:00
SendMyGroupsOut->numGroups = (int) NumRows;
SendMyGroupsOut->groupsArray.__size = (int) NumRows;
if (NumRows == 0)
SendMyGroupsOut->groupsArray.__ptr = NULL;
else // Groups found
{
2020-02-24 19:31:55 +01:00
SendMyGroupsOut->groupsArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(SendMyGroupsOut->groupsArray.__size) *
sizeof (*(SendMyGroupsOut->groupsArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next group */
row = mysql_fetch_row (mysql_res);
/* Get group type code (row[0]) */
SendMyGroupsOut->groupsArray.__ptr[NumRow].groupTypeCode = (int) Str_ConvertStrCodToLongCod (row[0]);
/* Get group type name (row[1]) */
2019-12-06 11:53:14 +01:00
SendMyGroupsOut->groupsArray.__ptr[NumRow].groupTypeName =
soap_malloc (soap,Grp_MAX_BYTES_GROUP_TYPE_NAME + 1);
2017-01-17 03:10:43 +01:00
Str_Copy (SendMyGroupsOut->groupsArray.__ptr[NumRow].groupTypeName,row[1],
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_TYPE_NAME);
2014-12-01 23:55:08 +01:00
/* Get group code (row[2]) */
GrpCod = Str_ConvertStrCodToLongCod (row[2]);
SendMyGroupsOut->groupsArray.__ptr[NumRow].groupCode = (int) GrpCod;
/* Get group name (row[3]) */
2019-12-06 11:53:14 +01:00
SendMyGroupsOut->groupsArray.__ptr[NumRow].groupName =
soap_malloc (soap,Grp_MAX_BYTES_GROUP_NAME + 1);
2017-01-17 03:10:43 +01:00
Str_Copy (SendMyGroupsOut->groupsArray.__ptr[NumRow].groupName,row[3],
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_NAME);
2014-12-01 23:55:08 +01:00
/* Get max number of students of group (row[4]) and number of current students */
MaxStudents = Grp_ConvertToNumMaxStdsGrp (row[4]);
SendMyGroupsOut->groupsArray.__ptr[NumRow].maxStudents = (MaxStudents > Grp_MAX_STUDENTS_IN_A_GROUP) ? -1 :
(int) MaxStudents;
/* Get number of current students */
SendMyGroupsOut->groupsArray.__ptr[NumRow].numStudents = (int) Grp_DB_CountNumUsrsInGrp (Rol_STD,GrpCod);
2014-12-01 23:55:08 +01:00
/* Get whether group is open ('Y') or closed ('N') (row[5]) */
SendMyGroupsOut->groupsArray.__ptr[NumRow].open = (row[5][0] == 'Y') ? 1 :
0;
/* Get whether group have file zones ('Y') or not ('N') (row[6]) */
SendMyGroupsOut->groupsArray.__ptr[NumRow].fileZones = (row[6][0] == 'Y') ? 1 :
0;
/* Get whether I belong to this group or not */
SendMyGroupsOut->groupsArray.__ptr[NumRow].member = Grp_GetIfIBelongToGrp (GrpCod) ? 1 :
0;
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/*********** Copy data of a user from database to soap structure *************/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static void API_CopyUsrData (struct soap *soap,
struct swad__user *Usr,struct UsrData *UsrDat,
bool UsrIDIsVisible)
2014-12-01 23:55:08 +01:00
{
2017-03-07 01:56:41 +01:00
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
2016-07-26 12:48:52 +02:00
const char *FirstID;
2017-01-15 22:58:26 +01:00
size_t Length;
2014-12-01 23:55:08 +01:00
/* Copy user's code */
Usr->userCode = UsrDat->UsrCod;
/* Copy user's nickname */
2017-01-15 22:58:26 +01:00
Length = strlen (UsrDat->Nickname);
Usr->userNickname = soap_malloc (soap,Length + 1);
Str_Copy (Usr->userNickname,UsrDat->Nickname,Length);
2014-12-01 23:55:08 +01:00
2016-07-26 12:48:52 +02:00
/* Copy user's first ID */
2014-12-01 23:55:08 +01:00
if (UsrIDIsVisible && UsrDat->IDs.List)
2016-07-26 12:48:52 +02:00
FirstID = UsrDat->IDs.List[0].ID;
2014-12-01 23:55:08 +01:00
else // Hide user's ID
2016-07-26 12:48:52 +02:00
FirstID = "********";
2017-01-15 22:58:26 +01:00
Length = strlen (FirstID);
Usr->userID = soap_malloc (soap,Length + 1);
Str_Copy (Usr->userID,FirstID,Length);
2014-12-01 23:55:08 +01:00
/* Copy user's surname1 */
2017-01-15 22:58:26 +01:00
Length = strlen (UsrDat->Surname1);
Usr->userSurname1 = soap_malloc (soap,Length + 1);
Str_Copy (Usr->userSurname1,UsrDat->Surname1,Length);
2014-12-01 23:55:08 +01:00
/* Copy user's surname2 */
2017-01-15 22:58:26 +01:00
Length = strlen (UsrDat->Surname2);
Usr->userSurname2 = soap_malloc (soap,Length + 1);
Str_Copy (Usr->userSurname2,UsrDat->Surname2,Length);
2014-12-01 23:55:08 +01:00
/* Copy user's first name */
Length = strlen (UsrDat->FrstName);
Usr->userFirstname = soap_malloc (soap,Length + 1);
Str_Copy (Usr->userFirstname,UsrDat->FrstName,Length);
2014-12-01 23:55:08 +01:00
/* User's photo URL */
2016-07-08 12:43:48 +02:00
Pho_BuildLinkToPhoto (UsrDat,PhotoURL);
2017-01-15 22:58:26 +01:00
Length = strlen (PhotoURL);
Usr->userPhoto = soap_malloc (soap,Length + 1);
Str_Copy (Usr->userPhoto,PhotoURL,Length);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************** Return list of attendance events in a course **************/
/*****************************************************************************/
int swad__getAttendanceEvents (struct soap *soap,
char *wsKey,int courseCode, // input
struct swad__getAttendanceEventsOutput *getAttendanceEventsOut) // output
{
int ReturnCode;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2018-11-02 01:23:05 +01:00
unsigned NumRows;
2014-12-01 23:55:08 +01:00
int NumAttEvent;
long AttCod;
2017-03-07 01:56:41 +01:00
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
2014-12-01 23:55:08 +01:00
long StartTime;
long EndTime;
size_t Length;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getAttendanceEvents;
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Check if course code is correct *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Check if I am a teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must be a teacher");
/***** Query list of attendance events *****/
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get attendance events",
"SELECT AttCod," // row[0]
"Hidden," // row[1]
"UsrCod," // row[2]
"UNIX_TIMESTAMP(StartTime) AS ST," // row[3]
"UNIX_TIMESTAMP(EndTime) AS ET," // row[4]
"CommentTchVisible," // row[5]
"Title," // row[6]
"Txt" // row[7]
" FROM att_events"
" WHERE CrsCod=%d"
" ORDER BY ST DESC,"
"ET DESC,"
"Title DESC",
courseCode);
2018-11-02 01:23:05 +01:00
2014-12-01 23:55:08 +01:00
getAttendanceEventsOut->eventsArray.__size =
2018-11-02 01:23:05 +01:00
getAttendanceEventsOut->numEvents = (int) NumRows;
2014-12-01 23:55:08 +01:00
if (getAttendanceEventsOut->numEvents == 0)
getAttendanceEventsOut->eventsArray.__ptr = NULL;
else // Events found
{
2020-02-24 19:31:55 +01:00
getAttendanceEventsOut->eventsArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getAttendanceEventsOut->eventsArray.__size) *
sizeof (*(getAttendanceEventsOut->eventsArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumAttEvent = 0;
NumAttEvent < getAttendanceEventsOut->numEvents;
NumAttEvent++)
{
/* Get next group */
row = mysql_fetch_row (mysql_res);
/* Get attendance event code (row[0]) */
AttCod = Str_ConvertStrCodToLongCod (row[0]);
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].attendanceEventCode = (int) AttCod;
2016-09-07 18:02:25 +02:00
/* Get whether the attendance event is hidden or not (row[1]) */
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].hidden = (row[1][0] == 'Y') ? 1 :
0;
/* Get user's code of the user who created the event (row[2]) */
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[2]);
2019-05-16 14:02:06 +02:00
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Gbl.Hierarchy.Crs.CrsCod)) // Get some user's data from database
2014-12-01 23:55:08 +01:00
{
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
2019-12-06 11:53:14 +01:00
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname1 =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname1,
Gbl.Usrs.Other.UsrDat.Surname1,Length);
2014-12-01 23:55:08 +01:00
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
2019-12-06 11:53:14 +01:00
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname2 =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname2,
Gbl.Usrs.Other.UsrDat.Surname2,Length);
2014-12-01 23:55:08 +01:00
Length = strlen (Gbl.Usrs.Other.UsrDat.FrstName);
2019-12-06 11:53:14 +01:00
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userFirstname =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userFirstname,
Gbl.Usrs.Other.UsrDat.FrstName,Length);
2014-12-01 23:55:08 +01:00
2016-07-08 12:43:48 +02:00
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
2014-12-01 23:55:08 +01:00
Length = strlen (PhotoURL);
2019-12-06 11:53:14 +01:00
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userPhoto =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userPhoto,
PhotoURL,Length);
2014-12-01 23:55:08 +01:00
}
else
{
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname1 = NULL;
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname2 = NULL;
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userFirstname = NULL;
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userPhoto = NULL;
}
2016-09-07 18:02:25 +02:00
/* Get event start time (row[3]) */
2014-12-01 23:55:08 +01:00
StartTime = 0L;
2016-09-07 18:02:25 +02:00
if (row[3])
sscanf (row[3],"%ld",&StartTime);
2014-12-01 23:55:08 +01:00
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].startTime = StartTime;
2016-09-07 18:02:25 +02:00
/* Get event end time (row[4]) */
2014-12-01 23:55:08 +01:00
EndTime = 0L;
2016-09-07 18:02:25 +02:00
if (row[4])
sscanf (row[4],"%ld",&EndTime);
2014-12-01 23:55:08 +01:00
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].endTime = EndTime;
2016-09-07 18:02:25 +02:00
/* Get whether teachers comments are visible ('Y') or hidden ('N') (row[5]) */
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].commentsTeachersVisible = (row[5][0] == 'Y') ? 1 :
2014-12-01 23:55:08 +01:00
0;
2016-09-07 18:02:25 +02:00
/* Get title of the event (row[6]) */
Length = strlen (row[6]);
2019-12-06 11:53:14 +01:00
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].title =
soap_malloc (soap,Length + 1);
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].title,
row[6],Length);
2014-12-01 23:55:08 +01:00
2016-09-07 18:02:25 +02:00
/* Get Txt (row[7]) */
Length = strlen (row[7]);
2019-12-06 11:53:14 +01:00
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].text =
soap_malloc (soap,Length + 1);
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].text,
row[7],Length);
2014-12-01 23:55:08 +01:00
/* Get list of groups for this attendance event */
2020-02-24 19:31:55 +01:00
API_GetListGrpsInAttendanceEventFromDB (soap,
AttCod,
&(getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].groups));
2014-12-01 23:55:08 +01:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/**************** Get lists of groups of an attendance event *****************/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static void API_GetListGrpsInAttendanceEventFromDB (struct soap *soap,
long AttCod,char **ListGroups)
2014-12-01 23:55:08 +01:00
{
MYSQL_RES *mysql_res;
long NumGrps;
long NumGrp;
long GrpCod;
2019-11-08 01:10:32 +01:00
char GrpCodStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2017-01-16 01:51:01 +01:00
size_t Length;
2014-12-01 23:55:08 +01:00
/***** Get list of groups *****/
NumGrps = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get groups of an attendance event",
"SELECT GrpCod"
" FROM att_groups"
" WHERE AttCod=%ld",
AttCod);
2018-11-02 01:23:05 +01:00
if (NumGrps == 0)
2014-12-01 23:55:08 +01:00
*ListGroups = NULL;
else // Events found
{
2017-01-16 01:51:01 +01:00
Length = NumGrps * (10 + 1) - 1;
2020-02-24 19:31:55 +01:00
*ListGroups = soap_malloc (soap,Length + 1);
2017-01-17 16:39:38 +01:00
(*ListGroups)[0] = '\0';
2014-12-01 23:55:08 +01:00
for (NumGrp = 0;
NumGrp < NumGrps;
NumGrp++)
{
/* Get next group */
GrpCod = DB_GetNextCode (mysql_res);
snprintf (GrpCodStr,sizeof (GrpCodStr),NumGrp ? ",%ld" :
"%ld",
2018-10-18 02:02:32 +02:00
GrpCod);
Str_Concat (*ListGroups,GrpCodStr,Length);
2014-12-01 23:55:08 +01:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/****************** Send the data of an attendance event *********************/
/*****************************************************************************/
int swad__sendAttendanceEvent (struct soap *soap,
char *wsKey,int attendanceEventCode,int courseCode,int hidden,
int startTime,int endTime,int commentsTeachersVisible,
char *title,char *text,char *groups, // input
struct swad__sendAttendanceEventOutput *sendAttendanceEventOut) // output
{
int ReturnCode;
2020-04-06 16:00:06 +02:00
struct Att_Event Event;
2014-12-01 23:55:08 +01:00
bool ItsANewAttEvent;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_sendAttendanceEvent;
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Check if course code is correct *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Check if I am a teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must be a teacher");
/**** Get data of attendance event *****/
/* Event code */
2020-04-06 16:00:06 +02:00
Event.AttCod = (long) attendanceEventCode;
2014-12-01 23:55:08 +01:00
/* Course code */
2020-04-06 16:00:06 +02:00
if (Event.AttCod > 0) // The event already exists
2014-12-01 23:55:08 +01:00
{
2020-04-06 16:00:06 +02:00
Att_GetDataOfAttEventByCod (&Event);
if (Event.CrsCod != (long) courseCode)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Attendance event does not belong to course");
ItsANewAttEvent = false;
}
else
{
ItsANewAttEvent = true;
2020-04-06 16:00:06 +02:00
Event.CrsCod = (long) courseCode;
2014-12-01 23:55:08 +01:00
}
/* Is event hidden? */
2020-04-06 16:00:06 +02:00
Event.Hidden = (hidden ? true :
2014-12-01 23:55:08 +01:00
false);
/* User's code (really not used) */
2020-04-06 16:00:06 +02:00
Event.UsrCod = Gbl.Usrs.Me.UsrDat.UsrCod;
2014-12-01 23:55:08 +01:00
/* startTime and endTime */
Event.TimeUTC[Dat_STR_TIME] = (time_t) startTime;
Event.TimeUTC[Dat_END_TIME] = (time_t) endTime;
2014-12-01 23:55:08 +01:00
/* Are teacher's comments visible? */
2020-04-06 16:00:06 +02:00
Event.CommentTchVisible = (commentsTeachersVisible ? true :
2014-12-01 23:55:08 +01:00
false);
/* Title */
2016-09-07 18:02:25 +02:00
if (!title[0])
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-09-07 18:02:25 +02:00
"Request forbidden",
"Title of attendance event is empty");
Str_Copy (Event.Title,title,sizeof (Event.Title) - 1);
2014-12-01 23:55:08 +01:00
2016-06-29 18:27:49 +02:00
/* Create a list of groups selected */
2019-05-16 14:02:06 +02:00
API_GetLstGrpsSel (groups);
2016-06-29 18:27:49 +02:00
/***** Create or update attendance event *****/
if (ItsANewAttEvent)
2020-04-06 16:00:06 +02:00
Att_CreateAttEvent (&Event,text); // Add new attendance event to database
2016-06-29 18:27:49 +02:00
else
2020-04-06 16:00:06 +02:00
Att_UpdateAttEvent (&Event,text); // Modify existing attendance event
2016-06-29 18:27:49 +02:00
/***** Free memory for list of selected groups *****/
Grp_FreeListCodSelectedGrps ();
2020-04-06 16:00:06 +02:00
sendAttendanceEventOut->attendanceEventCode = Event.AttCod;
2016-06-29 18:27:49 +02:00
return SOAP_OK;
}
2016-09-06 18:29:13 +02:00
/*****************************************************************************/
/************************ Remove an attendance event *************************/
/*****************************************************************************/
int swad__removeAttendanceEvent (struct soap *soap,
char *wsKey,int attendanceEventCode, // input
2016-09-19 21:42:35 +02:00
struct swad__removeAttendanceEventOutput *removeAttendanceEventOut) // output
2016-09-06 18:29:13 +02:00
{
int ReturnCode;
2020-04-06 16:00:06 +02:00
struct Att_Event Event;
2016-09-06 18:29:13 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_removeAttendanceEvent;
2016-09-19 21:42:35 +02:00
removeAttendanceEventOut->attendanceEventCode = 0;
2016-09-06 18:29:13 +02:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2016-09-06 18:29:13 +02:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-09-06 18:29:13 +02:00
"Bad web service key",
"Web service key does not exist in database");
/**** Get data of attendance event *****/
/* Event code */
2020-04-06 16:00:06 +02:00
Event.AttCod = (long) attendanceEventCode;
2016-09-06 18:29:13 +02:00
/* Course code */
2020-04-06 16:00:06 +02:00
if (Event.AttCod > 0) // The event already exists
2016-09-06 18:29:13 +02:00
{
2020-04-06 16:00:06 +02:00
Att_GetDataOfAttEventByCod (&Event);
Gbl.Hierarchy.Crs.CrsCod = Event.CrsCod;
2016-09-06 18:29:13 +02:00
}
else
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-09-06 18:29:13 +02:00
"Request forbidden",
"Attendance event does not exist");
/***** Check if course code is correct *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2016-09-06 18:29:13 +02:00
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-09-06 18:29:13 +02:00
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2016-09-06 18:29:13 +02:00
/***** Check if I am a teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-09-06 18:29:13 +02:00
"Request forbidden",
"Requester must be a teacher");
/***** Remove the attendance event from database *****/
2020-04-06 16:00:06 +02:00
Att_RemoveAttEventFromDB (Event.AttCod);
2016-09-06 18:29:13 +02:00
2020-04-06 16:00:06 +02:00
removeAttendanceEventOut->attendanceEventCode = Event.AttCod;
2016-09-06 18:29:13 +02:00
return SOAP_OK;
}
2016-06-29 18:27:49 +02:00
/*****************************************************************************/
/********************** Create a list of groups selected *********************/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
static void API_GetLstGrpsSel (const char *Groups)
2016-06-29 18:27:49 +02:00
{
const char *Ptr;
2019-11-08 01:10:32 +01:00
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2016-06-29 18:27:49 +02:00
unsigned NumGrp;
2014-12-01 23:55:08 +01:00
/***** Count number of groups *****/
2016-06-29 18:27:49 +02:00
for (Ptr = Groups, NumGrp = 0;
2014-12-01 23:55:08 +01:00
*Ptr;
NumGrp++)
2019-11-08 01:10:32 +01:00
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.LstGrpsSel.NumGrps = NumGrp;
2014-12-01 23:55:08 +01:00
/***** Create a list of groups selected *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps)
2014-12-01 23:55:08 +01:00
{
// Here NestedCalls is always 0
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.LstGrpsSel.NestedCalls++;
2014-12-01 23:55:08 +01:00
// Here NestedCalls is always 1
if ((Gbl.Crs.Grps.LstGrpsSel.GrpCods = calloc (Gbl.Crs.Grps.LstGrpsSel.NumGrps,
sizeof (*Gbl.Crs.Grps.LstGrpsSel.GrpCods))) == NULL)
Err_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
2016-06-29 18:27:49 +02:00
for (Ptr = Groups, NumGrp = 0;
2014-12-01 23:55:08 +01:00
*Ptr;
)
{
2019-11-08 01:10:32 +01:00
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrp] = Str_ConvertStrCodToLongCod (LongStr);
if (Grp_DB_CheckIfGrpBelongsToCrs (Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrp],Gbl.Hierarchy.Crs.CrsCod))
2014-12-01 23:55:08 +01:00
NumGrp++;
}
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.LstGrpsSel.NumGrps = NumGrp; // Update number of groups
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/*********** Return a list with the users in an attendance event *************/
/*****************************************************************************/
int swad__getAttendanceUsers (struct soap *soap,
char *wsKey,int attendanceEventCode, // input
struct swad__getAttendanceUsersOutput *getAttendanceUsersOut) // output
{
int ReturnCode;
2020-04-06 16:00:06 +02:00
struct Att_Event Event;
2014-12-01 23:55:08 +01:00
char SubQuery[512];
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRow,NumRows;
2017-03-07 01:56:41 +01:00
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
2014-12-01 23:55:08 +01:00
size_t Length;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getAttendanceUsers;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get course of this attendance event *****/
2020-04-06 16:00:06 +02:00
Event.AttCod = (long) attendanceEventCode;
Att_GetDataOfAttEventByCod (&Event);
Gbl.Hierarchy.Crs.CrsCod = Event.CrsCod;
2014-12-01 23:55:08 +01:00
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Check if I am a teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must be a teacher");
/***** Query list of attendance users *****/
if (Grp_DB_CheckIfAssociatedToGrps ("att_groups","AttCod",Event.AttCod))
2014-12-01 23:55:08 +01:00
// Event for one or more groups
// Subquery: list of users in groups of this attendance event...
// ...who have no entry in attendance list of users
sprintf (SubQuery,"SELECT DISTINCT grp_users.UsrCod AS UsrCod," // row[0]
"'N' AS Present" // row[1]
" FROM att_groups,"
"grp_groups,"
"grp_types,"
"crs_users,"
"grp_users"
" WHERE att_groups.AttCod=%ld"
" AND att_groups.GrpCod=grp_groups.GrpCod"
" AND grp_groups.GrpTypCod=grp_types.GrpTypCod"
" AND grp_types.CrsCod=crs_users.CrsCod"
" AND crs_users.Role=%u"
" AND crs_users.UsrCod=grp_users.UsrCod"
" AND grp_users.GrpCod=att_groups.GrpCod"
" AND grp_users.UsrCod NOT IN"
" (SELECT UsrCod"
" FROM att_users"
" WHERE AttCod=%ld)",
2020-04-06 16:00:06 +02:00
Event.AttCod,
2017-05-18 19:13:41 +02:00
(unsigned) Rol_STD,
2020-04-06 16:00:06 +02:00
Event.AttCod);
2014-12-01 23:55:08 +01:00
else
// Event for the whole course
// Subquery: list of users in the course of this attendance event...
// ...who have no entry in attendance list of users
sprintf (SubQuery,"SELECT crs_users.UsrCod AS UsrCod," // row[0]
"'N' AS Present" // row[1]
" FROM att_events,"
"crs_users"
2017-03-24 01:09:27 +01:00
" WHERE att_events.AttCod=%ld"
" AND att_events.CrsCod=crs_users.CrsCod"
" AND crs_users.Role=%u"
" AND crs_users.UsrCod NOT IN"
" (SELECT UsrCod"
" FROM att_users"
" WHERE AttCod=%ld)",
2020-04-06 16:00:06 +02:00
Event.AttCod,
2017-05-18 19:13:41 +02:00
(unsigned) Rol_STD,
2020-04-06 16:00:06 +02:00
Event.AttCod);
2014-12-01 23:55:08 +01:00
// Query: list of users in attendance list + rest of users (subquery)
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get users in an attendance event",
"SELECT u.UsrCod," // row[0]
"u.Present" // row[1]
" FROM (SELECT UsrCod,"
"Present"
" FROM att_users"
" WHERE AttCod=%ld"
" UNION %s) AS u,"
"usr_data"
" WHERE u.UsrCod=usr_data.UsrCod"
" ORDER BY usr_data.Surname1,"
"usr_data.Surname2,"
"usr_data.FirstName",
(long) attendanceEventCode,
SubQuery);
2014-12-01 23:55:08 +01:00
getAttendanceUsersOut->numUsers = (int) NumRows;
getAttendanceUsersOut->usersArray.__size = (int) NumRows;
if (NumRows == 0)
getAttendanceUsersOut->usersArray.__ptr = NULL;
else // Events found
{
2020-02-24 19:31:55 +01:00
getAttendanceUsersOut->usersArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getAttendanceUsersOut->usersArray.__size) *
sizeof (*(getAttendanceUsersOut->usersArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next user */
row = mysql_fetch_row (mysql_res);
/* Get user's code (row[0]) */
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
getAttendanceUsersOut->usersArray.__ptr[NumRow].userCode = (int) Gbl.Usrs.Other.UsrDat.UsrCod;
/* Get user's data */
2019-05-16 14:02:06 +02:00
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,-1L)) // Get some user's data from database
2014-12-01 23:55:08 +01:00
{
Length = strlen (Gbl.Usrs.Other.UsrDat.Nickname);
2019-12-06 11:53:14 +01:00
getAttendanceUsersOut->usersArray.__ptr[NumRow].userNickname =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userNickname,
Gbl.Usrs.Other.UsrDat.Nickname,Length);
2014-12-01 23:55:08 +01:00
2016-07-24 12:17:03 +02:00
if (Gbl.Usrs.Other.UsrDat.IDs.Num)
{
Length = strlen (Gbl.Usrs.Other.UsrDat.IDs.List[0].ID); // TODO: What user's ID?
2019-12-06 11:53:14 +01:00
getAttendanceUsersOut->usersArray.__ptr[NumRow].userID =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userID,
Gbl.Usrs.Other.UsrDat.IDs.List[0].ID,Length);
2016-07-24 12:17:03 +02:00
}
else
{
2019-12-06 11:53:14 +01:00
getAttendanceUsersOut->usersArray.__ptr[NumRow].userID =
soap_malloc (soap,1);
2016-07-24 12:17:03 +02:00
getAttendanceUsersOut->usersArray.__ptr[NumRow].userID[0] = '\0';
}
2014-12-01 23:55:08 +01:00
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
2019-12-06 11:53:14 +01:00
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname1 =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname1,
Gbl.Usrs.Other.UsrDat.Surname1,Length);
2014-12-01 23:55:08 +01:00
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
2019-12-06 11:53:14 +01:00
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname2 =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname2,
Gbl.Usrs.Other.UsrDat.Surname2,Length);
2014-12-01 23:55:08 +01:00
Length = strlen (Gbl.Usrs.Other.UsrDat.FrstName);
2019-12-06 11:53:14 +01:00
getAttendanceUsersOut->usersArray.__ptr[NumRow].userFirstname =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userFirstname,
Gbl.Usrs.Other.UsrDat.FrstName,Length);
2014-12-01 23:55:08 +01:00
2016-07-08 12:43:48 +02:00
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
2014-12-01 23:55:08 +01:00
Length = strlen (PhotoURL);
2019-12-06 11:53:14 +01:00
getAttendanceUsersOut->usersArray.__ptr[NumRow].userPhoto =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userPhoto,
PhotoURL,Length);
2014-12-01 23:55:08 +01:00
}
else
{
getAttendanceUsersOut->usersArray.__ptr[NumRow].userNickname = NULL;
getAttendanceUsersOut->usersArray.__ptr[NumRow].userID = NULL;
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname1 = NULL;
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname2 = NULL;
getAttendanceUsersOut->usersArray.__ptr[NumRow].userFirstname = NULL;
getAttendanceUsersOut->usersArray.__ptr[NumRow].userPhoto = NULL;
}
/* Get if user is present or not (row[1]) */
getAttendanceUsersOut->usersArray.__ptr[NumRow].present = (row[1][0] == 'Y') ? 1 :
0;
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/************ Send a list with the users in an attendance event **************/
/*****************************************************************************/
int swad__sendAttendanceUsers (struct soap *soap,
char *wsKey,int attendanceEventCode,
char *users,int setOthersAsAbsent, // input
struct swad__sendAttendanceUsersOutput *sendAttendanceUsersOut) // output
{
int ReturnCode;
2020-04-06 16:00:06 +02:00
struct Att_Event Event;
2014-12-01 23:55:08 +01:00
const char *Ptr;
2019-11-08 01:10:32 +01:00
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2017-06-08 15:32:33 +02:00
struct UsrData UsrDat;
2014-12-01 23:55:08 +01:00
unsigned NumCodsInList;
2018-11-04 20:51:38 +01:00
char *SubQueryAllUsrs = NULL;
2019-11-08 01:10:32 +01:00
char SubQueryOneUsr[1 + Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2017-01-16 01:51:01 +01:00
size_t Length = 0; // Initialized to avoid warning
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_sendAttendanceUsers;
2014-12-01 23:55:08 +01:00
/***** Initialize output *****/
sendAttendanceUsersOut->success = 0;
sendAttendanceUsersOut->numUsers = 0;
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get course of this attendance event *****/
2020-04-06 16:00:06 +02:00
Event.AttCod = (long) attendanceEventCode;
if (!Att_GetDataOfAttEventByCod (&Event))
2014-12-01 23:55:08 +01:00
return SOAP_OK; // return with success = 0
2020-04-06 16:00:06 +02:00
Gbl.Hierarchy.Crs.CrsCod = Event.CrsCod;
2014-12-01 23:55:08 +01:00
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Check if I am a teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must be a teacher");
2017-06-08 15:32:33 +02:00
/***** Initialize structure with user's data *****/
Usr_UsrDataConstructor (&UsrDat);
2014-12-01 23:55:08 +01:00
if (setOthersAsAbsent)
{
/* Count number of codes in list */
for (Ptr = users, NumCodsInList = 0;
*Ptr;
NumCodsInList++)
/* Find next string in text until comma (leading and trailing spaces are removed) */
2019-11-08 01:10:32 +01:00
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2014-12-01 23:55:08 +01:00
2018-11-04 20:51:38 +01:00
/* Allocate subquery used to mark not present users as absent */
2019-11-08 01:10:32 +01:00
Length = 256 + NumCodsInList * (1 + Cns_MAX_DECIMAL_DIGITS_LONG + 1) - 1;
if ((SubQueryAllUsrs = malloc (Length + 1)) == NULL)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Not enough memory",
"Not enough memory to store list of users");
2018-11-04 20:51:38 +01:00
SubQueryAllUsrs[0] = '\0';
2014-12-01 23:55:08 +01:00
}
for (Ptr = users;
*Ptr;
)
{
/* Find next string in text until comma (leading and trailing spaces are removed) */
2019-11-08 01:10:32 +01:00
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2017-06-08 15:32:33 +02:00
if ((UsrDat.UsrCod = Str_ConvertStrCodToLongCod (LongStr)) > 0)
if (Usr_ChkIfUsrCodExists (UsrDat.UsrCod))
2014-12-01 23:55:08 +01:00
// The user must belong to course,
// but it's not necessary he/she belongs to groups associated to the event
2017-06-09 15:04:02 +02:00
if (Usr_CheckIfUsrBelongsToCurrentCrs (&UsrDat))
2014-12-01 23:55:08 +01:00
{
/* Mark user as present */
2020-04-06 16:00:06 +02:00
Att_RegUsrInAttEventNotChangingComments (Event.AttCod,UsrDat.UsrCod);
2014-12-01 23:55:08 +01:00
/* Add this user to query used to mark not present users as absent */
if (setOthersAsAbsent)
{
2018-11-04 20:51:38 +01:00
if (sendAttendanceUsersOut->numUsers)
{
snprintf (SubQueryOneUsr,sizeof (SubQueryOneUsr),",%ld",
UsrDat.UsrCod);
Str_Concat (SubQueryAllUsrs,SubQueryOneUsr,Length);
2018-11-04 20:51:38 +01:00
}
else
snprintf (SubQueryAllUsrs,Length," AND UsrCod NOT IN (%ld",
2018-11-04 20:51:38 +01:00
UsrDat.UsrCod);
2014-12-01 23:55:08 +01:00
}
sendAttendanceUsersOut->numUsers++;
}
}
if (setOthersAsAbsent)
{
/* Mark not present users as absent in table of users */
if (sendAttendanceUsersOut->numUsers)
Str_Concat (SubQueryAllUsrs,")",Length);
2014-12-01 23:55:08 +01:00
2018-11-04 20:51:38 +01:00
DB_QueryUPDATE ("can not set other users as absent",
"UPDATE att_users"
" SET Present='N'"
" WHERE AttCod=%ld"
"%s",
Event.AttCod,
SubQueryAllUsrs);
2014-12-01 23:55:08 +01:00
2018-11-04 21:28:11 +01:00
/* Free memory for subquery string */
2019-11-06 19:45:20 +01:00
free (SubQueryAllUsrs);
2018-11-04 21:28:11 +01:00
/* Clean attendance users table */
Att_DB_RemoveUsrsAbsentWithoutCommentsFromAttEvent (Event.AttCod);
2014-12-01 23:55:08 +01:00
}
2017-06-08 15:32:33 +02:00
/***** Free memory used for user's data *****/
Usr_UsrDataDestructor (&UsrDat);
2014-12-01 23:55:08 +01:00
sendAttendanceUsersOut->success = 1;
return SOAP_OK;
}
/*****************************************************************************/
/********************* Return notifications of a user ************************/
/*****************************************************************************/
int swad__getNotifications (struct soap *soap,
char *wsKey,long beginTime, // input
struct swad__getNotificationsOutput *getNotificationsOut) // output
{
extern const char *Ntf_WSNotifyEvents[Ntf_NUM_NOTIFY_EVENTS];
extern const char *Txt_Forum;
extern const char *Txt_Course;
extern const char *Txt_Degree;
extern const char *Txt_Center;
2014-12-01 23:55:08 +01:00
extern const char *Txt_Institution;
int ReturnCode;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2016-07-20 20:24:16 +02:00
unsigned NumNotifications;
unsigned NumNotif;
2014-12-01 23:55:08 +01:00
long NtfCod;
Ntf_NotifyEvent_t NotifyEvent;
long EventTime;
2017-03-07 01:56:41 +01:00
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
2021-02-11 23:27:48 +01:00
struct Hie_Hierarchy Hie;
2014-12-01 23:55:08 +01:00
long Cod;
2020-04-07 03:01:41 +02:00
struct For_Forum ForumSelected;
2017-01-13 10:49:56 +01:00
char ForumName[For_MAX_BYTES_FORUM_NAME + 1];
2017-03-08 14:12:33 +01:00
char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1];
2014-12-01 23:55:08 +01:00
char *ContentStr;
Ntf_Status_t Status;
2017-01-15 22:58:26 +01:00
size_t Length;
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getNotifications;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
2015-12-07 23:13:08 +01:00
/***** Get my language from database *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_GetMyLanguage (soap)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Get my notifications from database *****/
NumNotifications = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get user's notifications",
"SELECT NtfCod," // row[0]
"NotifyEvent," // row[1]
"UNIX_TIMESTAMP(TimeNotif)," // row[2]
"FromUsrCod," // row[3]
"InsCod," // row[4]
"CtrCod," // row[5]
"DegCod," // row[6]
"CrsCod," // row[7]
"Cod," // row[8]
"Status" // row[9]
" FROM ntf_notifications"
" WHERE ToUsrCod=%ld"
" AND TimeNotif>=FROM_UNIXTIME(%ld)"
" ORDER BY TimeNotif DESC",
Gbl.Usrs.Me.UsrDat.UsrCod,beginTime);
2018-11-02 01:23:05 +01:00
2016-07-20 20:24:16 +02:00
if (NumNotifications) // Notifications found
2014-12-01 23:55:08 +01:00
{
2016-07-20 20:24:16 +02:00
getNotificationsOut->numNotifications = (int) NumNotifications;
getNotificationsOut->notificationsArray.__size = (int) NumNotifications;
2020-02-24 19:31:55 +01:00
getNotificationsOut->notificationsArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getNotificationsOut->notificationsArray.__size) *
sizeof (*(getNotificationsOut->notificationsArray.__ptr)));
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
for (NumNotif = 0;
NumNotif < NumNotifications;
NumNotif++)
2014-12-01 23:55:08 +01:00
{
/* Get next notification */
row = mysql_fetch_row (mysql_res);
/* Get unique notification code (row[0]) */
NtfCod = Str_ConvertStrCodToLongCod (row[0]);
2016-07-20 20:24:16 +02:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].notifCode = (int) NtfCod;
2014-12-01 23:55:08 +01:00
/* Get notification event type (row[1]) */
NotifyEvent = Ntf_GetNotifyEventFromStr (row[1]);
2019-12-06 11:53:14 +01:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].eventType =
soap_malloc (soap,Ntf_MAX_BYTES_NOTIFY_EVENT + 1);
2017-01-15 18:02:52 +01:00
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].eventType,
Ntf_WSNotifyEvents[NotifyEvent],Ntf_MAX_BYTES_NOTIFY_EVENT);
2014-12-01 23:55:08 +01:00
/* Get time of the event (row[2]) */
EventTime = 0L;
if (row[2])
sscanf (row[2],"%ld",&EventTime);
2016-07-20 20:24:16 +02:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].eventTime = EventTime;
2014-12-01 23:55:08 +01:00
/* Get course (row[7]) */
2021-02-11 23:27:48 +01:00
Hie.Crs.CrsCod = Str_ConvertStrCodToLongCod (row[7]);
Crs_GetDataOfCourseByCod (&Hie.Crs);
2014-12-01 23:55:08 +01:00
/* Get user's code of the user who caused the event (row[3]) */
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[3]);
2016-07-20 20:24:16 +02:00
2021-02-11 23:27:48 +01:00
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Hie.Crs.CrsCod)) // Get some user's data from database
2014-12-01 23:55:08 +01:00
{
2019-12-06 11:53:14 +01:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].userNickname =
soap_malloc (soap,Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1);
2017-01-15 18:02:52 +01:00
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userNickname,
Gbl.Usrs.Other.UsrDat.Nickname,
Nck_MAX_BYTES_NICK_WITHOUT_ARROBA);
2014-12-01 23:55:08 +01:00
2019-12-06 11:53:14 +01:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].userSurname1 =
soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
2017-01-15 18:02:52 +01:00
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userSurname1,
2017-01-17 03:10:43 +01:00
Gbl.Usrs.Other.UsrDat.Surname1,
2017-03-07 19:55:29 +01:00
Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
2014-12-01 23:55:08 +01:00
2019-12-06 11:53:14 +01:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].userSurname2 =
soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
2017-01-15 18:02:52 +01:00
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userSurname2,
2017-01-17 03:10:43 +01:00
Gbl.Usrs.Other.UsrDat.Surname2,
2017-03-07 19:55:29 +01:00
Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
2014-12-01 23:55:08 +01:00
2019-12-06 11:53:14 +01:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].userFirstname =
soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
2017-01-15 18:02:52 +01:00
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userFirstname,
Gbl.Usrs.Other.UsrDat.FrstName,
2017-03-07 19:55:29 +01:00
Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
2014-12-01 23:55:08 +01:00
2016-07-08 12:43:48 +02:00
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
2019-12-06 11:53:14 +01:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].userPhoto =
soap_malloc (soap,Cns_MAX_BYTES_WWW + 1);
2017-01-15 18:02:52 +01:00
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userPhoto,
PhotoURL,Cns_MAX_BYTES_WWW);
2014-12-01 23:55:08 +01:00
}
else
{
2016-07-20 20:24:16 +02:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].userNickname = NULL;
getNotificationsOut->notificationsArray.__ptr[NumNotif].userSurname1 = NULL;
getNotificationsOut->notificationsArray.__ptr[NumNotif].userSurname2 = NULL;
getNotificationsOut->notificationsArray.__ptr[NumNotif].userFirstname = NULL;
getNotificationsOut->notificationsArray.__ptr[NumNotif].userPhoto = NULL;
2014-12-01 23:55:08 +01:00
}
/* Get institution (row[4]) */
2021-02-11 23:27:48 +01:00
Hie.Ins.InsCod = Str_ConvertStrCodToLongCod (row[4]);
Ins_GetDataOfInstitByCod (&Hie.Ins);
2014-12-01 23:55:08 +01:00
/* Get center (row[5]) */
2021-02-11 23:27:48 +01:00
Hie.Ctr.CtrCod = Str_ConvertStrCodToLongCod (row[5]);
Ctr_GetDataOfCenterByCod (&Hie.Ctr);
2014-12-01 23:55:08 +01:00
/* Get degree (row[6]) */
2021-02-11 23:27:48 +01:00
Hie.Deg.DegCod = Str_ConvertStrCodToLongCod (row[6]);
Deg_GetDataOfDegreeByCod (&Hie.Deg);
2014-12-01 23:55:08 +01:00
/* Get message/post/... code (row[8]) */
Cod = Str_ConvertStrCodToLongCod (row[8]);
2016-07-20 20:24:16 +02:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].eventCode = (int) Cod;
2014-12-01 23:55:08 +01:00
/* Set location */
2019-12-06 11:53:14 +01:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].location =
soap_malloc (soap,Ntf_MAX_BYTES_NOTIFY_LOCATION + 1);
2014-12-01 23:55:08 +01:00
if (NotifyEvent == Ntf_EVENT_FORUM_POST_COURSE ||
NotifyEvent == Ntf_EVENT_FORUM_REPLY)
{
2017-04-18 01:25:44 +02:00
For_GetForumTypeAndLocationOfAPost (Cod,&ForumSelected);
For_SetForumName (&ForumSelected,
2014-12-01 23:55:08 +01:00
ForumName,Gbl.Prefs.Language,false); // Set forum name in recipient's language
2016-07-20 20:24:16 +02:00
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
2014-12-01 23:55:08 +01:00
Txt_Forum,ForumName);
}
2021-02-11 23:27:48 +01:00
else if (Hie.Crs.CrsCod > 0)
2016-07-20 20:24:16 +02:00
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
2021-02-11 23:27:48 +01:00
Txt_Course,Hie.Crs.ShrtName);
else if (Hie.Deg.DegCod > 0)
2016-07-20 20:24:16 +02:00
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
2021-02-11 23:27:48 +01:00
Txt_Degree,Hie.Deg.ShrtName);
else if (Hie.Ctr.CtrCod > 0)
2016-07-20 20:24:16 +02:00
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
Txt_Center,Hie.Ctr.ShrtName);
2021-02-11 23:27:48 +01:00
else if (Hie.Ins.InsCod > 0)
2016-07-20 20:24:16 +02:00
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
2021-02-11 23:27:48 +01:00
Txt_Institution,Hie.Ins.ShrtName);
2014-12-01 23:55:08 +01:00
else
2017-01-17 03:10:43 +01:00
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"-",
2017-03-07 19:55:29 +01:00
Ntf_MAX_BYTES_NOTIFY_LOCATION);
2014-12-01 23:55:08 +01:00
/* Get status (row[9]) */
if (sscanf (row[9],"%u",&Status) != 1)
Status = (Ntf_Status_t) 0;
2016-07-20 20:24:16 +02:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].status = (int) Status;
2014-12-01 23:55:08 +01:00
/* Get summary and content */
ContentStr = NULL;
Ntf_GetNotifSummaryAndContent (SummaryStr,&ContentStr,NotifyEvent,
2021-02-11 23:27:48 +01:00
Cod,Hie.Crs.CrsCod,Gbl.Usrs.Me.UsrDat.UsrCod,
2017-03-06 13:01:16 +01:00
true);
2014-12-01 23:55:08 +01:00
2017-01-15 22:58:26 +01:00
Length = strlen (SummaryStr);
2019-12-06 11:53:14 +01:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].summary =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].summary,
SummaryStr,Length);
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
if (ContentStr == NULL)
2014-12-01 23:55:08 +01:00
{
2019-12-06 11:53:14 +01:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].content =
soap_malloc (soap,1);
2016-07-20 20:24:16 +02:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].content[0] = '\0';
2014-12-01 23:55:08 +01:00
}
else
{
2017-01-15 22:58:26 +01:00
Length = strlen (ContentStr);
2019-12-06 11:53:14 +01:00
getNotificationsOut->notificationsArray.__ptr[NumNotif].content =
soap_malloc (soap,Length + 1);
2017-01-15 22:58:26 +01:00
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].content,
ContentStr,Length);
2016-07-20 20:24:16 +02:00
/* Free memory used by content string */
2019-11-06 19:45:20 +01:00
free (ContentStr);
2016-07-20 20:24:16 +02:00
ContentStr = NULL;
2014-12-01 23:55:08 +01:00
}
}
2016-07-20 20:24:16 +02:00
}
else // No notifications found
{
getNotificationsOut->numNotifications = 0;
getNotificationsOut->notificationsArray.__size = 0;
getNotificationsOut->notificationsArray.__ptr = NULL;
2014-12-01 23:55:08 +01:00
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
2015-12-07 23:13:08 +01:00
/********************* Get my language from database *************************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static int API_GetMyLanguage (struct soap *soap)
2014-12-01 23:55:08 +01:00
{
2018-12-08 16:43:13 +01:00
extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES];
2014-12-01 23:55:08 +01:00
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2018-12-08 16:43:13 +01:00
Lan_Language_t Lan;
2014-12-01 23:55:08 +01:00
/***** Get user's language *****/
2018-11-02 01:23:05 +01:00
if (DB_QuerySELECT (&mysql_res,"can not get user's language",
"SELECT Language" // row[0]
" FROM usr_data"
2018-11-02 01:23:05 +01:00
" WHERE UsrCod=%ld",
Gbl.Usrs.Me.UsrDat.UsrCod) != 1)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Can not get user's language from database",
"User doen't exist in database");
/***** Get language from database *****/
row = mysql_fetch_row (mysql_res);
/* Get language (row[0]) */
2019-12-15 01:10:36 +01:00
Gbl.Prefs.Language = Lan_LANGUAGE_UNKNOWN;
for (Lan = (Lan_Language_t) 1;
Lan <= (Lan_Language_t) (Lan_NUM_LANGUAGES - 1);
2014-12-01 23:55:08 +01:00
Lan++)
2018-12-08 16:43:13 +01:00
if (!strcasecmp (row[0],Lan_STR_LANG_ID[Lan]))
2014-12-01 23:55:08 +01:00
{
Gbl.Prefs.Language = Lan;
break;
}
2018-12-08 16:43:13 +01:00
if (Gbl.Prefs.Language == Lan_LANGUAGE_UNKNOWN) // Language stored in database is unknown
2015-12-07 23:13:08 +01:00
Gbl.Prefs.Language = Cfg_DEFAULT_LANGUAGE;
2014-12-01 23:55:08 +01:00
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/************************* Send a notice to a course *************************/
/*****************************************************************************/
int swad__markNotificationsAsRead (struct soap *soap,
char *wsKey,char *notifications, // input
struct swad__markNotificationsAsReadOutput *markNotificationsAsReadOut) // output
{
int ReturnCode;
const char *Ptr;
2019-11-08 01:10:32 +01:00
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2014-12-01 23:55:08 +01:00
unsigned NumNtf;
unsigned NumNtfsMarkedAsRead = 0;
long NtfCod;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_markNotificationsAsRead;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
if (notifications[0])
{
/***** Mark notifications from list as read *****/
for (NumNtf = 0, Ptr = notifications;
*Ptr;
NumNtf++)
{
/* Find next string in text until comma (leading and trailing spaces are removed) */
2019-11-08 01:10:32 +01:00
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2014-12-01 23:55:08 +01:00
if ((NtfCod = Str_ConvertStrCodToLongCod (LongStr)) > 0)
{
/***** Mark notification as read in the database *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not mark notification as read",
"UPDATE ntf_notifications"
" SET Status=(Status | %u)"
" WHERE NtfCod=%ld"
" AND ToUsrCod=%ld",
2018-11-03 12:16:40 +01:00
(unsigned) Ntf_STATUS_BIT_READ,
(long) NtfCod,
Gbl.Usrs.Me.UsrDat.UsrCod);
2014-12-01 23:55:08 +01:00
NumNtfsMarkedAsRead++;
}
}
}
/***** Return notification code *****/
markNotificationsAsReadOut->numNotifications = (int) NumNtfsMarkedAsRead;
return SOAP_OK;
}
/*****************************************************************************/
/****************** Send a message to one or more users **********************/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
#define API_MAX_BYTES_QUERY_RECIPIENTS (10 * 1024 - 1)
2014-12-01 23:55:08 +01:00
int swad__sendMessage (struct soap *soap,
char *wsKey,int messageCode,char *to,char *subject,char *body, // input
struct swad__sendMessageOutput *sendMessageOut) // output
{
int ReturnCode;
long ReplyUsrCod = -1L;
char Nick[Nck_MAX_BYTES_NICK_WITH_ARROBA + 1];
2018-10-30 03:29:40 +01:00
char *Query = NULL;
2014-12-01 23:55:08 +01:00
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumUsrs;
unsigned NumUsr;
2014-12-01 23:55:08 +01:00
bool FirstNickname = true;
bool ThereAreNicknames = false;
const char *Ptr;
2018-10-10 23:56:42 +02:00
bool ItsMe;
2014-12-01 23:55:08 +01:00
bool NotifyByEmail;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_sendMessage;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Check if the message is a reply to a previous message *****/
if (messageCode)
{
/***** Check if the original message was really received by me *****/
if (DB_QuerySELECTUnsigned ("can not check original message",
"SELECT SUM(N)"
" FROM (SELECT COUNT(*) AS N"
" FROM msg_rcv"
" WHERE UsrCod=%ld"
" AND MsgCod=%ld"
" UNION"
" SELECT COUNT(*) AS N"
" FROM msg_rcv_deleted"
" WHERE UsrCod=%ld"
" AND MsgCod=%ld) AS T",
Gbl.Usrs.Me.UsrDat.UsrCod,(long) messageCode,
Gbl.Usrs.Me.UsrDat.UsrCod,(long) messageCode) == 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Can not send reply message",
"Original message does not exist");
/***** Get the recipient of the message *****/
ReplyUsrCod = DB_QuerySELECTCode ("can not check original message",
"SELECT UsrCod"
" FROM msg_snt"
" WHERE MsgCod=%ld"
" UNION "
"SELECT UsrCod"
" FROM msg_snt_deleted"
" WHERE MsgCod=%ld",
(long) messageCode,
(long) messageCode);
if (ReplyUsrCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Can not send reply message",
"Original message does not exist");
}
2018-10-29 22:22:02 +01:00
/***** Allocate space for query *****/
if ((Query = malloc (API_MAX_BYTES_QUERY_RECIPIENTS + 1)) == NULL)
Err_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
/***** Build query for recipients from database *****/
if (ReplyUsrCod > 0)
2019-05-16 14:02:06 +02:00
snprintf (Query,API_MAX_BYTES_QUERY_RECIPIENTS + 1,
"SELECT UsrCod"
" FROM usr_data"
" WHERE UsrCod=%ld",
ReplyUsrCod);
2014-12-01 23:55:08 +01:00
else
2018-10-30 02:37:09 +01:00
Query[0] = '\0';
2014-12-01 23:55:08 +01:00
/***** Loop over recipients' nicknames building query *****/
Ptr = to;
while (*Ptr)
{
/* Find next string in text until comma (leading and trailing spaces are removed) */
Str_GetNextStringUntilComma (&Ptr,Nick,sizeof (Nick) - 1); // With leading arrobas
2014-12-01 23:55:08 +01:00
/* Check if string is a valid nickname */
if (Nck_CheckIfNickWithArrIsValid (Nick)) // String is a nickname (with leading arrobas)?
2014-12-01 23:55:08 +01:00
{
Str_RemoveLeadingArrobas (Nick);
2014-12-01 23:55:08 +01:00
/* Check for overflow in query */
if (strlen (Query) + Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 32 >
2019-05-16 14:02:06 +02:00
API_MAX_BYTES_QUERY_RECIPIENTS)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Can not send message",
"Too many recipients");
/* Add this nickname to query */
if (FirstNickname)
{
if (ReplyUsrCod > 0)
Str_Concat (Query," UNION ",API_MAX_BYTES_QUERY_RECIPIENTS);
Str_Concat (Query,"SELECT UsrCod"
" FROM usr_nicknames"
2017-01-16 01:51:01 +01:00
" WHERE Nickname IN ('",
2019-05-16 14:02:06 +02:00
API_MAX_BYTES_QUERY_RECIPIENTS);
2014-12-01 23:55:08 +01:00
FirstNickname = false;
ThereAreNicknames = true;
}
else
Str_Concat (Query,",'",API_MAX_BYTES_QUERY_RECIPIENTS);
Str_Concat (Query,Nick,API_MAX_BYTES_QUERY_RECIPIENTS); // Leading arrobas already removed
Str_Concat (Query,"'",API_MAX_BYTES_QUERY_RECIPIENTS);
2014-12-01 23:55:08 +01:00
}
}
if (ThereAreNicknames)
Str_Concat (Query,")",API_MAX_BYTES_QUERY_RECIPIENTS);
2014-12-01 23:55:08 +01:00
/***** Initialize output structure *****/
sendMessageOut->numUsers = 0;
sendMessageOut->usersArray.__size = 0;
sendMessageOut->usersArray.__ptr = NULL;
if (ReplyUsrCod > 0 || ThereAreNicknames) // There are a recipient to reply or nicknames in "to"
{
/***** Get users *****/
NumUsrs = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get users",
"%s",
Query);
2014-12-01 23:55:08 +01:00
sendMessageOut->numUsers = (int) NumUsrs;
sendMessageOut->usersArray.__size = (int) NumUsrs;
2014-12-01 23:55:08 +01:00
if (NumUsrs) // Users found
2014-12-01 23:55:08 +01:00
{
2020-02-24 19:31:55 +01:00
sendMessageOut->usersArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(sendMessageOut->usersArray.__size) *
sizeof (*(sendMessageOut->usersArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumUsr = 0;
NumUsr < NumUsrs;
NumUsr++)
2014-12-01 23:55:08 +01:00
{
/* 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 recipient data */
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,
Usr_DONT_GET_PREFS,
Usr_DONT_GET_ROLE_IN_CURRENT_CRS))
2014-12-01 23:55:08 +01:00
{
2016-11-16 23:19:52 +01:00
/* This received message must be notified by email? */
2018-10-10 23:56:42 +02:00
ItsMe = Usr_ItsMe (Gbl.Usrs.Other.UsrDat.UsrCod);
NotifyByEmail = (!ItsMe &&
2019-03-19 13:22:14 +01:00
(Gbl.Usrs.Other.UsrDat.NtfEvents.SendEmail & (1 << Ntf_EVENT_MESSAGE)));
2014-12-01 23:55:08 +01:00
/* Send message to this user */
if ((ReturnCode = API_SendMessageToUsr ((long) messageCode,
Gbl.Usrs.Me.UsrDat.UsrCod,
ReplyUsrCod,
Gbl.Usrs.Other.UsrDat.UsrCod,
NotifyByEmail,
subject,
body)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
{
DB_FreeMySQLResult (&mysql_res);
return ReturnCode;
}
/* Copy user's data into output structure */
2020-02-24 19:31:55 +01:00
API_CopyUsrData (soap,
&(sendMessageOut->usersArray.__ptr[NumUsr]),
2020-02-24 19:31:55 +01:00
&Gbl.Usrs.Other.UsrDat,
false);
2014-12-01 23:55:08 +01:00
}
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
return SOAP_OK;
}
/*****************************************************************************/
/************************* Send a message to one user ************************/
/*****************************************************************************/
2016-09-19 21:30:37 +02:00
/*
2019-05-16 14:02:06 +02:00
API_SendMessageToUsr ((long) messageCode,
2016-09-19 21:30:37 +02:00
Gbl.Usrs.Me.UsrDat.UsrCod,ReplyUsrCod,Gbl.Usrs.Other.UsrDat.UsrCod,
NotifyByEmail,subject,body)) != SOAP_OK)
*/
2019-05-16 14:02:06 +02:00
static int API_SendMessageToUsr (long OriginalMsgCod,
2016-09-19 21:30:37 +02:00
long SenderUsrCod,long ReplyUsrCod,long RecipientUsrCod,
bool NotifyByEmail,
const char *Subject,const char *Content)
2014-12-01 23:55:08 +01:00
{
static bool MsgAlreadyInserted = false;
static long NewMsgCod;
/***** Create message *****/
if (!MsgAlreadyInserted) // The message is inserted only once in the table of messages sent
{
/***** Insert message subject and body in the database *****/
/* Get the code of the inserted item */
2018-11-03 01:45:36 +01:00
NewMsgCod =
DB_QueryINSERTandReturnCode ("can not create message",
"INSERT INTO msg_content"
2019-03-18 15:42:22 +01:00
" (Subject,Content,MedCod)"
2018-11-03 01:45:36 +01:00
" VALUES"
2019-03-18 15:42:22 +01:00
" ('%s','%s',-1)",
Subject,
Content);
2018-11-03 01:45:36 +01:00
/* Insert message in sent messages */
2018-11-02 19:37:11 +01:00
DB_QueryINSERT ("can not create message",
"INSERT INTO msg_snt"
" (MsgCod,CrsCod,UsrCod,Expanded,CreatTime)"
" VALUES"
" (%ld,-1,%ld,'N',NOW())",
NewMsgCod,
SenderUsrCod);
2014-12-01 23:55:08 +01:00
MsgAlreadyInserted = true;
}
/***** Insert message received in the database *****/
2018-11-02 19:37:11 +01:00
DB_QueryINSERT ("can not create received message",
"INSERT INTO msg_rcv"
" (MsgCod,UsrCod,Notified,Open,Replied,Expanded)"
" VALUES"
" (%ld,%ld,'%c','N','N','N')",
NewMsgCod,
RecipientUsrCod,
2018-11-02 19:37:11 +01:00
NotifyByEmail ? 'Y' :
'N');
2014-12-01 23:55:08 +01:00
/***** Create notification for this recipient.
2016-11-16 23:19:52 +01:00
If this recipient wants to receive notifications by email, activate the sending of a notification *****/
2018-11-02 19:37:11 +01:00
DB_QueryINSERT ("can not create new notification event",
"INSERT INTO ntf_notifications"
2018-11-02 19:37:11 +01:00
" (NotifyEvent,ToUsrCod,FromUsrCod,InsCod,DegCod,CrsCod,Cod,TimeNotif,Status)"
" VALUES"
" (%u,%ld,%ld,-1,-1,-1,%ld,NOW(),%u)",
(unsigned) Ntf_EVENT_MESSAGE,
RecipientUsrCod,
SenderUsrCod,
NewMsgCod,
(unsigned) (NotifyByEmail ? Ntf_STATUS_BIT_EMAIL :
0));
2014-12-01 23:55:08 +01:00
/***** If this recipient is the original sender of a message been replied... *****/
if (RecipientUsrCod == ReplyUsrCod)
/***** ...then update received message setting Replied field to true *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update a received message",
"UPDATE msg_rcv"
" SET Replied='Y'"
" WHERE MsgCod=%ld"
" AND UsrCod=%ld",
OriginalMsgCod,
SenderUsrCod);
2014-12-01 23:55:08 +01:00
return SOAP_OK;
}
/*****************************************************************************/
/************************* Send a notice to a course *************************/
/*****************************************************************************/
int swad__sendNotice (struct soap *soap,
char *wsKey,int courseCode,char *body, // input
struct swad__sendNoticeOutput *sendNoticeOut) // output
{
int ReturnCode;
long NotCod;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_sendNotice;
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Check course and group codes *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
-1L)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Get degree of current course *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Check if I am a teacher *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must be a teacher");
/***** Insert notice in the database *****/
/* Get the code of the inserted item */
2018-11-03 01:45:36 +01:00
NotCod =
DB_QueryINSERTandReturnCode ("can not create message",
"INSERT INTO not_notices"
2018-11-03 01:45:36 +01:00
" (CrsCod,UsrCod,CreatTime,Content,Status)"
" VALUES"
" (%ld,%ld,NOW(),'%s',%u)",
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Usrs.Me.UsrDat.UsrCod,
2018-11-03 01:45:36 +01:00
body,(unsigned) Not_ACTIVE_NOTICE);
2014-12-01 23:55:08 +01:00
/***** Create notifications *****/
// TODO: create notifications
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/***** Return notification code *****/
sendNoticeOut->noticeCode = (int) NotCod;
return SOAP_OK;
}
/*****************************************************************************/
/****************** Return test configuration in a course ********************/
/*****************************************************************************/
2020-05-07 18:33:26 +02:00
#define TstPrn_MAX_BYTES_FEEDBACK_TYPE 32
2020-02-17 12:27:28 +01:00
2014-12-01 23:55:08 +01:00
int swad__getTestConfig (struct soap *soap,
char *wsKey,int courseCode, // input
struct swad__getTestConfigOutput *getTestConfigOut) // output
{
int ReturnCode;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getTestConfig;
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Check if course code is correct *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad course code",
"Course code must be a integer greater than 0");
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to course");
/***** Get degree of current course *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Set default result to empty *****/
2020-02-17 12:00:39 +01:00
getTestConfigOut->numQuestions =
getTestConfigOut->minQuestions =
getTestConfigOut->defQuestions =
getTestConfigOut->maxQuestions = 0;
2020-04-02 03:28:08 +02:00
getTestConfigOut->visibility = TstVis_MIN_VISIBILITY;
2020-02-19 11:44:54 +01:00
/* TODO: Remove these lines in 2021 */
getTestConfigOut->feedback = soap_malloc (soap,TstPrn_MAX_BYTES_FEEDBACK_TYPE + 1);
2014-12-01 23:55:08 +01:00
getTestConfigOut->feedback[0] = '\0';
/***** Get test configuration *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_GetTstConfig ((long) courseCode)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
2020-03-21 15:41:25 +01:00
getTestConfigOut->pluggable = (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES) ? 1 :
2020-04-23 20:24:36 +02:00
0;
2020-03-21 15:41:25 +01:00
getTestConfigOut->minQuestions = (int) TstCfg_GetConfigMin ();
getTestConfigOut->defQuestions = (int) TstCfg_GetConfigDef ();
getTestConfigOut->maxQuestions = (int) TstCfg_GetConfigMax ();
getTestConfigOut->visibility = (int) TstCfg_GetConfigVisibility ();
2020-02-17 12:00:39 +01:00
/* Convert from visibility to old feedback */
/* TODO: Remove these lines in 2021 */
2020-04-02 03:28:08 +02:00
if (!TstVis_IsVisibleTotalScore (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback,"nothing",
2020-05-07 18:33:26 +02:00
TstPrn_MAX_BYTES_FEEDBACK_TYPE);
2020-04-02 03:28:08 +02:00
else if (!TstVis_IsVisibleEachQstScore (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback,"totalResult",
2020-05-07 18:33:26 +02:00
TstPrn_MAX_BYTES_FEEDBACK_TYPE);
2020-04-02 03:28:08 +02:00
else if (!TstVis_IsVisibleCorrectAns (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback,"eachResult",
2020-05-07 18:33:26 +02:00
TstPrn_MAX_BYTES_FEEDBACK_TYPE);
2020-04-02 03:28:08 +02:00
else if (!TstVis_IsVisibleFeedbackTxt (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback,"eachGoodBad",
2020-05-07 18:33:26 +02:00
TstPrn_MAX_BYTES_FEEDBACK_TYPE);
2020-02-17 12:00:39 +01:00
else
Str_Copy (getTestConfigOut->feedback,"fullFeedback",
2020-05-07 18:33:26 +02:00
TstPrn_MAX_BYTES_FEEDBACK_TYPE);
2014-12-01 23:55:08 +01:00
/***** Get number of tests *****/
2020-03-21 15:41:25 +01:00
if (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES &&
TstCfg_GetConfigMax () > 0)
getTestConfigOut->numQuestions = (int) API_GetNumTestQuestionsInCrs ((long) courseCode);
2014-12-01 23:55:08 +01:00
return SOAP_OK;
}
/*****************************************************************************/
/****** Get configuration of tests from database giving a course code ********/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
static int API_GetTstConfig (long CrsCod)
2014-12-01 23:55:08 +01:00
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
/***** Query database *****/
2018-11-02 01:23:05 +01:00
if (DB_QuerySELECT (&mysql_res,"can not get test configuration",
"SELECT Pluggable," // row[0]
"Min," // row[1]
"Def," // row[2]
"Max," // row[3]
"MinTimeNxtTstPerQst," // row[4]
"Visibility" // row[5]
" FROM tst_config"
" WHERE CrsCod=%ld",
2018-11-02 01:23:05 +01:00
CrsCod))
2014-12-01 23:55:08 +01:00
{
/***** Get minimun, default and maximum *****/
row = mysql_fetch_row (mysql_res);
2020-03-21 15:41:25 +01:00
TstCfg_GetConfigFromRow (row);
2014-12-01 23:55:08 +01:00
}
else // NumRows == 0
{
2020-03-21 15:41:25 +01:00
TstCfg_SetConfigPluggable (TstCfg_PLUGGABLE_UNKNOWN);
TstCfg_SetConfigMin (0);
TstCfg_SetConfigDef (0);
TstCfg_SetConfigMax (0);
2020-04-02 03:28:08 +02:00
TstCfg_SetConfigVisibility (TstVis_VISIBILITY_DEFAULT);
2014-12-01 23:55:08 +01:00
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/** Get number of visible test questions from database giving a course code **/
/*****************************************************************************/
static unsigned API_GetNumTestQuestionsInCrs (long CrsCod)
2014-12-01 23:55:08 +01:00
{
/***** Get number of questions *****/
// Reject questions with any tag hidden
// Select only questions with tags
return (unsigned)
DB_QueryCOUNT ("can not get number of test questions",
"SELECT COUNT(*)"
" FROM tst_questions,"
"tst_question_tags,"
"tst_tags"
" WHERE tst_questions.CrsCod=%ld"
" AND tst_questions.QstCod NOT IN"
" (SELECT tst_question_tags.QstCod"
" FROM tst_tags,"
"tst_question_tags"
" WHERE tst_tags.CrsCod=%ld"
" AND tst_tags.TagHidden='Y'"
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
" AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod"
" AND tst_tags.CrsCod=%ld",
CrsCod,
CrsCod,
CrsCod);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************* Return tests of a course **************************/
/*****************************************************************************/
int swad__getTests (struct soap *soap,
char *wsKey,int courseCode,long beginTime, // input
struct swad__getTestsOutput *getTestsOut) // output
{
int ReturnCode;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getTests;
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Check if course code is correct *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad course code",
"Course code must be a integer greater than 0");
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to course");
/***** Get degree of current course *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Set default result to empty *****/
getTestsOut->tagsArray.__size = 0;
getTestsOut->tagsArray.__ptr = NULL;
getTestsOut->questionsArray.__size = 0;
getTestsOut->questionsArray.__ptr = NULL;
getTestsOut->answersArray.__size = 0;
getTestsOut->answersArray.__ptr = NULL;
getTestsOut->questionTagsArray.__size = 0;
getTestsOut->questionTagsArray.__ptr = NULL;
/***** Get test configuration *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_GetTstConfig ((long) courseCode)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
2020-03-21 15:41:25 +01:00
if (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES)
2014-12-01 23:55:08 +01:00
{
/***** Get tags *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_GetTstTags (soap,
(long) courseCode,getTestsOut)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Get questions *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_GetTstQuestions (soap,
(long) courseCode,beginTime,getTestsOut)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Get answers *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_GetTstAnswers (soap,
(long) courseCode,beginTime,getTestsOut)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Get tags for each question *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_GetTstQuestionTags (soap,
(long) courseCode,beginTime,getTestsOut)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
}
return SOAP_OK;
}
/*****************************************************************************/
/**** Get test tags (only not hidden) from database giving a course code *****/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static int API_GetTstTags (struct soap *soap,
long CrsCod,struct swad__getTestsOutput *getTestsOut)
2014-12-01 23:55:08 +01:00
{
2018-12-08 16:43:13 +01:00
extern const char *Lan_STR_LANG_ID[1 + Lan_NUM_LANGUAGES];
2014-12-01 23:55:08 +01:00
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumTags;
unsigned NumTag;
2014-12-01 23:55:08 +01:00
/***** Get available tags from database *****/
NumTags = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get test tags",
"SELECT TagCod," // row[0]
"TagTxt" // row[1]
" FROM tst_tags"
" WHERE CrsCod=%ld"
" AND TagHidden='N'"
" ORDER BY TagTxt",
CrsCod);
getTestsOut->tagsArray.__size = (int) NumTags;
if (NumTags == 0)
2014-12-01 23:55:08 +01:00
getTestsOut->tagsArray.__ptr = NULL;
else // Tags found
{
2020-02-24 19:31:55 +01:00
getTestsOut->tagsArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getTestsOut->tagsArray.__size) *
sizeof (*(getTestsOut->tagsArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumTag = 0;
NumTag < NumTags;
NumTag++)
2014-12-01 23:55:08 +01:00
{
/* Get next tag */
row = mysql_fetch_row (mysql_res);
/* Get tag code (row[0]) */
getTestsOut->tagsArray.__ptr[NumTag].tagCode = (int) Str_ConvertStrCodToLongCod (row[0]);
2014-12-01 23:55:08 +01:00
/* Get tag text (row[1]) */
getTestsOut->tagsArray.__ptr[NumTag].tagText =
soap_malloc (soap,Tag_MAX_BYTES_TAG + 1);
Str_Copy (getTestsOut->tagsArray.__ptr[NumTag].tagText,row[1],
2020-05-17 17:11:04 +02:00
Tag_MAX_BYTES_TAG);
2014-12-01 23:55:08 +01:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/******* Get recent test questions from database giving a course code ********/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static int API_GetTstQuestions (struct soap *soap,
long CrsCod,long BeginTime,
struct swad__getTestsOutput *getTestsOut)
2014-12-01 23:55:08 +01:00
{
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
2014-12-01 23:55:08 +01:00
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2015-06-16 20:12:38 +02:00
unsigned NumRow;
unsigned NumRows;
Qst_AnswerType_t AnswerType;
2014-12-01 23:55:08 +01:00
/***** Get recent test questions from database *****/
// DISTINCTROW is necessary to not repeat questions
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get test questions",
"SELECT DISTINCTROW tst_questions.QstCod," // row[0]
"tst_questions.AnsType," // row[1]
"tst_questions.Shuffle," // row[2]
"tst_questions.Stem," // row[3]
"tst_questions.Feedback" // row[4]
" FROM tst_questions,"
"tst_question_tags,"
"tst_tags"
" WHERE tst_questions.CrsCod=%ld"
" AND tst_questions.QstCod NOT IN"
" (SELECT tst_question_tags.QstCod"
" FROM tst_tags,"
"tst_question_tags"
" WHERE tst_tags.CrsCod=%ld"
" AND tst_tags.TagHidden='Y'"
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
" AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod"
" AND tst_tags.CrsCod=%ld"
" AND (tst_questions.EditTime>=FROM_UNIXTIME(%ld)"
" OR "
"tst_tags.ChangeTime>=FROM_UNIXTIME(%ld))"
" ORDER BY QstCod",
CrsCod,
CrsCod,
CrsCod,
BeginTime,
BeginTime);
2014-12-01 23:55:08 +01:00
getTestsOut->questionsArray.__size = (int) NumRows;
if (NumRows == 0)
getTestsOut->questionsArray.__ptr = NULL;
else // Questions found
{
2020-02-24 19:31:55 +01:00
getTestsOut->questionsArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getTestsOut->questionsArray.__size) *
sizeof (*(getTestsOut->questionsArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next question */
row = mysql_fetch_row (mysql_res);
/* Get question code (row[0]) */
getTestsOut->questionsArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
/* Get answer type (row[1]) */
AnswerType = Qst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
2019-12-06 11:53:14 +01:00
getTestsOut->questionsArray.__ptr[NumRow].answerType =
soap_malloc (soap,Tst_MAX_BYTES_ANSWER_TYPE + 1);
2017-01-15 18:02:52 +01:00
Str_Copy (getTestsOut->questionsArray.__ptr[NumRow].answerType,
2017-01-17 03:10:43 +01:00
Tst_StrAnswerTypesXML[AnswerType],
2017-03-08 03:48:23 +01:00
Tst_MAX_BYTES_ANSWER_TYPE);
2014-12-01 23:55:08 +01:00
/* Get shuffle (row[2]) */
getTestsOut->questionsArray.__ptr[NumRow].shuffle = (row[2][0] == 'Y') ? 1 :
0;
/* Get question stem (row[3]) */
2019-12-06 11:53:14 +01:00
getTestsOut->questionsArray.__ptr[NumRow].stem =
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
2017-01-15 18:02:52 +01:00
Str_Copy (getTestsOut->questionsArray.__ptr[NumRow].stem,row[3],
Cns_MAX_BYTES_TEXT);
2014-12-01 23:55:08 +01:00
2015-06-16 20:12:38 +02:00
/* Get question feedback (row[4]) */
2019-12-06 11:53:14 +01:00
getTestsOut->questionsArray.__ptr[NumRow].feedback =
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
2017-01-15 18:02:52 +01:00
Str_Copy (getTestsOut->questionsArray.__ptr[NumRow].feedback,row[4],
Cns_MAX_BYTES_TEXT);
2014-12-01 23:55:08 +01:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/** Get answers of recent test questions from database giving a course code **/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static int API_GetTstAnswers (struct soap *soap,
long CrsCod,long BeginTime,
struct swad__getTestsOutput *getTestsOut)
2014-12-01 23:55:08 +01:00
{
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
2014-12-01 23:55:08 +01:00
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRow,NumRows;
unsigned Index;
/***** Get recent test questions from database *****/
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get test answers",
"SELECT QstCod," // row[0]
"AnsInd," // row[1]
"Correct," // row[2]
"Answer," // row[3]
"Feedback" // row[4]
" FROM tst_answers"
" WHERE QstCod IN "
"(SELECT tst_questions.QstCod"
" FROM tst_questions,"
"tst_question_tags,"
"tst_tags"
" WHERE tst_questions.CrsCod=%ld"
" AND tst_questions.QstCod NOT IN"
" (SELECT tst_question_tags.QstCod"
" FROM tst_tags,"
"tst_question_tags"
" WHERE tst_tags.CrsCod=%ld"
" AND tst_tags.TagHidden='Y'"
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
" AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod"
" AND tst_tags.CrsCod=%ld"
" AND (tst_questions.EditTime>=FROM_UNIXTIME(%ld)"
" OR "
"tst_tags.ChangeTime>=FROM_UNIXTIME(%ld)))"
" ORDER BY QstCod,"
"AnsInd",
CrsCod,
CrsCod,
CrsCod,
BeginTime,
BeginTime);
2014-12-01 23:55:08 +01:00
getTestsOut->answersArray.__size = (int) NumRows;
if (NumRows == 0)
getTestsOut->answersArray.__ptr = NULL;
else // Answers found
{
2020-02-24 19:31:55 +01:00
getTestsOut->answersArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getTestsOut->answersArray.__size) *
sizeof (*(getTestsOut->answersArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next question */
row = mysql_fetch_row (mysql_res);
/* Get question code (row[0]) */
getTestsOut->answersArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
/* Get answer index (row[1]) */
if (sscanf (row[1],"%u",&Index) == 1)
getTestsOut->answersArray.__ptr[NumRow].answerIndex = (int) Index;
else
getTestsOut->answersArray.__ptr[NumRow].answerIndex = 0; // error
/* Get correct (row[2]) */
getTestsOut->answersArray.__ptr[NumRow].correct = (row[2][0] == 'Y') ? 1 :
0;
/* Get answer (row[3]) */
2019-12-06 11:53:14 +01:00
getTestsOut->answersArray.__ptr[NumRow].answerText =
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
Str_Copy (getTestsOut->answersArray.__ptr[NumRow].answerText,
row[3],Cns_MAX_BYTES_TEXT);
2014-12-01 23:55:08 +01:00
/* Get feedback (row[4]) */
2019-12-06 11:53:14 +01:00
getTestsOut->answersArray.__ptr[NumRow].answerFeedback =
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
Str_Copy (getTestsOut->answersArray.__ptr[NumRow].answerFeedback,
row[4],Cns_MAX_BYTES_TEXT);
2014-12-01 23:55:08 +01:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/*** Get tags of recent test questions from database giving a course code ****/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static int API_GetTstQuestionTags (struct soap *soap,
long CrsCod,long BeginTime,
struct swad__getTestsOutput *getTestsOut)
2014-12-01 23:55:08 +01:00
{
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
2014-12-01 23:55:08 +01:00
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRow,NumRows;
unsigned Index;
/***** Get recent test questions from database *****/
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get test question tags",
"SELECT QstCod," // row[0]
"TagCod," // row[1]
"TagInd" // row[2]
" FROM tst_question_tags"
" WHERE QstCod IN "
"(SELECT tst_questions.QstCod"
" FROM tst_questions,"
"tst_question_tags,"
"tst_tags"
" WHERE tst_questions.CrsCod=%ld"
" AND tst_questions.QstCod NOT IN"
" (SELECT tst_question_tags.QstCod"
" FROM tst_tags,"
"tst_question_tags"
" WHERE tst_tags.CrsCod=%ld"
" AND tst_tags.TagHidden='Y'"
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
" AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod"
" AND tst_tags.CrsCod=%ld"
" AND (tst_questions.EditTime>=FROM_UNIXTIME(%ld)"
" OR "
"tst_tags.ChangeTime>=FROM_UNIXTIME(%ld)))"
" ORDER BY QstCod,"
"TagInd",
CrsCod,
CrsCod,
CrsCod,
BeginTime,
BeginTime);
2014-12-01 23:55:08 +01:00
getTestsOut->questionTagsArray.__size = (int) NumRows;
if (NumRows == 0)
getTestsOut->questionTagsArray.__ptr = NULL;
else // Answers found
{
2020-02-24 19:31:55 +01:00
getTestsOut->questionTagsArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getTestsOut->questionTagsArray.__size) *
sizeof (*(getTestsOut->questionTagsArray.__ptr)));
2014-12-01 23:55:08 +01:00
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next question */
row = mysql_fetch_row (mysql_res);
/* Get question code (row[0]) */
getTestsOut->questionTagsArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
/* Get tag code (row[1]) */
getTestsOut->questionTagsArray.__ptr[NumRow].tagCode = (int) Str_ConvertStrCodToLongCod (row[1]);
/* Get tag index (row[2]) */
if (sscanf (row[2],"%u",&Index) == 1)
getTestsOut->questionTagsArray.__ptr[NumRow].tagIndex = (int) Index;
else
getTestsOut->questionTagsArray.__ptr[NumRow].tagIndex = 0; // error
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
2015-06-16 20:12:38 +02:00
/*****************************************************************************/
/***************** Return one test question for Trivial game *****************/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
#define API_MAX_BYTES_DEGREES_STR (1024 - 1)
2017-01-16 01:51:01 +01:00
2015-06-16 20:12:38 +02:00
int swad__getTrivialQuestion (struct soap *soap,
char *wsKey,char *degrees,float lowerScore,float upperScore, // input
struct swad__getTrivialQuestionOutput *getTrivialQuestionOut) // output
{
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
2015-06-16 20:12:38 +02:00
int ReturnCode;
const char *Ptr;
2019-11-08 01:10:32 +01:00
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2019-05-16 14:02:06 +02:00
char DegreesStr[API_MAX_BYTES_DEGREES_STR + 1];
2019-11-08 01:10:32 +01:00
char DegStr[ 1 + 1 + Cns_MAX_DECIMAL_DIGITS_LONG + 1 + 1];
2017-01-28 15:58:46 +01:00
// DegStr=", ' - number ' \0"
2015-06-16 20:12:38 +02:00
long DegCod;
bool FirstDegree = true;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRow;
unsigned NumRows;
long QstCod = -1L;
Qst_AnswerType_t AnswerType;
2015-06-16 20:12:38 +02:00
unsigned Index;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getTrivialQuestion;
2015-06-16 20:12:38 +02:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2015-06-16 20:12:38 +02:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2015-06-16 20:12:38 +02:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2015-06-16 20:12:38 +02:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2015-06-16 20:12:38 +02:00
/***** Loop over recipients' nicknames building query *****/
DegreesStr[0] = '\0';
Ptr = degrees;
while (*Ptr)
{
/* Find next string in text until comma (leading and trailing spaces are removed) */
2019-11-08 01:10:32 +01:00
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2015-06-16 20:12:38 +02:00
/* Check if degree code from string is a valid code */
if (sscanf (LongStr,"%ld",&DegCod) == 1) // Degree code
if (DegCod > 0)
{
/* Add this degree to query */
if (FirstDegree)
{
snprintf (DegreesStr,sizeof (DegreesStr),"%ld",DegCod);
2015-06-16 20:12:38 +02:00
FirstDegree = false;
}
else
2015-06-23 19:33:13 +02:00
{
snprintf (DegStr,sizeof (DegStr),",%ld",DegCod);
Str_Concat (DegreesStr,DegStr,sizeof (DegreesStr) - 1);
2015-06-23 19:33:13 +02:00
}
2015-06-16 20:12:38 +02:00
}
}
if (!DegreesStr[0]) // Degrees not found
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2015-06-16 20:12:38 +02:00
"Bad list of degrees codes",
"Degrees codes must be integers greater than 0 separated by commas");
/***** Check lowerScore and upperScore *****/
if (lowerScore < -1.0 || lowerScore > 1.0 ||
upperScore < -1.0 || upperScore > 1.0 ||
upperScore < lowerScore)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2015-06-16 20:12:38 +02:00
"Bad score interval",
"lowerScore or upperScore values not valid");
/***** Get test questions *****/
2016-06-04 14:21:01 +02:00
Str_SetDecimalPointToUS (); // To print the floating point as a dot
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get test questions",
"SELECT DISTINCTROW "
"tst_questions.QstCod," // row[0]
"tst_questions.AnsType," // row[1]
"tst_questions.Shuffle," // row[2]
"tst_questions.Stem," // row[3]
"tst_questions.Feedback," // row[4]
"tst_questions.Score/tst_questions.NumHits AS S" // row[5]
" FROM crs_courses,"
"tst_questions"
" WHERE crs_courses.DegCod IN (%s)"
" AND crs_courses.CrsCod=tst_questions.CrsCod"
" AND tst_questions.AnsType='unique_choice'"
" AND tst_questions.NumHits>0"
" AND tst_questions.QstCod NOT IN"
" (SELECT tst_question_tags.QstCod"
" FROM crs_courses,"
"tst_tags,"
"tst_question_tags"
" WHERE crs_courses.DegCod IN (%s)"
" AND crs_courses.CrsCod=tst_tags.CrsCod"
" AND tst_tags.TagHidden='Y'"
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
" HAVING S>='%f'"
" AND S<='%f'"
" ORDER BY RAND()"
" LIMIT 1",
DegreesStr,
DegreesStr,
lowerScore,
upperScore);
2016-06-04 14:21:01 +02:00
Str_SetDecimalPointToLocal (); // Return to local system
2015-06-16 20:12:38 +02:00
if (NumRows == 1) // Question found
{
/* Get next question */
row = mysql_fetch_row (mysql_res);
/* Get question code (row[0]) */
QstCod = Str_ConvertStrCodToLongCod (row[0]);
getTrivialQuestionOut->question.questionCode = (int) QstCod;
/* Get answer type (row[1]) */
AnswerType = Qst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
2019-12-06 11:53:14 +01:00
getTrivialQuestionOut->question.answerType =
soap_malloc (soap,Tst_MAX_BYTES_ANSWER_TYPE + 1);
2017-01-15 18:02:52 +01:00
Str_Copy (getTrivialQuestionOut->question.answerType,
Tst_StrAnswerTypesXML[AnswerType],Tst_MAX_BYTES_ANSWER_TYPE);
2015-06-16 20:12:38 +02:00
/* Get shuffle (row[2]) */
getTrivialQuestionOut->question.shuffle = (row[2][0] == 'Y') ? 1 :
0;
/* Get question stem (row[3]) */
2019-12-06 11:53:14 +01:00
getTrivialQuestionOut->question.stem =
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
Str_Copy (getTrivialQuestionOut->question.stem,row[3],Cns_MAX_BYTES_TEXT);
2015-06-16 20:12:38 +02:00
/* Get question feedback (row[4]) */
2019-12-06 11:53:14 +01:00
getTrivialQuestionOut->question.feedback =
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
Str_Copy (getTrivialQuestionOut->question.feedback,row[4],Cns_MAX_BYTES_TEXT);
2015-06-16 20:12:38 +02:00
}
else // Empty question
{
/* Question code (row[0]) */
QstCod = -1L;
getTrivialQuestionOut->question.questionCode = -1;
/* Answer type (row[1]) */
getTrivialQuestionOut->question.answerType = soap_malloc (soap,1);
2015-06-16 20:12:38 +02:00
getTrivialQuestionOut->question.answerType[0] = '\0';
/* Shuffle (row[2]) */
getTrivialQuestionOut->question.shuffle = 0;
/* Question stem (row[3]) */
getTrivialQuestionOut->question.stem = soap_malloc (soap,1);
2015-06-16 20:12:38 +02:00
getTrivialQuestionOut->question.stem[0] = '\0';
/* Get question feedback (row[4]) */
getTrivialQuestionOut->question.feedback = soap_malloc (soap,1);
2015-06-16 20:12:38 +02:00
getTrivialQuestionOut->question.feedback[0] = '\0';
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
if (QstCod > 0)
{
/***** Get answer from database *****/
NumRows = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get test answers",
"SELECT QstCod," // row[0]
"AnsInd," // row[1]
"Correct," // row[2]
"Answer," // row[3]
"Feedback" // row[4]
" FROM tst_answers"
" WHERE QstCod=%ld"
" ORDER BY AnsInd",
QstCod);
2015-06-16 20:12:38 +02:00
getTrivialQuestionOut->answersArray.__size = (int) NumRows;
if (NumRows == 0)
getTrivialQuestionOut->answersArray.__ptr = NULL;
else // Answers found
{
2020-02-24 19:31:55 +01:00
getTrivialQuestionOut->answersArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getTrivialQuestionOut->answersArray.__size) *
sizeof (*(getTrivialQuestionOut->answersArray.__ptr)));
2015-06-16 20:12:38 +02:00
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next question */
row = mysql_fetch_row (mysql_res);
/* Get question code (row[0]) */
getTrivialQuestionOut->answersArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
/* Get answer index (row[1]) */
if (sscanf (row[1],"%u",&Index) == 1)
getTrivialQuestionOut->answersArray.__ptr[NumRow].answerIndex = (int) Index;
else
getTrivialQuestionOut->answersArray.__ptr[NumRow].answerIndex = 0; // error
/* Get correct (row[2]) */
getTrivialQuestionOut->answersArray.__ptr[NumRow].correct = (row[2][0] == 'Y') ? 1 :
0;
/* Get answer (row[3]) */
2019-12-06 11:53:14 +01:00
getTrivialQuestionOut->answersArray.__ptr[NumRow].answerText =
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
Str_Copy (getTrivialQuestionOut->answersArray.__ptr[NumRow].answerText,
row[3],Cns_MAX_BYTES_TEXT);
2015-06-16 20:12:38 +02:00
/* Get feedback (row[4]) */
2019-12-06 11:53:14 +01:00
getTrivialQuestionOut->answersArray.__ptr[NumRow].answerFeedback =
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
Str_Copy (getTrivialQuestionOut->answersArray.__ptr[NumRow].answerFeedback,
row[4],Cns_MAX_BYTES_TEXT);
2015-06-16 20:12:38 +02:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
return SOAP_OK;
}
2019-05-16 14:02:06 +02:00
/*****************************************************************************/
/*********************** Return list of games in a course ********************/
/*****************************************************************************/
int swad__getGames (struct soap *soap,
char *wsKey,int courseCode, // input
struct swad__getGamesOutput *getGamesOut) // output
{
int ReturnCode;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumGames;
2019-05-16 14:02:06 +02:00
int NumGame;
long GamCod;
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
long StartTime;
long EndTime;
size_t Length;
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getGames;
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
/***** Check web service key *****/
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-05-16 14:02:06 +02:00
"Bad web service key",
"Web service key does not exist in database");
/***** Check if course code is correct *****/
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2019-05-16 14:02:06 +02:00
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-05-16 14:02:06 +02:00
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2019-05-16 14:02:06 +02:00
2019-12-06 11:53:14 +01:00
/***** Check if I am logged as student in the course *****/
if (Gbl.Usrs.Me.Role.Logged != Rol_STD)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-12-06 11:53:14 +01:00
"Request forbidden",
"Requester must be a student in the course");
2019-05-16 14:02:06 +02:00
/***** Query list of games *****/
NumGames = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get games",
"SELECT gam_games.GamCod," // row[0]
"gam_games.UsrCod," // row[1]
"UNIX_TIMESTAMP(MIN(mch_matches.StartTime)) AS StartTime," // row[2]
"UNIX_TIMESTAMP(MAX(mch_matches.EndTime)) AS EndTime," // row[3]
"gam_games.MaxGrade," // row[4]
"gam_games.Visibility," // row[5]
"gam_games.Title," // row[6]
"gam_games.Txt" // row[7]
" FROM gam_games"
" LEFT JOIN mch_matches"
" ON gam_games.GamCod=mch_matches.GamCod"
" WHERE gam_games.CrsCod=%ld"
" AND Hidden='N'"
" GROUP BY gam_games.GamCod"
" ORDER BY StartTime DESC,"
"EndTime DESC,"
"gam_games.Title DESC",
Gbl.Hierarchy.Crs.CrsCod);
2019-05-16 14:02:06 +02:00
getGamesOut->gamesArray.__size =
getGamesOut->numGames = (int) NumGames;
2019-05-16 14:02:06 +02:00
if (getGamesOut->numGames == 0)
getGamesOut->gamesArray.__ptr = NULL;
2019-12-01 21:34:50 +01:00
else // Games found
2019-05-16 14:02:06 +02:00
{
2020-02-24 19:31:55 +01:00
getGamesOut->gamesArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getGamesOut->gamesArray.__size) *
sizeof (*(getGamesOut->gamesArray.__ptr)));
2019-05-16 14:02:06 +02:00
for (NumGame = 0;
NumGame < getGamesOut->numGames;
NumGame++)
{
2019-12-01 21:34:50 +01:00
/* Get next game */
2019-05-16 14:02:06 +02:00
row = mysql_fetch_row (mysql_res);
/* Get game code (row[0]) */
GamCod = Str_ConvertStrCodToLongCod (row[0]);
getGamesOut->gamesArray.__ptr[NumGame].gameCode = (int) GamCod;
/* Get user's code of the user who created the game (row[1]) */
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[1]);
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Gbl.Hierarchy.Crs.CrsCod)) // Get some user's data from database
{
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
2019-12-06 11:53:14 +01:00
getGamesOut->gamesArray.__ptr[NumGame].userSurname1 =
soap_malloc (soap,Length + 1);
2019-05-16 14:02:06 +02:00
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].userSurname1,
Gbl.Usrs.Other.UsrDat.Surname1,Length);
2019-05-16 14:02:06 +02:00
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
2019-12-06 11:53:14 +01:00
getGamesOut->gamesArray.__ptr[NumGame].userSurname2 =
soap_malloc (soap,Length + 1);
2019-05-16 14:02:06 +02:00
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].userSurname2,
Gbl.Usrs.Other.UsrDat.Surname2,Length);
2019-05-16 14:02:06 +02:00
Length = strlen (Gbl.Usrs.Other.UsrDat.FrstName);
2019-12-06 11:53:14 +01:00
getGamesOut->gamesArray.__ptr[NumGame].userFirstname =
soap_malloc (soap,Length + 1);
2019-05-16 14:02:06 +02:00
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].userFirstname,
Gbl.Usrs.Other.UsrDat.FrstName,Length);
2019-05-16 14:02:06 +02:00
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
Length = strlen (PhotoURL);
2019-12-06 11:53:14 +01:00
getGamesOut->gamesArray.__ptr[NumGame].userPhoto =
soap_malloc (soap,Length + 1);
2019-05-16 14:02:06 +02:00
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].userPhoto,
PhotoURL,Length);
2019-05-16 14:02:06 +02:00
}
else
{
getGamesOut->gamesArray.__ptr[NumGame].userSurname1 = NULL;
getGamesOut->gamesArray.__ptr[NumGame].userSurname2 = NULL;
getGamesOut->gamesArray.__ptr[NumGame].userFirstname = NULL;
getGamesOut->gamesArray.__ptr[NumGame].userPhoto = NULL;
}
/* Get game start time (row[2]) */
StartTime = 0L;
if (row[2])
sscanf (row[2],"%ld",&StartTime);
getGamesOut->gamesArray.__ptr[NumGame].startTime = StartTime;
/* Get game end time (row[3]) */
EndTime = 0L;
if (row[3])
sscanf (row[3],"%ld",&EndTime);
getGamesOut->gamesArray.__ptr[NumGame].endTime = EndTime;
2019-12-01 21:34:50 +01:00
/* Get maximum grade (row[4]) */
getGamesOut->gamesArray.__ptr[NumGame].maxGrade = Str_GetDoubleFromStr (row[4]);
if (getGamesOut->gamesArray.__ptr[NumGame].maxGrade < 0.0) // Only positive values allowed
getGamesOut->gamesArray.__ptr[NumGame].maxGrade = 0.0;
2020-02-18 15:40:04 +01:00
/* Get visibility (row[5]) */
2020-04-02 03:28:08 +02:00
getGamesOut->gamesArray.__ptr[NumGame].visibility = TstVis_GetVisibilityFromStr (row[5]);
2020-02-18 15:40:04 +01:00
/* Get title of the game (row[6]) */
Length = strlen (row[6]);
2019-12-06 11:53:14 +01:00
getGamesOut->gamesArray.__ptr[NumGame].title =
soap_malloc (soap,Length + 1);
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].title,row[6],Length);
2019-05-16 14:02:06 +02:00
2020-02-18 15:40:04 +01:00
/* Get Txt (row[7]) */
Length = strlen (row[7]);
2019-12-06 11:53:14 +01:00
getGamesOut->gamesArray.__ptr[NumGame].text =
soap_malloc (soap,Length + 1);
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].text,row[7],Length);
2019-12-01 21:34:50 +01:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/********************** Return list of matches in a game *********************/
/*****************************************************************************/
int swad__getMatches (struct soap *soap,
2020-08-18 11:37:02 +02:00
char *wsKey,int courseCode,int gameCode, // input
2019-12-01 21:34:50 +01:00
struct swad__getMatchesOutput *getMatchesOut) // output
{
int ReturnCode;
2020-04-08 03:06:45 +02:00
struct Gam_Game Game;
2019-12-01 21:34:50 +01:00
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumMatches;
2019-12-01 21:34:50 +01:00
int NumMatch;
long MchCod;
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
long StartTime;
long EndTime;
size_t Length;
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-12-01 21:34:50 +01:00
Gbl.WebService.Function = API_getMatches;
2020-08-18 11:37:02 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2019-12-01 21:34:50 +01:00
/***** Check web service key *****/
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-12-01 21:34:50 +01:00
"Bad web service key",
"Web service key does not exist in database");
2020-08-18 11:37:02 +02:00
/***** Check if course code is correct *****/
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
return soap_sender_fault (soap,
"Bad course code",
"Course code must be a integer greater than 0");
2020-04-23 23:09:28 +02:00
/***** Reset game *****/
Gam_ResetGame (&Game);
2019-12-01 21:34:50 +01:00
/***** Get game data from database *****/
Game.GamCod = (long) gameCode;
if (Game.GamCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2019-12-01 21:34:50 +01:00
"Bad game code",
"Game code must be a integer greater than 0");
Gam_GetDataOfGameByCod (&Game);
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-12-01 21:34:50 +01:00
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2019-12-01 21:34:50 +01:00
2019-12-06 11:53:14 +01:00
/***** Check if I am logged as student in the course *****/
if (Gbl.Usrs.Me.Role.Logged != Rol_STD)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-12-06 11:53:14 +01:00
"Request forbidden",
"Requester must be a student in the course");
2019-12-01 21:34:50 +01:00
/***** Query list of matches *****/
NumMatches = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get matches",
"SELECT MchCod," // row[ 0]
"UsrCod," // row[ 1]
"UNIX_TIMESTAMP(StartTime)," // row[ 2]
"UNIX_TIMESTAMP(EndTime)," // row[ 3]
"Title," // row[ 4]
"QstInd" // row[ 5]
" FROM mch_matches"
" WHERE GamCod=%ld"
" AND (MchCod NOT IN"
" (SELECT MchCod FROM mch_groups)"
" OR"
" MchCod IN"
" (SELECT mch_groups.MchCod"
" FROM mch_groups,"
"grp_users"
" WHERE grp_users.UsrCod=%ld"
" AND mch_groups.GrpCod=grp_users.GrpCod))"
" ORDER BY MchCod",
Game.GamCod,
Gbl.Usrs.Me.UsrDat.UsrCod);
2019-12-01 21:34:50 +01:00
getMatchesOut->matchesArray.__size =
getMatchesOut->numMatches = (int) NumMatches;
2019-12-01 21:34:50 +01:00
if (getMatchesOut->numMatches == 0)
getMatchesOut->matchesArray.__ptr = NULL;
else // Matches found
{
2020-02-24 19:31:55 +01:00
getMatchesOut->matchesArray.__ptr = soap_malloc (soap,
2019-12-06 11:53:14 +01:00
(getMatchesOut->matchesArray.__size) *
sizeof (*(getMatchesOut->matchesArray.__ptr)));
2019-12-01 21:34:50 +01:00
for (NumMatch = 0;
NumMatch < getMatchesOut->numMatches;
NumMatch++)
{
/* Get next game */
row = mysql_fetch_row (mysql_res);
/* Get match code (row[0]) */
MchCod = Str_ConvertStrCodToLongCod (row[0]);
getMatchesOut->matchesArray.__ptr[NumMatch].matchCode = (int) MchCod;
/* Get user's code of the user who created the game (row[1]) */
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[1]);
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Gbl.Hierarchy.Crs.CrsCod)) // Get some user's data from database
{
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
2019-12-06 11:53:14 +01:00
getMatchesOut->matchesArray.__ptr[NumMatch].userSurname1 =
soap_malloc (soap,Length + 1);
2019-12-01 21:34:50 +01:00
Str_Copy (getMatchesOut->matchesArray.__ptr[NumMatch].userSurname1,
Gbl.Usrs.Other.UsrDat.Surname1,Length);
2019-12-01 21:34:50 +01:00
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
2019-12-06 11:53:14 +01:00
getMatchesOut->matchesArray.__ptr[NumMatch].userSurname2 =
soap_malloc (soap,Length + 1);
2019-12-01 21:34:50 +01:00
Str_Copy (getMatchesOut->matchesArray.__ptr[NumMatch].userSurname2,
Gbl.Usrs.Other.UsrDat.Surname2,Length);
2019-12-01 21:34:50 +01:00
Length = strlen (Gbl.Usrs.Other.UsrDat.FrstName);
2019-12-06 11:53:14 +01:00
getMatchesOut->matchesArray.__ptr[NumMatch].userFirstname =
soap_malloc (soap,Length + 1);
2019-12-01 21:34:50 +01:00
Str_Copy (getMatchesOut->matchesArray.__ptr[NumMatch].userFirstname,
Gbl.Usrs.Other.UsrDat.FrstName,Length);
2019-12-01 21:34:50 +01:00
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
Length = strlen (PhotoURL);
2019-12-06 11:53:14 +01:00
getMatchesOut->matchesArray.__ptr[NumMatch].userPhoto =
soap_malloc (soap,Length + 1);
2019-12-01 21:34:50 +01:00
Str_Copy (getMatchesOut->matchesArray.__ptr[NumMatch].userPhoto,
PhotoURL,Length);
2019-12-01 21:34:50 +01:00
}
else
{
getMatchesOut->matchesArray.__ptr[NumMatch].userSurname1 = NULL;
getMatchesOut->matchesArray.__ptr[NumMatch].userSurname2 = NULL;
getMatchesOut->matchesArray.__ptr[NumMatch].userFirstname = NULL;
getMatchesOut->matchesArray.__ptr[NumMatch].userPhoto = NULL;
}
/* Get match start time (row[2]) */
StartTime = 0L;
if (row[2])
sscanf (row[2],"%ld",&StartTime);
getMatchesOut->matchesArray.__ptr[NumMatch].startTime = StartTime;
/* Get match end time (row[3]) */
EndTime = 0L;
if (row[3])
sscanf (row[3],"%ld",&EndTime);
getMatchesOut->matchesArray.__ptr[NumMatch].endTime = EndTime;
/* Get title of the match (row[4]) */
Length = strlen (row[4]);
2019-12-06 11:53:14 +01:00
getMatchesOut->matchesArray.__ptr[NumMatch].title =
soap_malloc (soap,Length + 1);
2019-12-01 21:34:50 +01:00
Str_Copy (getMatchesOut->matchesArray.__ptr[NumMatch].title,row[4],
2019-05-16 14:02:06 +02:00
Length);
2019-12-01 21:34:50 +01:00
/* Get current question index (row[5]) */
2020-02-27 00:19:55 +01:00
getMatchesOut->matchesArray.__ptr[NumMatch].questionIndex = (int) Str_ConvertStrToUnsigned (row[5]);
2019-12-01 21:34:50 +01:00
/* Get list of groups for this match */
2020-02-24 19:31:55 +01:00
API_GetListGrpsInGameFromDB (soap,
MchCod,&(getMatchesOut->matchesArray.__ptr[NumMatch].groups));
2019-05-16 14:02:06 +02:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
2019-12-04 22:22:42 +01:00
/*********** Get match status to be refreshed in student's screen ************/
2019-12-01 21:34:50 +01:00
/*****************************************************************************/
2019-12-04 22:22:42 +01:00
int swad__getMatchStatus (struct soap *soap,
2020-08-18 11:37:02 +02:00
char *wsKey,int courseCode,int gameCode,int matchCode, // input
struct swad__getMatchStatusOutput *getMatchStatusOut) // output
2019-12-01 21:34:50 +01:00
{
int ReturnCode;
2020-04-08 03:06:45 +02:00
struct Gam_Game Game;
2020-04-23 23:09:28 +02:00
struct Mch_Match Match;
2019-12-02 09:57:17 +01:00
bool ICanPlayThisMatchBasedOnGrps;
2019-12-04 22:22:42 +01:00
struct Mch_UsrAnswer UsrAnswer;
2019-12-01 21:34:50 +01:00
2020-08-18 11:37:02 +02:00
/***** Reset game and match *****/
Gam_ResetGame (&Game);
Mch_ResetMatch (&Match);
2019-12-01 21:34:50 +01:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-12-04 22:22:42 +01:00
Gbl.WebService.Function = API_getMatchStatus;
2020-08-18 11:37:02 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
Game.GamCod = (long) gameCode;
Match.MchCod = (long) matchCode;
2019-12-01 21:34:50 +01:00
2020-08-26 12:06:25 +02:00
/***** Default output *****/
getMatchStatusOut->matchCode = -1;
getMatchStatusOut->questionIndex = -1;
getMatchStatusOut->numAnswers = -1;
getMatchStatusOut->answerIndex = -1;
2019-12-01 21:34:50 +01:00
/***** Check web service key *****/
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-12-01 21:34:50 +01:00
"Bad web service key",
"Web service key does not exist in database");
2020-08-18 11:37:02 +02:00
/***** Check if course code is correct *****/
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2020-08-18 11:37:02 +02:00
"Bad course code",
"Course code must be a integer greater than 0");
2019-12-02 09:57:17 +01:00
/***** Get game data from database *****/
if (Game.GamCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2019-12-02 09:57:17 +01:00
"Bad game code",
"Game code must be a integer greater than 0");
Gam_GetDataOfGameByCod (&Game);
2020-08-18 11:37:02 +02:00
/***** Get match data from database *****/
if (Match.MchCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2020-08-18 11:37:02 +02:00
"Bad match code",
"Match code must be a integer greater than 0");
Mch_GetDataOfMatchByCod (&Match);
/* Check that match belongs to game */
if (Match.GamCod != Game.GamCod)
return soap_sender_fault (soap,
"Bad game code",
2020-08-22 13:05:15 +02:00
"Match does not belong to game");
2019-12-02 09:57:17 +01:00
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-12-02 09:57:17 +01:00
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2019-12-02 09:57:17 +01:00
2019-12-06 11:53:14 +01:00
/***** Check if I am logged as student in the course *****/
if (Gbl.Usrs.Me.Role.Logged != Rol_STD)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-12-06 11:53:14 +01:00
"Request forbidden",
"Requester must be a student in the course");
2019-12-02 09:57:17 +01:00
/***** Can I play this match? *****/
2019-12-05 19:54:28 +01:00
ICanPlayThisMatchBasedOnGrps = Mch_CheckIfICanPlayThisMatchBasedOnGrps (&Match);
2019-12-02 09:57:17 +01:00
if (!ICanPlayThisMatchBasedOnGrps)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-12-02 09:57:17 +01:00
"Request forbidden",
"Requester can not join this match");
2020-08-28 14:45:30 +02:00
/***** Set default match code *****/
2019-12-10 21:52:22 +01:00
getMatchStatusOut->matchCode = 0; // == 0 ==> wait
2020-08-28 14:45:30 +02:00
/***** Set index of question inside the game *****/
getMatchStatusOut->questionIndex = (int) Match.Status.QstInd;
2019-12-10 21:52:22 +01:00
if (Match.Status.Playing && // Match is being played
Match.Status.Showing != Mch_END) // Unfinished
2020-08-28 14:45:30 +02:00
/***** Join match *****/
2019-12-04 22:22:42 +01:00
/* Update players */
2020-08-26 12:06:25 +02:00
if (Mch_RegisterMeAsPlayerInMatch (&Match))
if (Match.Status.Showing == Mch_ANSWERS) // Showing the question stem and the answers
getMatchStatusOut->matchCode = (int) Match.MchCod; // > 0 ==> student is allowed to answer the question
2019-12-04 22:22:42 +01:00
2020-08-28 14:45:30 +02:00
/***** Set number of answers (options) in question and student's answer (<0 ==> no answer) *****/
switch (Match.Status.Showing)
2019-12-02 09:57:17 +01:00
{
2020-08-28 14:45:30 +02:00
case Mch_START: // Start: don't show anything
case Mch_END: // End: don't show anything
getMatchStatusOut->numAnswers = 0;
getMatchStatusOut->answerIndex = -1;
break;
case Mch_STEM: // Showing only the question stem
case Mch_ANSWERS: // Showing the question stem and the answers
case Mch_RESULTS: // Showing the results
getMatchStatusOut->numAnswers = (int) Qst_GetNumAnswersQst (Match.Status.QstCod);
2020-08-28 14:45:30 +02:00
Mch_GetQstAnsFromDB (Match.MchCod,
Gbl.Usrs.Me.UsrDat.UsrCod,
Match.Status.QstInd,
&UsrAnswer);
getMatchStatusOut->answerIndex = UsrAnswer.NumOpt;
break;
2019-12-02 09:57:17 +01:00
}
2019-12-01 21:34:50 +01:00
return SOAP_OK;
}
/*****************************************************************************/
/************* Send an answer to the current question in a match *************/
/*****************************************************************************/
int swad__answerMatchQuestion (struct soap *soap,
2020-08-18 11:37:02 +02:00
char *wsKey,int courseCode,int gameCode,int matchCode,int questionIndex,int numOption, // input
struct swad__answerMatchQuestionOutput *answerMatchQuestionOut) // output
2019-12-01 21:34:50 +01:00
{
int ReturnCode;
// unsigned NumOpt;
2020-08-18 11:37:02 +02:00
struct Gam_Game Game;
struct Mch_Match Match;
2020-08-22 13:05:15 +02:00
unsigned QstInd; // 0 means that the game has not started. First question has index 1.
struct Mch_UsrAnswer UsrAnswer;
2020-08-18 11:37:02 +02:00
/***** Reset game and match *****/
Gam_ResetGame (&Game);
Mch_ResetMatch (&Match);
2019-12-01 21:34:50 +01:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-12-01 21:34:50 +01:00
Gbl.WebService.Function = API_answerMatchQuestion;
2020-08-18 11:37:02 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
2020-08-22 13:05:15 +02:00
Game.GamCod = (long) gameCode;
2020-08-18 11:37:02 +02:00
Match.MchCod = (long) matchCode;
2019-12-01 21:34:50 +01:00
2020-08-22 13:05:15 +02:00
/***** Set default output *****/
2020-08-29 19:24:23 +02:00
/* <= 0 on error
> 0 on sucess */
2020-08-22 13:05:15 +02:00
answerMatchQuestionOut->matchCode = -1;
2019-12-01 21:34:50 +01:00
/***** Check web service key *****/
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-12-01 21:34:50 +01:00
"Bad web service key",
"Web service key does not exist in database");
2020-08-18 11:37:02 +02:00
/***** Check if course code is correct *****/
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
return soap_sender_fault (soap,
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get game data from database *****/
if (Game.GamCod <= 0)
return soap_sender_fault (soap,
"Bad game code",
"Game code must be a integer greater than 0");
Gam_GetDataOfGameByCod (&Game);
/***** Get match data from database *****/
if (Match.MchCod <= 0)
return soap_sender_fault (soap,
"Bad match code",
"Match code must be a integer greater than 0");
Mch_GetDataOfMatchByCod (&Match);
2020-08-22 13:05:15 +02:00
/***** Check that match belongs to game *****/
2020-08-18 11:37:02 +02:00
if (Match.GamCod != Game.GamCod)
return soap_sender_fault (soap,
"Bad game code",
2020-08-22 13:05:15 +02:00
"Match does not belong to game");
2020-08-18 11:37:02 +02:00
2020-08-22 13:05:15 +02:00
/***** Check question index *****/
if (questionIndex <= 0)
return soap_sender_fault (soap,
"Bad question index",
"The question index should be greater than 0");
QstInd = (unsigned) questionIndex;
/***** Check number of option selected by student *****/
if (numOption < 0)
2020-08-26 12:06:25 +02:00
/***** Remove my answer to this question *****/
Mch_RemoveMyQuestionAnswer (&Match,QstInd);
else
{
/***** Store answer *****/
UsrAnswer.NumOpt = (unsigned) numOption;
Mch_StoreQuestionAnswer (&Match,QstInd,&UsrAnswer);
}
2019-12-01 21:34:50 +01:00
2020-08-29 19:24:23 +02:00
/***** Set success output *****/
answerMatchQuestionOut->matchCode = Match.MchCod;
2019-12-01 21:34:50 +01:00
return SOAP_OK;
}
/*****************************************************************************/
/*********************** Get lists of groups of a match **********************/
/*****************************************************************************/
2020-02-24 19:31:55 +01:00
static void API_GetListGrpsInGameFromDB (struct soap *soap,
long MchCod,char **ListGroups)
2019-05-16 14:02:06 +02:00
{
MYSQL_RES *mysql_res;
long NumGrps;
long NumGrp;
long GrpCod;
2019-11-08 01:10:32 +01:00
char GrpCodStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2019-05-16 14:02:06 +02:00
size_t Length;
/***** Get list of groups *****/
NumGrps = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get groups of a match",
"SELECT GrpCod"
" FROM mch_groups"
" WHERE MchCod=%ld",
MchCod);
2019-05-16 14:02:06 +02:00
if (NumGrps == 0)
*ListGroups = NULL;
2019-12-01 21:34:50 +01:00
else // Groups found
2019-05-16 14:02:06 +02:00
{
Length = NumGrps * (10 + 1) - 1;
2020-02-24 19:31:55 +01:00
*ListGroups = soap_malloc (soap,Length + 1);
2019-05-16 14:02:06 +02:00
(*ListGroups)[0] = '\0';
for (NumGrp = 0;
NumGrp < NumGrps;
NumGrp++)
{
/* Get next group */
GrpCod = DB_GetNextCode (mysql_res);
snprintf (GrpCodStr,sizeof (GrpCodStr),NumGrp ? ",%ld" :
"%ld",
2019-05-16 14:02:06 +02:00
GrpCod);
Str_Concat (*ListGroups,GrpCodStr,Length);
2019-05-16 14:02:06 +02:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/*************** Get a directory tree in a course or a group *****************/
/*****************************************************************************/
// TODO: should treeCode be a string with one of the followins values?
// documents
// shared
// marks
int swad__getDirectoryTree (struct soap *soap,
char *wsKey,int courseCode,int groupCode,int treeCode, // input
struct swad__getDirectoryTreeOutput *getDirectoryTreeOut) // output
{
extern const char *Brw_RootFolderInternalNames[Brw_NUM_TYPES_FILE_BROWSER];
int ReturnCode;
2017-01-28 15:58:46 +01:00
char XMLFileName[PATH_MAX + 1];
2014-12-01 23:55:08 +01:00
unsigned long FileSize;
unsigned long NumBytesRead;
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getDirectoryTree;
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (long) courseCode;
Gbl.Crs.Grps.GrpCod = (long) groupCode;
2014-12-01 23:55:08 +01:00
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Check course and group codes *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Crs.Grps.GrpCod)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to course");
/***** Check if I belong to course/group *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpCod > 0)
if (!Grp_GetIfIBelongToGrp (Gbl.Crs.Grps.GrpCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to group");
/***** Check if tree code is correct *****/
if (treeCode <= 0 || treeCode > 3)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad tree code",
"Tree code must be 1 (documents), 2 (shared files) or 3 (marks)");
/***** Return directory tree *****/
/* Get directory tree into XML file */
if (courseCode > 0)
{
if (groupCode > 0)
switch (treeCode)
{
case 1: // Documents
2017-10-08 00:51:49 +02:00
Gbl.FileBrowser.Type = Brw_SHOW_DOC_GRP;
2014-12-01 23:55:08 +01:00
break;
case 2: // Shared files
2017-10-08 00:51:49 +02:00
Gbl.FileBrowser.Type = Brw_ADMI_SHR_GRP;
2014-12-01 23:55:08 +01:00
break;
case 3: // Marks
2017-10-08 00:51:49 +02:00
Gbl.FileBrowser.Type = Brw_SHOW_MRK_GRP;
2014-12-01 23:55:08 +01:00
break;
}
else // groupCode <= 0
switch (treeCode)
{
case 1: // Documents
2017-10-08 00:51:49 +02:00
Gbl.FileBrowser.Type = Brw_SHOW_DOC_CRS;
2014-12-01 23:55:08 +01:00
break;
case 2: // Shared files
2017-10-08 00:51:49 +02:00
Gbl.FileBrowser.Type = Brw_ADMI_SHR_CRS;
2014-12-01 23:55:08 +01:00
break;
case 3: // Marks
2017-10-08 00:51:49 +02:00
Gbl.FileBrowser.Type = Brw_SHOW_MRK_CRS;
2014-12-01 23:55:08 +01:00
break;
}
}
else
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad course code",
"Course code must be a integer greater than 0");
/* Initialize path to private directory */
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod = (courseCode > 0) ? (long) courseCode :
2020-04-10 19:14:08 +02:00
-1L;
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpCod = (groupCode > 0) ? (long) groupCode :
2020-04-10 19:14:08 +02:00
-1L;
2014-12-01 23:55:08 +01:00
snprintf (Gbl.Crs.PathPriv,sizeof (Gbl.Crs.PathPriv),"%s/%ld",
2019-04-04 10:45:15 +02:00
Cfg_PATH_CRS_PRIVATE,Gbl.Hierarchy.Crs.CrsCod);
2014-12-01 23:55:08 +01:00
Brw_InitializeFileBrowser ();
2019-04-25 14:39:51 +02:00
Str_Copy (Gbl.FileBrowser.FilFolLnk.Path,Brw_RootFolderInternalNames[Gbl.FileBrowser.Type],
sizeof (Gbl.FileBrowser.FilFolLnk.Path) - 1);
2019-04-25 14:39:51 +02:00
Str_Copy (Gbl.FileBrowser.FilFolLnk.Name,".",
sizeof (Gbl.FileBrowser.FilFolLnk.Name) - 1);
2019-04-25 14:39:51 +02:00
Brw_SetFullPathInTree ();
2014-12-01 23:55:08 +01:00
2014-12-21 14:47:04 +01:00
/* Check if exists the directory for HTML output. If not exists, create it */
2019-03-20 01:36:36 +01:00
Fil_CreateDirIfNotExists (Cfg_PATH_OUT_PRIVATE);
2014-12-01 23:55:08 +01:00
/* Create a unique name for the file */
snprintf (XMLFileName,sizeof (XMLFileName),"%s/%s.xml",
2019-03-20 01:36:36 +01:00
Cfg_PATH_OUT_PRIVATE,Gbl.UniqueNameEncrypted);
2014-12-01 23:55:08 +01:00
/* Open file for writing and reading */
if ((Gbl.F.XML = fopen (XMLFileName,"w+t")) == NULL)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Can not get tree",
"Can not create temporary XML file");
/* Get directory tree into XML file */
XML_WriteStartFile (Gbl.F.XML,"tree",false);
if (!Brw_CheckIfFileOrFolderIsSetAsHiddenInDB (Brw_IS_FOLDER,
2019-04-25 14:39:51 +02:00
Gbl.FileBrowser.FilFolLnk.Full)) // If root folder is visible
2019-05-16 14:02:06 +02:00
API_ListDir (1,Gbl.FileBrowser.Priv.PathRootFolder,Brw_RootFolderInternalNames[Gbl.FileBrowser.Type]);
2014-12-01 23:55:08 +01:00
XML_WriteEndFile (Gbl.F.XML,"tree");
/* Compute file size */
// fseek (Gbl.F.XML,0L,SEEK_END);
FileSize = (unsigned long) ftell (Gbl.F.XML);
fseek (Gbl.F.XML,0L,SEEK_SET);
/* Copy XML content from file to memory */
getDirectoryTreeOut->tree = soap_malloc (soap,FileSize + 1);
2014-12-01 23:55:08 +01:00
NumBytesRead = fread (getDirectoryTreeOut->tree,1,FileSize,Gbl.F.XML);
getDirectoryTreeOut->tree[NumBytesRead] = '\0';
/* Close and remove XML file */
Fil_CloseXMLFile ();
unlink (XMLFileName);
return SOAP_OK;
}
/*****************************************************************************/
/************************ List a directory recursively ***********************/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
static void API_ListDir (unsigned Level,const char *Path,const char *PathInTree)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_NEW_LINE;
2015-12-21 13:36:39 +01:00
struct dirent **FileList;
int NumFile;
int NumFiles;
2018-11-09 20:47:39 +01:00
char PathFileRel[PATH_MAX + 1 + NAME_MAX + 1];
char PathFileInExplTree[PATH_MAX + 1 + NAME_MAX + 1];
2014-12-01 23:55:08 +01:00
struct stat FileStatus;
/***** Scan directory *****/
2015-12-21 13:36:39 +01:00
if ((NumFiles = scandir (Path,&FileList,NULL,alphasort)) >= 0) // No error
{
/***** List files *****/
for (NumFile = 0;
NumFile < NumFiles;
NumFile++)
{
if (strcmp (FileList[NumFile]->d_name,".") &&
strcmp (FileList[NumFile]->d_name,"..")) // Skip directories "." and ".."
{
snprintf (PathFileRel,sizeof (PathFileRel),"%s/%s",
2018-10-18 02:02:32 +02:00
Path,FileList[NumFile]->d_name);
snprintf (PathFileInExplTree,sizeof (PathFileInExplTree),"%s/%s",
2018-10-18 02:02:32 +02:00
PathInTree,FileList[NumFile]->d_name);
2014-12-01 23:55:08 +01:00
2019-04-25 14:39:51 +02:00
Str_Copy (Gbl.FileBrowser.FilFolLnk.Path,PathInTree,
sizeof (Gbl.FileBrowser.FilFolLnk.Path) - 1);
2019-04-25 14:39:51 +02:00
Str_Copy (Gbl.FileBrowser.FilFolLnk.Name,FileList[NumFile]->d_name,
sizeof (Gbl.FileBrowser.FilFolLnk.Name) - 1);
2019-04-25 14:39:51 +02:00
2016-12-29 22:00:35 +01:00
if (!lstat (PathFileRel,&FileStatus)) // On success ==> 0 is returned
2014-12-01 23:55:08 +01:00
{
2016-12-29 22:00:35 +01:00
/***** Construct the full path of the file or folder *****/
2019-04-25 14:39:51 +02:00
Brw_SetFullPathInTree ();
2014-12-01 23:55:08 +01:00
2016-12-29 22:00:35 +01:00
if (S_ISDIR (FileStatus.st_mode)) // It's a directory
{
/***** Write a row for the subdirectory *****/
2019-05-16 14:02:06 +02:00
if (API_WriteRowFileBrowser (Level,Brw_IS_FOLDER,FileList[NumFile]->d_name))
2016-12-29 22:00:35 +01:00
{
/* List subtree starting at this this directory */
2019-05-16 14:02:06 +02:00
API_ListDir (Level + 1,PathFileRel,PathFileInExplTree);
2016-12-29 22:00:35 +01:00
/* Indent and end dir */
2019-05-16 14:02:06 +02:00
API_IndentXMLLine (Level);
2016-12-29 22:00:35 +01:00
fprintf (Gbl.F.XML,"</dir>%s",Txt_NEW_LINE);
}
2015-12-21 13:36:39 +01:00
}
2016-12-29 22:00:35 +01:00
else if (S_ISREG (FileStatus.st_mode)) // It's a regular file
2019-05-16 14:02:06 +02:00
API_WriteRowFileBrowser (Level,
2016-12-29 22:00:35 +01:00
Str_FileIs (FileList[NumFile]->d_name,"url") ? Brw_IS_LINK :
Brw_IS_FILE,
FileList[NumFile]->d_name);
2014-12-01 23:55:08 +01:00
}
}
2015-12-21 13:36:39 +01:00
2019-11-06 19:45:20 +01:00
free (FileList[NumFile]);
2014-12-01 23:55:08 +01:00
}
2019-11-06 19:45:20 +01:00
free (FileList);
2015-12-21 13:36:39 +01:00
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********************** Write a row of a file browser ***********************/
/*****************************************************************************/
// If it is the first row (root folder), always show it
// If it is not the first row, it is shown or not depending on whether it is hidden or not
// If the row is visible, return true. If it is hidden, return false
2019-05-16 14:02:06 +02:00
static bool API_WriteRowFileBrowser (unsigned Level,Brw_FileType_t FileType,const char *FileName)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_NEW_LINE;
extern const char *Txt_LICENSES[Brw_NUM_LICENSES];
struct FileMetadata FileMetadata;
2017-03-07 01:56:41 +01:00
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
2014-12-01 23:55:08 +01:00
/***** Is this row hidden or visible? *****/
2017-10-08 00:51:49 +02:00
if (Gbl.FileBrowser.Type == Brw_SHOW_DOC_CRS ||
Gbl.FileBrowser.Type == Brw_SHOW_DOC_GRP)
2014-12-01 23:55:08 +01:00
if (Brw_CheckIfFileOrFolderIsSetAsHiddenInDB (FileType,
2019-04-25 14:39:51 +02:00
Gbl.FileBrowser.FilFolLnk.Full))
2014-12-01 23:55:08 +01:00
return false;
/***** XML row *****/
/* Indent */
2019-05-16 14:02:06 +02:00
API_IndentXMLLine (Level);
2014-12-01 23:55:08 +01:00
/* Write file or folder data */
if (FileType == Brw_IS_FOLDER)
fprintf (Gbl.F.XML,"<dir name=\"%s\">%s",
FileName,Txt_NEW_LINE);
else // File or link
{
/* Get file metadata */
Brw_GetFileMetadataByPath (&FileMetadata);
2015-02-23 23:45:32 +01:00
Brw_GetFileTypeSizeAndDate (&FileMetadata);
2014-12-01 23:55:08 +01:00
if (FileMetadata.FilCod <= 0) // No entry for this file in database table of files
/* Add entry to the table of files/folders */
FileMetadata.FilCod = Brw_DB_AddPath (-1L,FileMetadata.FilFolLnk.Type,
2019-04-25 14:39:51 +02:00
Gbl.FileBrowser.FilFolLnk.Full,false,Brw_LICENSE_DEFAULT);
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Other.UsrDat.UsrCod = FileMetadata.PublisherUsrCod;
Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,
Usr_DONT_GET_PREFS,
Usr_DONT_GET_ROLE_IN_CURRENT_CRS);
2016-07-08 12:43:48 +02:00
Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,PhotoURL);
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.XML,"<file name=\"%s\">"
"<code>%ld</code>"
"<size>%lu</size>"
"<time>%lu</time>"
"<license>%s</license>"
"<publisher>%s</publisher>"
"<photo>%s</photo>"
"</file>%s",
FileName,
FileMetadata.FilCod,
(unsigned long) FileMetadata.Size,
(unsigned long) FileMetadata.Time,
Txt_LICENSES[FileMetadata.License],
Gbl.Usrs.Other.UsrDat.FullName,
PhotoURL,
Txt_NEW_LINE);
}
return true;
}
/*****************************************************************************/
/******************************* Indent XML line *****************************/
/*****************************************************************************/
2019-05-16 14:02:06 +02:00
static void API_IndentXMLLine (unsigned Level)
2014-12-01 23:55:08 +01:00
{
for ( ;
Level;
Level--)
fprintf (Gbl.F.XML,"\t");
}
/*****************************************************************************/
/**************************** Get info of a file *****************************/
/*****************************************************************************/
int swad__getFile (struct soap *soap,
char *wsKey,int fileCode, // input
struct swad__getFileOutput *getFileOut) // output
{
extern const char *Txt_LICENSES[Brw_NUM_LICENSES];
int ReturnCode;
struct FileMetadata FileMetadata;
2017-03-07 01:56:41 +01:00
char URL[Cns_MAX_BYTES_WWW + 1];
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getFile;
2014-12-01 23:55:08 +01:00
/***** Allocate space for strings *****/
getFileOut->fileName = soap_malloc (soap,NAME_MAX + 1);
getFileOut->URL = soap_malloc (soap,Cns_MAX_BYTES_WWW + 1);
getFileOut->license = soap_malloc (soap,Brw_MAX_BYTES_LICENSE + 1);
getFileOut->publisherName = soap_malloc (soap,Usr_MAX_BYTES_FULL_NAME + 1);
getFileOut->publisherPhoto = soap_malloc (soap,Cns_MAX_BYTES_WWW + 1);
2014-12-01 23:55:08 +01:00
/***** Default values returned on error *****/
getFileOut->fileName[0] = '\0';
getFileOut->URL[0] = '\0';
getFileOut->size = 0;
getFileOut->time = 0;
getFileOut->license[0] = '\0';
getFileOut->publisherName[0] = '\0';
getFileOut->publisherPhoto[0] = '\0';
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get file metadata *****/
FileMetadata.FilCod = (long) fileCode;
if (FileMetadata.FilCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad file code",
"File code must be a integer greater than 0");
Brw_GetFileMetadataByCod (&FileMetadata);
if (FileMetadata.FilCod <= 0)
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"File does not exist, please refresh",
"The file requested does not exists");
/***** Set course and group codes *****/
2015-01-25 02:07:04 +01:00
Brw_GetCrsGrpFromFileMetadata (FileMetadata.FileBrowser,FileMetadata.Cod,
2019-04-03 20:57:04 +02:00
&Gbl.Hierarchy.Ins.InsCod,
&Gbl.Hierarchy.Ctr.CtrCod,
&Gbl.Hierarchy.Deg.DegCod,
2019-04-04 10:45:15 +02:00
&Gbl.Hierarchy.Crs.CrsCod,
&Gbl.Crs.Grps.GrpCod);
2020-09-25 12:43:21 +02:00
Hie_InitHierarchy ();
2014-12-01 23:55:08 +01:00
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
/***** Check course and group codes *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Crs.Grps.GrpCod)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to course");
/***** Check if I belong to group *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpCod > 0)
if (!Grp_GetIfIBelongToGrp (Gbl.Crs.Grps.GrpCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to group");
/***** Check if file is in a valid zone *****/
2019-04-25 14:39:51 +02:00
Gbl.FileBrowser.Type = FileMetadata.FileBrowser;
switch (Gbl.FileBrowser.Type)
2014-12-01 23:55:08 +01:00
{
2017-10-08 00:51:49 +02:00
case Brw_ADMI_DOC_CRS:
case Brw_ADMI_DOC_GRP:
case Brw_ADMI_SHR_CRS:
case Brw_ADMI_SHR_GRP:
2014-12-01 23:55:08 +01:00
break;
2017-10-08 00:51:49 +02:00
case Brw_ADMI_MRK_CRS:
case Brw_ADMI_MRK_GRP:
2014-12-01 23:55:08 +01:00
// Downloading a file of marks is only allowed for teachers
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2019-04-25 14:39:51 +02:00
"Wrong tree",
"Wrong file zone");
2014-12-01 23:55:08 +01:00
break;
default:
2020-02-24 19:31:55 +01:00
return soap_sender_fault (soap,
2014-12-01 23:55:08 +01:00
"Wrong tree",
"Wrong file zone");
}
/***** Set paths *****/
Brw_InitializeFileBrowser ();
2019-04-25 15:31:42 +02:00
Str_Copy (Gbl.FileBrowser.FilFolLnk.Path,FileMetadata.FilFolLnk.Path,
sizeof (Gbl.FileBrowser.FilFolLnk.Path) - 1);
2019-04-25 15:31:42 +02:00
Str_Copy (Gbl.FileBrowser.FilFolLnk.Name,FileMetadata.FilFolLnk.Name,
sizeof (Gbl.FileBrowser.FilFolLnk.Name) - 1);
2019-04-25 14:39:51 +02:00
Brw_SetFullPathInTree ();
2014-12-01 23:55:08 +01:00
/***** Get file size and date *****/
2015-02-23 23:45:32 +01:00
Brw_GetFileTypeSizeAndDate (&FileMetadata);
2014-12-01 23:55:08 +01:00
/***** Update number of views *****/
Brw_GetAndUpdateFileViews (&FileMetadata);
/***** Create and get link to download the file *****/
2019-04-25 15:31:42 +02:00
Brw_GetLinkToDownloadFile (FileMetadata.FilFolLnk.Path,
FileMetadata.FilFolLnk.Name,
2014-12-01 23:55:08 +01:00
URL);
/***** Copy data into output structure *****/
Str_Copy (getFileOut->fileName,FileMetadata.FilFolLnk.Name,NAME_MAX);
2014-12-01 23:55:08 +01:00
Str_Copy (getFileOut->URL,URL,Cns_MAX_BYTES_WWW);
2014-12-01 23:55:08 +01:00
getFileOut->size = (int) FileMetadata.Size;
getFileOut->time = (int) FileMetadata.Time;
2017-01-15 18:02:52 +01:00
Str_Copy (getFileOut->license,Txt_LICENSES[FileMetadata.License],
2017-03-07 11:03:05 +01:00
Brw_MAX_BYTES_LICENSE);
2014-12-01 23:55:08 +01:00
if ((Gbl.Usrs.Other.UsrDat.UsrCod = FileMetadata.PublisherUsrCod) > 0)
/* Get publisher's data */
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,
Usr_DONT_GET_PREFS,
Usr_DONT_GET_ROLE_IN_CURRENT_CRS))
2014-12-01 23:55:08 +01:00
{
/* Copy publisher's data into output structure */
2017-01-15 18:02:52 +01:00
Str_Copy (getFileOut->publisherName,Gbl.Usrs.Other.UsrDat.FullName,
Usr_MAX_BYTES_FULL_NAME);
2014-12-01 23:55:08 +01:00
2016-07-08 12:43:48 +02:00
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
Str_Copy (getFileOut->publisherPhoto,PhotoURL,Cns_MAX_BYTES_WWW);
2014-12-01 23:55:08 +01:00
}
return SOAP_OK;
}
/*****************************************************************************/
/**************************** Get info of my marks ***************************/
/*****************************************************************************/
int swad__getMarks (struct soap *soap,
char *wsKey,int fileCode, // input
struct swad__getMarksOutput *getMarksOut) // output
{
int ReturnCode;
struct FileMetadata FileMetadata;
2017-03-08 14:12:33 +01:00
char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1]; // Not used
2014-12-01 23:55:08 +01:00
char *ContentStr;
2017-01-15 22:58:26 +01:00
size_t Length;
2014-12-01 23:55:08 +01:00
2016-07-20 20:24:16 +02:00
/***** Initializations *****/
2020-02-24 19:31:55 +01:00
API_Set_gSOAP_RuntimeEnv (soap);
2019-05-16 14:02:06 +02:00
Gbl.WebService.Function = API_getMarks;
2014-12-01 23:55:08 +01:00
getMarksOut->content = NULL;
/***** Check web service key *****/
2019-05-16 14:02:06 +02:00
if ((ReturnCode = API_CheckWSKey (wsKey)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad web service key",
"Web service key does not exist in database");
/***** Get file metadata *****/
FileMetadata.FilCod = (long) fileCode;
Brw_GetFileMetadataByCod (&FileMetadata);
2019-04-25 15:31:42 +02:00
if (FileMetadata.FilFolLnk.Type != Brw_IS_FILE ||
2014-12-01 23:55:08 +01:00
FileMetadata.IsHidden ||
2017-10-08 00:51:49 +02:00
(FileMetadata.FileBrowser != Brw_ADMI_MRK_CRS &&
FileMetadata.FileBrowser != Brw_ADMI_MRK_GRP))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Bad file code",
"You can not get marks from this file");
2015-01-25 00:58:21 +01:00
/***** Set course and group codes *****/
2015-01-25 02:07:04 +01:00
Brw_GetCrsGrpFromFileMetadata (FileMetadata.FileBrowser,FileMetadata.Cod,
2019-04-03 20:57:04 +02:00
&Gbl.Hierarchy.Ins.InsCod,
&Gbl.Hierarchy.Ctr.CtrCod,
&Gbl.Hierarchy.Deg.DegCod,
2019-04-04 10:45:15 +02:00
&Gbl.Hierarchy.Crs.CrsCod,
&Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
/***** Check course and group codes *****/
2020-02-24 19:31:55 +01:00
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Crs.Grps.GrpCod)) != SOAP_OK)
2014-12-01 23:55:08 +01:00
return ReturnCode;
/***** Get some of my data *****/
2019-05-16 14:02:06 +02:00
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2016-07-20 20:24:16 +02:00
"Can not get user's data from database",
"User does not exist in database");
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2014-12-01 23:55:08 +01:00
2017-05-23 00:40:03 +02:00
/***** Check if I am a student, non-editing teacher or teacher in the course *****/
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_STD &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_NET &&
Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to course");
/***** Check if I belong to group *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpCod > 0)
if (!Grp_GetIfIBelongToGrp (Gbl.Crs.Grps.GrpCod))
2020-02-24 19:31:55 +01:00
return soap_receiver_fault (soap,
2014-12-01 23:55:08 +01:00
"Request forbidden",
"Requester must belong to group");
/***** Get content *****/
ContentStr = NULL;
2017-03-06 13:01:16 +01:00
Mrk_GetNotifMyMarks (SummaryStr, // Not used
&ContentStr,
FileMetadata.FilCod,Gbl.Usrs.Me.UsrDat.UsrCod,true);
2014-12-01 23:55:08 +01:00
if (ContentStr != NULL)
{
2017-01-15 22:58:26 +01:00
Length = strlen (ContentStr);
getMarksOut->content = soap_malloc (soap,Length + 1);
Str_Copy (getMarksOut->content,ContentStr,Length);
2019-11-06 19:45:20 +01:00
free (ContentStr);
2014-12-01 23:55:08 +01:00
ContentStr = NULL;
}
else
{
getMarksOut->content = soap_malloc (soap,1);
2014-12-01 23:55:08 +01:00
getMarksOut->content[0] = '\0';
}
return SOAP_OK;
}
2020-05-06 21:27:06 +02:00
/*****************************************************************************/
/**************** Get locations associated to a MAC address ******************/
/*****************************************************************************/
2020-05-30 18:11:53 +02:00
int swad__getLocation (struct soap *soap,
char *wsKey,char *MAC, // input
struct swad__getLocationOutput *getLocationOut) // output
2020-05-06 21:27:06 +02:00
{
int ReturnCode;
2020-09-01 12:49:11 +02:00
unsigned long long MACnum;
2020-05-06 21:27:06 +02:00
MYSQL_RES *mysql_res;
unsigned NumLocs;
/***** Initializations *****/
API_Set_gSOAP_RuntimeEnv (soap);
2020-05-30 18:11:53 +02:00
Gbl.WebService.Function = API_getLocation;
2020-05-06 21:27:06 +02:00
/***** Check web service key *****/
if ((ReturnCode = API_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 (soap,
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2020-05-06 21:27:06 +02:00
/***** Convert MAC string to number *****/
2020-09-01 12:49:11 +02:00
if (sscanf (MAC,"%llx",&MACnum) != 1)
2020-05-06 21:27:06 +02:00
return soap_receiver_fault (soap,
"Bad MAC",
"MAC address format should be 12 hexadecimal digits");
/***** Get list of locations *****/
NumLocs = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get matches",
"SELECT ins_instits.InsCod," // row[ 0]
"ins_instits.ShortName," // row[ 1]
"ins_instits.FullName," // row[ 2]
"ctr_centers.CtrCod," // row[ 3]
"ctr_centers.ShortName," // row[ 4]
"ctr_centers.FullName," // row[ 5]
"bld_buildings.BldCod," // row[ 6]
"bld_buildings.ShortName," // row[ 7]
"bld_buildings.FullName," // row[ 8]
"roo_rooms.Floor," // row[ 9]
"roo_rooms.RooCod," // row[10]
"roo_rooms.ShortName," // row[11]
"roo_rooms.FullName" // row[12]
" FROM roo_macs,"
"roo_rooms,"
"bld_buildings,"
"ctr_centers,"
"ins_instits"
" WHERE roo_macs.MAC=%llu"
" AND roo_macs.RooCod=roo_rooms.RooCod"
" AND roo_rooms.BldCod=bld_buildings.BldCod"
" AND bld_buildings.CtrCod=ctr_centers.CtrCod"
" AND ctr_centers.InsCod=ins_instits.InsCod"
" ORDER BY roo_rooms.Capacity DESC," // Get the biggest room
"roo_rooms.ShortName"
" LIMIT 1",
MACnum);
2020-05-06 21:27:06 +02:00
2020-05-30 18:11:53 +02:00
API_GetDataOfLocation (soap,
&(getLocationOut->location),
NULL, // Don't get check in time
&mysql_res,NumLocs);
return SOAP_OK;
}
/*****************************************************************************/
/***************** Check in (send user's current location) *******************/
/*****************************************************************************/
int swad__sendMyLocation (struct soap *soap,
char *wsKey,int roomCode, // input
struct swad__sendMyLocationOutput *sendMyLocationOut) // output
{
int ReturnCode;
long ChkCod;
/***** Initializations *****/
API_Set_gSOAP_RuntimeEnv (soap);
Gbl.WebService.Function = API_sendMyLocation;
/***** Default values returned on error *****/
sendMyLocationOut->success = 0; // error
/***** Check web service key *****/
if ((ReturnCode = API_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 (soap,
"Bad web service key",
"Web service key does not exist in database");
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
2020-05-30 18:11:53 +02:00
/***** Check in (insert pair user-room) in the database *****/
/* Get the code of the inserted item */
ChkCod =
DB_QueryINSERTandReturnCode ("can not save current location",
"INSERT INTO roo_check_in"
2020-05-30 18:11:53 +02:00
" (UsrCod,RooCod,CheckInTime)"
" SELECT %ld,"
"RooCod,"
"NOW()"
" FROM roo_rooms"
" WHERE RooCod=%d", // Check that room exists
Gbl.Usrs.Me.UsrDat.UsrCod,
roomCode);
2020-05-30 18:11:53 +02:00
/***** Return notification code *****/
sendMyLocationOut->success = (ChkCod > 0) ? 1 : 0;
return SOAP_OK;
}
/*****************************************************************************/
/***************** Check in (send user's current location) *******************/
/*****************************************************************************/
int swad__getLastLocation (struct soap *soap,
char *wsKey,int userCode, // input
struct swad__getLastLocationOutput *getLastLocationOut) // output
{
int ReturnCode;
MYSQL_RES *mysql_res;
unsigned NumLocs;
/***** Initializations *****/
API_Set_gSOAP_RuntimeEnv (soap);
Gbl.WebService.Function = API_getLastLocation;
/***** Check web service key *****/
if ((ReturnCode = API_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 (soap,
"Bad web service key",
"Web service key does not exist in database");
/***** Check if I can see user's location *****/
/*
I can only consult the location of another user
if the intersection of the centers of our courses is not empty.
The other user does not have to share any course with me,
but at least some course of each one has to share center.
*/
if (DB_QueryCOUNT ("can not get session data",
"SELECT COUNT(*) FROM "
"(SELECT DISTINCT deg_degrees.CtrCod"
" FROM crs_users,"
"crs_courses,"
"deg_degrees"
" WHERE crs_users.UsrCod=%ld"
" AND crs_users.CrsCod=crs_courses.CrsCod"
" AND crs_courses.DegCod=deg_degrees.DegCod) AS C1," // centers of my courses
"(SELECT DISTINCT deg_degrees.CtrCod"
" FROM crs_users,"
"crs_courses,"
"deg_degrees"
" WHERE crs_users.UsrCod=%d"
" AND crs_users.CrsCod=crs_courses.CrsCod"
" AND crs_courses.DegCod=deg_degrees.DegCod) AS C2" // centers of user's courses
2020-05-30 18:11:53 +02:00
" WHERE C1.CtrCod=C2.CtrCod",
Gbl.Usrs.Me.UsrDat.UsrCod,
userCode))
{
/***** Get list of locations *****/
NumLocs = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get matches",
"SELECT ins_instits.InsCod," // row[ 0]
"ins_instits.ShortName," // row[ 1]
"ins_instits.FullName," // row[ 2]
"ctr_centers.CtrCod," // row[ 3]
"ctr_centers.ShortName," // row[ 4]
"ctr_centers.FullName," // row[ 5]
"bld_buildings.BldCod," // row[ 6]
"bld_buildings.ShortName," // row[ 7]
"bld_buildings.FullName," // row[ 8]
"roo_rooms.Floor," // row[ 9]
"roo_rooms.RooCod," // row[10]
"roo_rooms.ShortName," // row[11]
"roo_rooms.FullName," // row[12]
"UNIX_TIMESTAMP(roo_check_in.CheckInTime)" // row[13]
" FROM roo_check_in,"
"roo_rooms,"
"bld_buildings,"
"ctr_centers,"
"ins_instits"
" WHERE roo_check_in.UsrCod=%d"
" AND roo_check_in.ChkCod="
"(SELECT ChkCod"
" FROM roo_check_in"
" WHERE UsrCod=%d"
" ORDER BY ChkCod DESC"
" LIMIT 1)" // Faster than SELECT MAX
" AND roo_check_in.RooCod=roo_rooms.RooCod"
" AND roo_rooms.BldCod=bld_buildings.BldCod"
" AND bld_buildings.CtrCod=ctr_centers.CtrCod"
" AND ctr_centers.InsCod=ins_instits.InsCod",
userCode,
userCode);
2020-05-30 18:11:53 +02:00
API_GetDataOfLocation (soap,
&(getLastLocationOut->location),
&(getLastLocationOut->checkinTime), // Get check in time
&mysql_res,NumLocs);
}
else
{
/* I can not see user's location ==> reset output */
API_ResetLocation (soap, &(getLastLocationOut->location));
getLastLocationOut->checkinTime = 0L;
}
return SOAP_OK;
}
/*****************************************************************************/
/************************* Get assignment data *******************************/
/*****************************************************************************/
static void API_GetDataOfLocation (struct soap *soap,
struct swad__location *location,
time_t *CheckInTime,
MYSQL_RES **mysql_res,
unsigned NumLocs)
{
MYSQL_ROW row;
size_t Length;
/***** Get data of location from database *****/
2020-05-11 16:57:04 +02:00
if (NumLocs) // Rooms found
2020-05-06 21:27:06 +02:00
{
2020-05-30 18:11:53 +02:00
/* Get row */
row = mysql_fetch_row (*mysql_res);
2020-05-11 16:57:04 +02:00
/*
ins_instits.InsCod // row[ 0]
ins_instits.ShortName // row[ 1]
ins_instits.FullName // row[ 2]
ctr_centers.CtrCod // row[ 3]
ctr_centers.ShortName // row[ 4]
ctr_centers.FullName // row[ 5]
bld_buildings.BldCod // row[ 6]
bld_buildings.ShortName // row[ 7]
bld_buildings.FullName // row[ 8]
roo_rooms.Floor // row[ 9]
roo_rooms.RooCod // row[10]
roo_rooms.ShortName // row[11]
roo_rooms.FullName // row[12]
UNIX_TIMESTAMP(roo_check_in.CheckInTime) // row[13] (optional)
2020-05-11 16:57:04 +02:00
*/
/* Get institution code (row[0]) */
2020-05-30 18:11:53 +02:00
location->institutionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
2020-05-11 16:57:04 +02:00
/* Get institution short name (row[1]) */
Length = strlen (row[1]);
location->institutionShortName = soap_malloc (soap,Length + 1);
2020-05-30 18:11:53 +02:00
Str_Copy (location->institutionShortName,row[1],Length);
2020-05-11 16:57:04 +02:00
/* Get institution full name (row[2]) */
Length = strlen (row[2]);
location->institutionFullName = soap_malloc (soap,Length + 1);
2020-05-30 18:11:53 +02:00
Str_Copy (location->institutionFullName,row[2],Length);
2020-05-11 16:57:04 +02:00
/* Get center code (row[3]) */
2020-05-30 18:11:53 +02:00
location->centerCode = (int) Str_ConvertStrCodToLongCod (row[3]);
2020-05-11 16:57:04 +02:00
/* Get center short name (row[4]) */
Length = strlen (row[4]);
location->centerShortName = soap_malloc (soap,Length + 1);
2020-05-30 18:11:53 +02:00
Str_Copy (location->centerShortName,row[4],Length);
2020-05-11 16:57:04 +02:00
/* Get center full name (row[5]) */
Length = strlen (row[5]);
location->centerFullName = soap_malloc (soap,Length + 1);
2020-05-30 18:11:53 +02:00
Str_Copy (location->centerFullName,row[5],Length);
2020-05-11 16:57:04 +02:00
/* Get building code (row[6]) */
2020-05-30 18:11:53 +02:00
location->buildingCode = (int) Str_ConvertStrCodToLongCod (row[6]);
2020-05-11 16:57:04 +02:00
/* Get building short name (row[7]) */
Length = strlen (row[7]);
location->buildingShortName = soap_malloc (soap,Length + 1);
2020-05-30 18:11:53 +02:00
Str_Copy (location->buildingShortName,row[7],Length);
2020-05-11 16:57:04 +02:00
/* Get building full name (row[8]) */
Length = strlen (row[8]);
location->buildingFullName = soap_malloc (soap,Length + 1);
2020-05-30 18:11:53 +02:00
Str_Copy (location->buildingFullName,row[8],Length);
2020-05-11 16:57:04 +02:00
/* Get floor (row[9]) */
2020-05-30 18:11:53 +02:00
location->floor = (int) Str_ConvertStrCodToLongCod (row[9]);
2020-05-11 16:57:04 +02:00
/* Get room code (row[10]) */
2020-05-30 18:11:53 +02:00
location->roomCode = (int) Str_ConvertStrCodToLongCod (row[10]);
2020-05-11 16:57:04 +02:00
/* Get room short name (row[11]) */
Length = strlen (row[11]);
location->roomShortName = soap_malloc (soap,Length + 1);
2020-05-30 18:11:53 +02:00
Str_Copy (location->roomShortName,row[11],Length);
2020-05-11 16:57:04 +02:00
/* Get room full name (row[12]) */
Length = strlen (row[12]);
location->roomFullName = soap_malloc (soap,Length + 1);
2020-05-30 18:11:53 +02:00
Str_Copy (location->roomFullName,row[12],Length);
/* Get check in time (row[13]) */
if (CheckInTime)
{
*CheckInTime = 0L;
if (row[13])
sscanf (row[13],"%ld",CheckInTime);
}
2020-05-11 16:57:04 +02:00
}
else
{
/* No room found ==> reset output */
2020-05-30 18:11:53 +02:00
API_ResetLocation (soap,location);
if (CheckInTime)
*CheckInTime = 0L;
2020-05-06 21:27:06 +02:00
}
/***** Free structure that stores the query result *****/
2020-05-30 18:11:53 +02:00
DB_FreeMySQLResult (mysql_res);
2020-05-06 21:27:06 +02:00
}
2020-05-25 20:56:51 +02:00
/*****************************************************************************/
2020-05-30 18:11:53 +02:00
/************************* Get assignment data *******************************/
2020-05-25 20:56:51 +02:00
/*****************************************************************************/
2020-05-30 18:11:53 +02:00
static void API_ResetLocation (struct soap *soap,
struct swad__location *location)
2020-05-25 20:56:51 +02:00
{
location->institutionCode = -1;
location->institutionShortName = soap_malloc (soap,1);
2020-05-30 18:11:53 +02:00
location->institutionShortName[0] = '\0';
location->institutionFullName = soap_malloc (soap,1);
location->institutionFullName[0] = '\0';
2020-05-30 18:11:53 +02:00
location->centerCode = -1;
location->centerShortName = soap_malloc (soap,1);
location->centerShortName[0] = '\0';
location->centerFullName = soap_malloc (soap,1);
location->centerFullName[0] = '\0';
2020-05-30 18:11:53 +02:00
location->buildingCode = -1;
location->buildingShortName = soap_malloc (soap,1);
location->buildingShortName[0] = '\0';
location->buildingFullName = soap_malloc (soap,1);
location->buildingFullName[0] = '\0';
2020-05-30 18:11:53 +02:00
location->floor = 0;
location->roomCode = -1;
location->roomShortName = soap_malloc (soap,1);
location->roomShortName[0] = '\0';
location->roomFullName = soap_malloc (soap,1);
location->roomFullName[0] = '\0';
2020-05-25 20:56:51 +02:00
}