mirror of
https://github.com/acanas/swad-core.git
synced 2024-09-08 00:00:25 +02:00
5429 lines
208 KiB
C
5429 lines
208 KiB
C
// swad_API.c: SWAD web API provided to external plugins
|
|
|
|
/*
|
|
SWAD (Shared Workspace At a Distance),
|
|
is a web platform developed at the University of Granada (Spain),
|
|
and used to support university teaching.
|
|
|
|
This file is part of SWAD core.
|
|
Copyright (C) 1999-2024 Antonio Cañas Vargas
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
/*****************************************************************************/
|
|
/******* 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:
|
|
---------------------
|
|
OBJS = list of swad object files
|
|
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
|
|
|
|
#include <dirent.h> // For scandir, etc.
|
|
#include <linux/limits.h> // For PATH_MAX
|
|
#include <stddef.h> // For NULL
|
|
#include <string.h>
|
|
#include <stdsoap2.h>
|
|
#include <sys/stat.h> // For lstat
|
|
|
|
#include "soap/soapH.h" // gSOAP header
|
|
#include "soap/swad.nsmap" // Namespaces map used
|
|
|
|
#include "swad_account.h"
|
|
#include "swad_API.h"
|
|
#include "swad_API_database.h"
|
|
#include "swad_attendance_database.h"
|
|
#include "swad_autolink.h"
|
|
#include "swad_browser.h"
|
|
#include "swad_browser_database.h"
|
|
#include "swad_course_database.h"
|
|
#include "swad_database.h"
|
|
#include "swad_enrolment_database.h"
|
|
#include "swad_error.h"
|
|
#include "swad_forum.h"
|
|
#include "swad_game_database.h"
|
|
#include "swad_global.h"
|
|
#include "swad_group_database.h"
|
|
#include "swad_hierarchy.h"
|
|
#include "swad_hierarchy_type.h"
|
|
#include "swad_ID.h"
|
|
#include "swad_mail_database.h"
|
|
#include "swad_mark.h"
|
|
#include "swad_match.h"
|
|
#include "swad_match_database.h"
|
|
#include "swad_message_database.h"
|
|
#include "swad_nickname_database.h"
|
|
#include "swad_notice.h"
|
|
#include "swad_notice_database.h"
|
|
#include "swad_notification.h"
|
|
#include "swad_notification_database.h"
|
|
#include "swad_password.h"
|
|
#include "swad_plugin_database.h"
|
|
#include "swad_question_database.h"
|
|
#include "swad_role.h"
|
|
#include "swad_role_database.h"
|
|
#include "swad_room_database.h"
|
|
#include "swad_search.h"
|
|
#include "swad_session_database.h"
|
|
#include "swad_setting_database.h"
|
|
#include "swad_tag_database.h"
|
|
#include "swad_test_config.h"
|
|
#include "swad_test_visibility.h"
|
|
#include "swad_user.h"
|
|
#include "swad_user_database.h"
|
|
#include "swad_www.h"
|
|
#include "swad_xml.h"
|
|
|
|
/*****************************************************************************/
|
|
/************** External global variables from others modules ****************/
|
|
/*****************************************************************************/
|
|
|
|
extern struct Globals Gbl;
|
|
extern const char Str_BIN_TO_BASE64URL[64 + 1];
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private constants *****************************/
|
|
/*****************************************************************************/
|
|
|
|
// Add new functions at the end
|
|
static const char *API_Functions[1 + API_NUM_FUNCTIONS] =
|
|
{
|
|
[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
|
|
};
|
|
|
|
/* Web service roles (they do not match internal swad-core roles) */
|
|
#define API_NUM_ROLES 4
|
|
typedef enum
|
|
{
|
|
API_ROLE_UNKNOWN = 0, // User not logged in (do not change this constant to any value other than 0)
|
|
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;
|
|
|
|
/* Translation from service-web-role to swad-core-role */
|
|
static const Rol_Role_t API_SvcRole_to_RolRole[API_NUM_ROLES] =
|
|
{
|
|
[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
|
|
};
|
|
|
|
/* Translation from swad-core-role to service-web-role */
|
|
static const API_Role_t API_RolRole_to_SvcRole[Rol_NUM_ROLES] =
|
|
{
|
|
[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,
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private prototypes ****************************/
|
|
/*****************************************************************************/
|
|
|
|
static void API_Set_gSOAP_RuntimeEnv (struct soap *soap);
|
|
static void API_FreeSoapContext (struct soap *soap);
|
|
|
|
static int API_GetPlgCodFromAppKey (struct soap *soap,
|
|
const char *appKey);
|
|
static int API_CheckIdSession (struct soap *soap,
|
|
const char *IdSes);
|
|
static int API_CheckAPIKey (char APIKey[API_BYTES_KEY + 1]);
|
|
|
|
static int API_CheckCourseAndGroupCodes (struct soap *soap,
|
|
long CrsCod,long GrpCod);
|
|
static int API_GenerateNewAPIKey (struct soap *soap,
|
|
long UsrCod,
|
|
char APIKey[API_BYTES_KEY + 1]);
|
|
static bool API_GetSomeUsrDataFromUsrCod (struct Usr_Data *UsrDat,long CrsCod);
|
|
|
|
static int API_CheckParsNewAccount (char *NewNickWithArr, // Input
|
|
char NewNickWithoutArr[Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1], // Output
|
|
char *NewEmail, // Input-output
|
|
char *NewPlainPassword, // Input
|
|
char NewEncryptedPassword[Pwd_BYTES_ENCRYPTED_PASSWORD + 1]); // Output
|
|
|
|
static int API_WriteSyllabusIntoHTMLBuffer (struct soap *soap,
|
|
struct Syl_Syllabus *Syllabus,
|
|
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 Usr_Data *UsrDat,
|
|
Usr_Can_t ICanSeeUsrID);
|
|
|
|
static void API_GetListGrpsInAttendanceEventFromDB (struct soap *soap,
|
|
long AttCod,char **ListGroups);
|
|
static void API_GetLstGrpsSel (const char *Groups);
|
|
|
|
static int API_GetMyLanguage (struct soap *soap);
|
|
|
|
static int API_SendMessageToUsr (long OriginalMsgCod,
|
|
long ReplyUsrCod,long RecipientUsrCod,
|
|
bool NotifyByEmail,
|
|
const char *Subject,const char *Content);
|
|
|
|
static int API_GetTstTags (struct soap *soap,
|
|
long CrsCod,struct swad__getTestsOutput *getTestsOut);
|
|
static int API_GetTstQuestions (struct soap *soap,
|
|
long CrsCod,time_t BeginTime,
|
|
struct swad__getTestsOutput *getTestsOut);
|
|
static int API_GetTstAnswers (struct soap *soap,
|
|
long CrsCod,time_t BeginTime,
|
|
struct swad__getTestsOutput *getTestsOut);
|
|
static int API_GetTstQuestionTags (struct soap *soap,
|
|
long CrsCod,time_t BeginTime,
|
|
struct swad__getTestsOutput *getTestsOut);
|
|
|
|
static void API_GetListGrpsInMatchFromDB (struct soap *soap,
|
|
long MchCod,char **ListGroups);
|
|
|
|
static void API_ListDir (FILE *XML,unsigned Level,const char *Path,const char *PathInTree);
|
|
static bool API_WriteRowFileBrowser (FILE *XML,unsigned Level,
|
|
Brw_FileType_t FileType,
|
|
const char *FileName);
|
|
static void API_IndentXMLLine (FILE *XML,unsigned Level);
|
|
|
|
static void API_GetLocationData (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);
|
|
|
|
/*****************************************************************************/
|
|
/******* Function called when a web service if required by a plugin **********/
|
|
/*****************************************************************************/
|
|
|
|
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 **********/
|
|
/*****************************************************************************/
|
|
|
|
void API_WebService (void)
|
|
{
|
|
struct soap *soap;
|
|
|
|
if ((soap = soap_new ())) // Allocate and initialize runtime context
|
|
{
|
|
soap_serve (soap);
|
|
|
|
API_FreeSoapContext (soap);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******* Function called to exit on error when executing web service *********/
|
|
/*****************************************************************************/
|
|
|
|
void API_Exit (const char *DetailErrorMessage)
|
|
{
|
|
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);
|
|
|
|
API_FreeSoapContext (soap);
|
|
}
|
|
|
|
exit (ReturnCode);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************************** 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
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****** Check if the application key of the requester of a web service *******/
|
|
/****** is one of the application keys allowed in the plugins *******/
|
|
/*****************************************************************************/
|
|
|
|
static int API_GetPlgCodFromAppKey (struct soap *soap,
|
|
const char *appKey)
|
|
{
|
|
/***** Get plugin code from application key *****/
|
|
if ((Gbl.WebService.PlgCod = Plg_DB_GetPlgCodFromAppKey (appKey)) <= 0)
|
|
return soap_sender_fault (soap,
|
|
"Unknown application key",
|
|
"Unknown application");
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****** Get the name of a web service function given the function code *******/
|
|
/*****************************************************************************/
|
|
|
|
const char *API_GetFunctionNameFromFunCod (long FunCod)
|
|
{
|
|
if (FunCod < 0 || FunCod > API_NUM_FUNCTIONS)
|
|
return API_Functions[0];
|
|
return API_Functions[FunCod];
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****** Check if a session identifier is valid and exists in database ********/
|
|
/*****************************************************************************/
|
|
|
|
static int API_CheckIdSession (struct soap *soap,
|
|
const char *IdSes)
|
|
{
|
|
const char *Ptr;
|
|
unsigned i;
|
|
|
|
/***** Check if pointer is NULL *****/
|
|
if (IdSes == NULL)
|
|
return soap_sender_fault (soap,
|
|
"Bad session identifier",
|
|
"Session identifier is a null pointer");
|
|
|
|
/***** Check length of session identifier *****/
|
|
if (strlen (IdSes) != Cns_BYTES_SESSION_ID)
|
|
return soap_sender_fault (soap,
|
|
"Bad session identifier",
|
|
"The length of the session identifier is wrong");
|
|
|
|
/***** Check if session identifier is in base64url *****/
|
|
for (Ptr = IdSes;
|
|
*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
|
|
return soap_sender_fault (soap,
|
|
"Bad session identifier",
|
|
"The session identifier must contain only base64url characters");
|
|
}
|
|
|
|
/***** Query if session identifier already exists in database *****/
|
|
if (!Ses_DB_CheckIfSessionExists (IdSes))
|
|
return soap_receiver_fault (soap,
|
|
"Bad session identifier",
|
|
"Session identifier does not exist in database");
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************** Check if a web service key exists in database ****************/
|
|
/*****************************************************************************/
|
|
|
|
static int API_CheckAPIKey (char APIKey[API_BYTES_KEY + 1])
|
|
{
|
|
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 *****/
|
|
if (API_DB_GetDataFromAPIKey (&mysql_res,APIKey))
|
|
{
|
|
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 **/
|
|
/*****************************************************************************/
|
|
|
|
static int API_CheckCourseAndGroupCodes (struct soap *soap,
|
|
long CrsCod,long GrpCod)
|
|
{
|
|
/***** Check if course code is correct *****/
|
|
if (CrsCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** Query if course code already exists in database *****/
|
|
if (!Crs_DB_CheckIfCrsCodExists (CrsCod))
|
|
return soap_sender_fault (soap,
|
|
"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"
|
|
if (!Grp_DB_CheckIfGrpBelongsToCrs (GrpCod,CrsCod))
|
|
return soap_sender_fault (soap,
|
|
"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 ********/
|
|
/*****************************************************************************/
|
|
|
|
static int API_GenerateNewAPIKey (struct soap *soap,
|
|
long UsrCod,
|
|
char APIKey[API_BYTES_KEY + 1])
|
|
{
|
|
/***** Remove expired web service keys *****/
|
|
API_DB_RemoveOldAPIKeys ();
|
|
|
|
/***** Create a unique name for the key *****/
|
|
Str_Copy (APIKey,Cry_GetUniqueNameEncrypted (),API_BYTES_KEY);
|
|
|
|
/***** Check that key does not exist in database *****/
|
|
if (API_DB_CheckIfAPIKeyExists (APIKey))
|
|
return soap_receiver_fault (soap,
|
|
"Error when generating key",
|
|
"Generated key already existed in database");
|
|
|
|
/***** Insert key into database *****/
|
|
API_DB_CreateAPIKey (APIKey,UsrCod,Gbl.WebService.PlgCod);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************ Get user's data from database giving a user's code *************/
|
|
/*****************************************************************************/
|
|
// Return false if UsrDat->UsrCod does not exist ini database
|
|
|
|
static bool API_GetSomeUsrDataFromUsrCod (struct Usr_Data *UsrDat,long CrsCod)
|
|
{
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
bool UsrFound;
|
|
|
|
/***** Check if user's code is valid *****/
|
|
if (UsrDat->UsrCod <= 0)
|
|
return false;
|
|
|
|
/***** Get some user's data *****/
|
|
if ((UsrFound = Usr_DB_GetSomeUsrDataFromUsrCod (&mysql_res,UsrDat->UsrCod)))
|
|
{
|
|
/***** 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);
|
|
|
|
/* Get user's brithday (row[4]) */
|
|
Dat_GetDateFromYYYYMMDD (&(UsrDat->Birthday),row[4]);
|
|
|
|
/***** Get list of user's IDs *****/
|
|
ID_GetListIDsFromUsrCod (UsrDat);
|
|
|
|
/***** Get user's nickname *****/
|
|
Nck_DB_GetNicknameFromUsrCod (UsrDat->UsrCod,UsrDat->Nickname);
|
|
|
|
/***** Get user's role *****/
|
|
if (CrsCod > 0)
|
|
/* Get the role in the given course */
|
|
UsrDat->Roles.InCurrentCrs = Rol_DB_GetRoleUsrInCrs (UsrDat->UsrCod,CrsCod);
|
|
else
|
|
/* Get the maximum role in any course */
|
|
UsrDat->Roles.InCurrentCrs = Rol_DB_GetMaxRoleUsrInCrss (UsrDat->UsrCod);
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return UsrFound;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**************************** Get info of my marks ***************************/
|
|
/*****************************************************************************/
|
|
|
|
#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
|
|
|
|
int swad__createAccount (struct soap *soap,
|
|
char *userNickname,char *userEmail,char *userPassword,char *appKey, // input
|
|
struct swad__createAccountOutput *createAccountOut) // output
|
|
{
|
|
char NewNickWithoutArr[Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1];
|
|
char NewEncryptedPassword[Pwd_BYTES_ENCRYPTED_PASSWORD + 1];
|
|
int Result;
|
|
int ReturnCode;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_createAccount;
|
|
|
|
/***** Allocate space for strings *****/
|
|
createAccountOut->wsKey = soap_malloc (soap,API_BYTES_KEY + 1);
|
|
|
|
/***** Default values returned on error *****/
|
|
createAccountOut->userCode = 0; // Undefined error
|
|
createAccountOut->wsKey[0] = '\0';
|
|
|
|
/***** Get plugin code *****/
|
|
if ((ReturnCode = API_GetPlgCodFromAppKey (soap,appKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Check parameters used to create the new account *****/
|
|
Result = API_CheckParsNewAccount (userNickname, // Input
|
|
NewNickWithoutArr, // Output
|
|
userEmail, // Input-output
|
|
userPassword, // Input
|
|
NewEncryptedPassword); // Output
|
|
if (Result < 0)
|
|
{
|
|
createAccountOut->userCode = Result;
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/***** User's has no ID *****/
|
|
Gbl.Usrs.Me.UsrDat.IDs.Num = 0;
|
|
Gbl.Usrs.Me.UsrDat.IDs.List = NULL;
|
|
|
|
/***** Set password to the password typed by the user *****/
|
|
Str_Copy (Gbl.Usrs.Me.UsrDat.Password,NewEncryptedPassword,
|
|
sizeof (Gbl.Usrs.Me.UsrDat.Password) - 1);
|
|
|
|
/***** User does not exist in the platform, so create him/her! *****/
|
|
Acc_CreateNewUsr (&Gbl.Usrs.Me.UsrDat,Usr_ME);
|
|
|
|
/***** 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);
|
|
|
|
/***** Save email *****/
|
|
if (Mai_UpdateEmailInDB (&Gbl.Usrs.Me.UsrDat,userEmail))
|
|
{
|
|
/* Email updated sucessfully */
|
|
Str_Copy (Gbl.Usrs.Me.UsrDat.Email,userEmail,
|
|
sizeof (Gbl.Usrs.Me.UsrDat.Email) - 1);
|
|
Gbl.Usrs.Me.UsrDat.EmailConfirmed = false;
|
|
}
|
|
|
|
/***** Copy new user's code *****/
|
|
createAccountOut->userCode = Gbl.Usrs.Me.UsrDat.UsrCod;
|
|
|
|
/***** Generate a key used in subsequents calls to other web services *****/
|
|
return API_GenerateNewAPIKey (soap,
|
|
(long) createAccountOut->userCode,
|
|
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_CheckParsNewAccount (char *NewNickWithArr, // Input
|
|
char NewNickWithoutArr[Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1], // Output
|
|
char *NewEmail, // Input-output
|
|
char *NewPlainPassword, // Input
|
|
char NewEncryptedPassword[Pwd_BYTES_ENCRYPTED_PASSWORD + 1]) // Output
|
|
{
|
|
char CopyOfNewNick[Nck_MAX_BYTES_NICK_WITH_ARROBA + 1];
|
|
|
|
/***** Step 1/3: Check new nickname *****/
|
|
/* Make a copy without possible starting arrobas */
|
|
if (Nck_CheckIfNickWithArrIsValid (NewNickWithArr)) // If new nickname is valid
|
|
{
|
|
/***** Remove leading arrobas *****/
|
|
Str_Copy (CopyOfNewNick,NewNickWithArr,sizeof (CopyOfNewNick) - 1);
|
|
Str_RemoveLeadingArrobas (CopyOfNewNick);
|
|
|
|
/***** Check if the new nickname matches any of the nicknames of other users *****/
|
|
if (Nck_DB_CheckIfNickMatchesAnyNick (CopyOfNewNick)) // Already without leading arrobas
|
|
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);
|
|
}
|
|
else // New nickname is not valid
|
|
return API_CHECK_NEW_ACCOUNT_NICKNAME_NOT_VALID;
|
|
|
|
/***** Step 2/3: Check new email *****/
|
|
if (Mai_CheckIfEmailIsValid (NewEmail)) // New email is valid
|
|
{
|
|
/***** Check if the new email matches any of the confirmed emails of other users *****/
|
|
if (Mai_DB_CheckIfEmailExistsConfirmed (NewEmail)) // An email of another user is the same that my email
|
|
return API_CHECK_NEW_ACCOUNT_EMAIL_REGISTERED_BY_ANOTHER_USER;
|
|
}
|
|
else // New email is not valid
|
|
return API_CHECK_NEW_ACCOUNT_EMAIL_NOT_VALID;
|
|
|
|
/***** Step 3/3: Check new password *****/
|
|
Cry_EncryptSHA512Base64 (NewPlainPassword,NewEncryptedPassword);
|
|
if (!Pwd_SlowCheckIfPasswordIsGood (NewPlainPassword,NewEncryptedPassword,-1L)) // New password is good?
|
|
return API_CHECK_NEW_ACCOUNT_PASSWORD_NOT_VALID;
|
|
|
|
return API_CHECK_NEW_ACCOUNT_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************** 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];
|
|
int ReturnCode;
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
bool UsrFound;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_loginByUserPasswordKey;
|
|
|
|
/***** Allocate space for strings *****/
|
|
loginByUserPasswordKeyOut->wsKey = soap_malloc (soap,API_BYTES_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,WWW_MAX_BYTES_WWW + 1);
|
|
loginByUserPasswordKeyOut->userBirthday = soap_malloc (soap,Dat_LENGTH_YYYYMMDD + 1);
|
|
|
|
/***** 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)
|
|
return ReturnCode;
|
|
|
|
/***** 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
|
|
{
|
|
Str_RemoveLeadingArrobas (UsrIDNickOrEmail);
|
|
|
|
/* User has typed a nickname */
|
|
Gbl.Usrs.Me.UsrDat.UsrCod = Usr_DB_GetUsrCodFromNickPwd (UsrIDNickOrEmail,
|
|
userPassword);
|
|
}
|
|
else if (Mai_CheckIfEmailIsValid (UsrIDNickOrEmail)) // 2: It's an email
|
|
/* User has typed an email */
|
|
// TODO: Get only if email confirmed?
|
|
Gbl.Usrs.Me.UsrDat.UsrCod = Usr_DB_GetUsrCodFromEmailPwd (UsrIDNickOrEmail,
|
|
userPassword);
|
|
else // 3: It's not a nickname nor email
|
|
{
|
|
// 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) */
|
|
Gbl.Usrs.Me.UsrDat.UsrCod = Usr_DB_GetUsrCodFromIDPwd (UsrIDNickOrEmail,
|
|
userPassword);
|
|
else // String is not a valid user's nickname, email or ID
|
|
return soap_receiver_fault (soap,
|
|
"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
|
|
/***** Get user's data *****/
|
|
UsrFound = API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L); // Get some user's data from database
|
|
else
|
|
UsrFound = false;
|
|
|
|
if (UsrFound)
|
|
{
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
|
|
|
|
loginByUserPasswordKeyOut->userCode = (int) Gbl.Usrs.Me.UsrDat.UsrCod;
|
|
|
|
Str_Copy (loginByUserPasswordKeyOut->userNickname,
|
|
Gbl.Usrs.Me.UsrDat.Nickname,Nck_MAX_BYTES_NICK_WITHOUT_ARROBA);
|
|
|
|
if (Gbl.Usrs.Me.UsrDat.IDs.Num)
|
|
Str_Copy (loginByUserPasswordKeyOut->userID,
|
|
Gbl.Usrs.Me.UsrDat.IDs.List[0].ID, // TODO: What user's ID?
|
|
ID_MAX_BYTES_USR_ID);
|
|
|
|
Str_Copy (loginByUserPasswordKeyOut->userSurname1,
|
|
Gbl.Usrs.Me.UsrDat.Surname1,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
|
|
Str_Copy (loginByUserPasswordKeyOut->userSurname2,
|
|
Gbl.Usrs.Me.UsrDat.Surname2,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
|
|
Str_Copy (loginByUserPasswordKeyOut->userFirstname,
|
|
Gbl.Usrs.Me.UsrDat.FrstName,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,PhotoURL);
|
|
Str_Copy (loginByUserPasswordKeyOut->userPhoto,PhotoURL,WWW_MAX_BYTES_WWW);
|
|
|
|
Str_Copy (loginByUserPasswordKeyOut->userBirthday,
|
|
Gbl.Usrs.Me.UsrDat.Birthday.YYYYMMDD,Dat_LENGTH_YYYYMMDD);
|
|
|
|
loginByUserPasswordKeyOut->userRole =
|
|
API_RolRole_to_SvcRole[Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs];
|
|
|
|
/***** Generate a key used in subsequents calls to other web services *****/
|
|
return API_GenerateNewAPIKey (soap,
|
|
(long) loginByUserPasswordKeyOut->userCode,
|
|
loginByUserPasswordKeyOut->wsKey);
|
|
}
|
|
else
|
|
{
|
|
loginByUserPasswordKeyOut->userCode = -1;
|
|
loginByUserPasswordKeyOut->userID = NULL;
|
|
loginByUserPasswordKeyOut->userSurname1 = NULL;
|
|
loginByUserPasswordKeyOut->userSurname2 = NULL;
|
|
loginByUserPasswordKeyOut->userFirstname = NULL;
|
|
loginByUserPasswordKeyOut->userPhoto = NULL;
|
|
loginByUserPasswordKeyOut->userRole = 0;
|
|
|
|
return soap_receiver_fault (soap,
|
|
"Bad log in",
|
|
"User's ID or nickname don't exist or password is wrong");
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************** Login user by session ****************************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__loginBySessionKey (struct soap *soap,
|
|
char *sessionID,char *appKey, // input
|
|
struct swad__loginBySessionKeyOutput *loginBySessionKeyOut) // output
|
|
{
|
|
extern bool (*Hie_GetDataByCod[Hie_NUM_LEVELS]) (struct Hie_Node *Node);
|
|
int ReturnCode;
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
bool UsrFound;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_loginBySessionKey;
|
|
|
|
/***** Allocate space for strings *****/
|
|
loginBySessionKeyOut->wsKey = soap_malloc (soap,API_BYTES_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,WWW_MAX_BYTES_WWW + 1);
|
|
loginBySessionKeyOut->userBirthday = soap_malloc (soap,Dat_LENGTH_YYYYMMDD + 1);
|
|
loginBySessionKeyOut->degreeName = soap_malloc (soap,Nam_MAX_BYTES_FULL_NAME + 1);
|
|
loginBySessionKeyOut->courseName = soap_malloc (soap,Nam_MAX_BYTES_FULL_NAME + 1);
|
|
|
|
/***** 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';
|
|
loginBySessionKeyOut->userRole = Rol_UNK;
|
|
loginBySessionKeyOut->degreeName[0] = '\0';
|
|
loginBySessionKeyOut->courseName[0] = '\0';
|
|
|
|
/***** Get plugin code *****/
|
|
if ((ReturnCode = API_GetPlgCodFromAppKey (soap,appKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Check length of session identifier *****/
|
|
if (sessionID == NULL)
|
|
return soap_sender_fault (soap,
|
|
"SessionID is null",
|
|
"Login by session");
|
|
|
|
/***** Check session identifier coming from an external plugin *****/
|
|
if ((ReturnCode = API_CheckIdSession (soap,sessionID)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
// Now, we know that sessionID is a valid session identifier
|
|
/***** Query data of the session from database *****/
|
|
if (Ses_DB_GetSomeSessionData (&mysql_res,sessionID)) // Session found in table of sessions
|
|
{
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/***** Get course (row[2]) *****/
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = Str_ConvertStrCodToLongCod (row[2]);
|
|
Hie_GetDataByCod[Hie_CRS] (&Gbl.Hierarchy.Node[Hie_CRS]);
|
|
loginBySessionKeyOut->courseCode = (int) Gbl.Hierarchy.Node[Hie_CRS].HieCod;
|
|
Str_Copy (loginBySessionKeyOut->courseName,Gbl.Hierarchy.Node[Hie_CRS].FullName,
|
|
Nam_MAX_BYTES_FULL_NAME);
|
|
|
|
/***** Get user code (row[0]) *****/
|
|
Gbl.Usrs.Me.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
UsrFound = API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod); // Get some user's data from database
|
|
|
|
/***** Get degree (row[1]) *****/
|
|
Gbl.Hierarchy.Node[Hie_DEG].HieCod = Str_ConvertStrCodToLongCod (row[1]);
|
|
Hie_GetDataByCod[Hie_DEG] (&Gbl.Hierarchy.Node[Hie_DEG]);
|
|
loginBySessionKeyOut->degreeCode = (int) Gbl.Hierarchy.Node[Hie_DEG].HieCod;
|
|
Str_Copy (loginBySessionKeyOut->degreeName,Gbl.Hierarchy.Node[Hie_DEG].FullName,
|
|
Nam_MAX_BYTES_FULL_NAME);
|
|
}
|
|
else
|
|
UsrFound = false;
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
/***** Get degree of current course *****/
|
|
Gbl.Hierarchy.Node[Hie_DEG].HieCod = Crs_DB_GetDegCodOfCourseByCod (Gbl.Hierarchy.Node[Hie_CRS].HieCod);
|
|
|
|
if (UsrFound)
|
|
{
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
|
|
|
|
loginBySessionKeyOut->userCode = (int) Gbl.Usrs.Me.UsrDat.UsrCod;
|
|
|
|
Str_Copy (loginBySessionKeyOut->userNickname,Gbl.Usrs.Me.UsrDat.Nickname,
|
|
Nck_MAX_BYTES_NICK_WITHOUT_ARROBA);
|
|
|
|
if (Gbl.Usrs.Me.UsrDat.IDs.Num)
|
|
Str_Copy (loginBySessionKeyOut->userID,
|
|
Gbl.Usrs.Me.UsrDat.IDs.List[0].ID, // TODO: What user's ID?
|
|
ID_MAX_BYTES_USR_ID);
|
|
|
|
Str_Copy (loginBySessionKeyOut->userSurname1,
|
|
Gbl.Usrs.Me.UsrDat.Surname1,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
|
|
Str_Copy (loginBySessionKeyOut->userSurname2,
|
|
Gbl.Usrs.Me.UsrDat.Surname2,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
|
|
Str_Copy (loginBySessionKeyOut->userFirstname,
|
|
Gbl.Usrs.Me.UsrDat.FrstName,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,PhotoURL);
|
|
Str_Copy (loginBySessionKeyOut->userPhoto,PhotoURL,WWW_MAX_BYTES_WWW);
|
|
|
|
Str_Copy (loginBySessionKeyOut->userBirthday,
|
|
Gbl.Usrs.Me.UsrDat.Birthday.YYYYMMDD,Dat_LENGTH_YYYYMMDD);
|
|
|
|
loginBySessionKeyOut->userRole = API_RolRole_to_SvcRole[Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs];
|
|
|
|
/***** Generate a key used in subsequents calls to other web services *****/
|
|
return API_GenerateNewAPIKey (soap,
|
|
(long) loginBySessionKeyOut->userCode,
|
|
loginBySessionKeyOut->wsKey);
|
|
}
|
|
else
|
|
return soap_receiver_fault (soap,
|
|
"Bad session identifier",
|
|
"Session identifier does not exist in database");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************** 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,
|
|
char *wsKey,int courseCode, // input
|
|
struct swad__getAvailableRolesOutput *getAvailableRolesOut) // output
|
|
{
|
|
int ReturnCode;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getAvailableRoles;
|
|
|
|
/***** Initialize hierarchy *****/
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
Hie_InitHierarchy ();
|
|
|
|
/***** Default value returned on error *****/
|
|
getAvailableRolesOut->roles = 0; // error
|
|
|
|
/***** Check API (web service) key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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;
|
|
|
|
/***** Return available roles *****/
|
|
Rol_SetMyRoles ();
|
|
getAvailableRolesOut->roles = Gbl.Usrs.Me.Role.Available;
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********************** Send a new password by email ************************/
|
|
/*****************************************************************************/
|
|
|
|
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];
|
|
char NewRandomPlainPassword[Pwd_MAX_BYTES_PLAIN_PASSWORD + 1];
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getNewPassword;
|
|
|
|
/***** Default value returned on error *****/
|
|
getNewPasswordOut->success = 0; // error
|
|
|
|
/***** Get plugin code *****/
|
|
if ((ReturnCode = API_GetPlgCodFromAppKey (soap,appKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** 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
|
|
{
|
|
Str_RemoveLeadingArrobas (UsrIDNickOrEmail);
|
|
|
|
/* User has typed a nickname */
|
|
Gbl.Usrs.Me.UsrDat.UsrCod = Usr_DB_GetUsrCodFromNick (UsrIDNickOrEmail);
|
|
}
|
|
else if (Mai_CheckIfEmailIsValid (Gbl.Usrs.Me.UsrIdLogin)) // 2: It's an email
|
|
/* User has typed an email */
|
|
Gbl.Usrs.Me.UsrDat.UsrCod = Usr_DB_GetUsrCodFromEmail (UsrIDNickOrEmail);
|
|
else // 3: It's not a nickname nor email
|
|
{
|
|
// 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) */
|
|
Gbl.Usrs.Me.UsrDat.UsrCod = Usr_DB_GetUsrCodFromID (UsrIDNickOrEmail);
|
|
else // String is not a valid user's nickname, email or ID
|
|
return soap_receiver_fault (soap,
|
|
"Bad log in",
|
|
"User's email, nickname or ID don't exist");
|
|
}
|
|
|
|
/***** Get user's data from database *****/
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod > 0) // One unique user found in table of users' data
|
|
{
|
|
Usr_GetUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat, // Get my data
|
|
Usr_DONT_GET_PREFS,
|
|
Usr_DONT_GET_ROLE_IN_CRS);
|
|
|
|
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;
|
|
unsigned NumCrs;
|
|
unsigned NumCrss;
|
|
Rol_Role_t Role;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getCourses;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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;
|
|
|
|
/***** Query my courses from database *****/
|
|
NumCrss = Enr_DB_GetMyCoursesNames (&mysql_res);
|
|
|
|
getCoursesOut->numCourses =
|
|
getCoursesOut->coursesArray.__size = (int) NumCrss;
|
|
|
|
if (NumCrss == 0)
|
|
getCoursesOut->coursesArray.__ptr = NULL;
|
|
else // Courses found
|
|
{
|
|
getCoursesOut->coursesArray.__ptr = soap_malloc (soap,
|
|
(getCoursesOut->coursesArray.__size) *
|
|
sizeof (*(getCoursesOut->coursesArray.__ptr)));
|
|
|
|
for (NumCrs = 0;
|
|
NumCrs < NumCrss;
|
|
NumCrs++)
|
|
{
|
|
/* Get next course */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get course code (row[0]) */
|
|
getCoursesOut->coursesArray.__ptr[NumCrs].courseCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get course short name (row[1])
|
|
and course full name (row[2]) */
|
|
getCoursesOut->coursesArray.__ptr[NumCrs].courseShortName =
|
|
soap_malloc (soap,Nam_MAX_BYTES_SHRT_NAME + 1);
|
|
getCoursesOut->coursesArray.__ptr[NumCrs].courseFullName =
|
|
soap_malloc (soap,Nam_MAX_BYTES_FULL_NAME + 1);
|
|
Str_Copy (getCoursesOut->coursesArray.__ptr[NumCrs].courseShortName,
|
|
row[1],Nam_MAX_BYTES_SHRT_NAME);
|
|
Str_Copy (getCoursesOut->coursesArray.__ptr[NumCrs].courseFullName,
|
|
row[2],Nam_MAX_BYTES_FULL_NAME);
|
|
|
|
/* Get role (row[3]) */
|
|
if (sscanf (row[3],"%u",&Role) != 1) // Role in this course
|
|
Role = Rol_UNK;
|
|
getCoursesOut->coursesArray.__ptr[NumCrs].userRole = API_RolRole_to_SvcRole[Role];
|
|
}
|
|
}
|
|
|
|
/***** 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;
|
|
struct Syl_Syllabus Syllabus;
|
|
Inf_Type_t InfoType;
|
|
size_t Length;
|
|
struct Inf_FromDB FromDB;
|
|
int Result = SOAP_OK;
|
|
const char *NamesInWSForInfoType[Inf_NUM_TYPES] =
|
|
{
|
|
[Inf_INFORMATION ] = "introduction",
|
|
[Inf_TEACHING_GUIDE] = "guide",
|
|
[Inf_LECTURES ] = "lectures",
|
|
[Inf_PRACTICALS ] = "practicals",
|
|
[Inf_BIBLIOGRAPHY ] = "bibliography",
|
|
[Inf_FAQ ] = "FAQ",
|
|
[Inf_LINKS ] = "links",
|
|
[Inf_ASSESSMENT ] = "assessment",
|
|
};
|
|
const char *NamesInWSForInfoSrc[Inf_NUM_SOURCES] =
|
|
{
|
|
[Inf_NONE ] = "none",
|
|
[Inf_EDITOR ] = "editor",
|
|
[Inf_PLAIN_TEXT] = "plainText",
|
|
[Inf_RICH_TEXT ] = "richText",
|
|
[Inf_PAGE ] = "page",
|
|
[Inf_URL ] = "URL",
|
|
};
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getCourseInfo;
|
|
|
|
/***** Initialize hierarchy *****/
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
Hie_InitHierarchy ();
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course and group codes *****/
|
|
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod,
|
|
-1L)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get some of my data *****/
|
|
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Reset syllabus context *****/
|
|
Syl_ResetSyllabus (&Syllabus);
|
|
|
|
/***** Get info source *****/
|
|
for (InfoType = (Inf_Type_t) 0;
|
|
InfoType <= (Inf_Type_t) (Inf_NUM_TYPES - 1);
|
|
InfoType++)
|
|
if (!strcmp (infoType,NamesInWSForInfoType[InfoType]))
|
|
break;
|
|
if (InfoType == Inf_NUM_TYPES) // Not found!
|
|
return soap_receiver_fault (soap,
|
|
"Bad info type",
|
|
"Unknown requested info type");
|
|
Gbl.Crs.Info.Type = InfoType;
|
|
Inf_GetAndCheckInfoSrcFromDB (&Syllabus,
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod,
|
|
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);
|
|
|
|
/***** Get info text *****/
|
|
getCourseInfo->infoTxt = NULL;
|
|
switch (FromDB.Src)
|
|
{
|
|
case Inf_NONE: // No info available
|
|
break;
|
|
case Inf_EDITOR: // Internal editor (only for syllabus)
|
|
switch (Gbl.Crs.Info.Type)
|
|
{
|
|
case Inf_LECTURES: // Syllabus (lectures)
|
|
case Inf_PRACTICALS: // Syllabys (practicals)
|
|
Result = API_WriteSyllabusIntoHTMLBuffer (soap,&Syllabus,&(getCourseInfo->infoTxt));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case Inf_PLAIN_TEXT: // Plain text
|
|
case Inf_RICH_TEXT: // Rich text (not yet available)
|
|
Result = API_WritePlainTextIntoHTMLBuffer (soap,&(getCourseInfo->infoTxt));
|
|
break;
|
|
case Inf_PAGE: // Web page hosted in SWAD server
|
|
Result = API_WritePageIntoHTMLBuffer (soap,&(getCourseInfo->infoTxt));
|
|
break;
|
|
case Inf_URL: // Link to a web page
|
|
getCourseInfo->infoTxt = soap_malloc (soap,WWW_MAX_BYTES_WWW + 1);
|
|
Inf_WriteURLIntoTxtBuffer (getCourseInfo->infoTxt);
|
|
break;
|
|
}
|
|
|
|
/***** Return empty text if pointer is null *****/
|
|
if (getCourseInfo->infoTxt == NULL)
|
|
{
|
|
getCourseInfo->infoTxt = soap_malloc (soap,1);
|
|
getCourseInfo->infoTxt[0] = '\0';
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************** Write the syllabus into a temporary HTML file ****************/
|
|
/*****************************************************************************/
|
|
|
|
static int API_WriteSyllabusIntoHTMLBuffer (struct soap *soap,
|
|
struct Syl_Syllabus *Syllabus,
|
|
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 *****/
|
|
Syl_LoadListItemsSyllabusIntoMemory (Syllabus,Gbl.Hierarchy.Node[Hie_CRS].HieCod);
|
|
|
|
if (Syl_LstItemsSyllabus.NumItems)
|
|
{
|
|
/***** Create a unique name for the file *****/
|
|
snprintf (FileNameHTMLTmp,sizeof (FileNameHTMLTmp),"%s/%s_syllabus.html",
|
|
Cfg_PATH_OUT_PRIVATE,Cry_GetUniqueNameEncrypted ());
|
|
|
|
/***** 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)
|
|
{
|
|
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];
|
|
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.Node[Hie_CRS].HieCod,Gbl.Crs.Info.Type,
|
|
TxtHTML,NULL);
|
|
|
|
if (TxtHTML[0])
|
|
{
|
|
/***** Create a unique name for the file *****/
|
|
snprintf (FileNameHTMLTmp,sizeof (FileNameHTMLTmp),"%s/%s_info.html",
|
|
Cfg_PATH_OUT_PRIVATE,Cry_GetUniqueNameEncrypted ());
|
|
|
|
/***** 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]);
|
|
fprintf (FileHTMLTmp,"<body>\n"
|
|
"<div class=\"LM DAT_%s\">\n",The_GetSuffix ());
|
|
|
|
/***** 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,Str_DONT_REMOVE_SPACES);
|
|
ALn_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)
|
|
{
|
|
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.Node[Hie_CRS].HieCod,Gbl.Crs.Info.Type,PathRelDirHTML);
|
|
|
|
/***** Open file with web page *****/
|
|
/* 1. Check if index.html exists */
|
|
snprintf (PathRelFileHTML,sizeof (PathRelFileHTML),"%s/index.html",
|
|
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",
|
|
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 ();
|
|
|
|
/* 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)
|
|
{
|
|
fclose (FileHTML);
|
|
Err_NotEnoughMemoryExit ();
|
|
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;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************* Get users in a course (and optionally in groups) **************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getUsers (struct soap *soap,
|
|
char *wsKey,int courseCode,char *groups,int userRole, // input
|
|
struct swad__getUsersOutput *getUsersOut) // output
|
|
{
|
|
int ReturnCode;
|
|
Rol_Role_t Role;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getUsers;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (courseCode > 0) ? (long) courseCode :
|
|
-1L;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course *****/
|
|
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod,
|
|
-1L)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get some of my data *****/
|
|
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Get degree of current course *****/
|
|
Gbl.Hierarchy.Node[Hie_DEG].HieCod = Crs_DB_GetDegCodOfCourseByCod (Gbl.Hierarchy.Node[Hie_CRS].HieCod);
|
|
|
|
/***** Check requested users' role *****/
|
|
if (userRole != API_ROLE_STUDENT && // Students
|
|
userRole != API_ROLE_TEACHER) // Teachers
|
|
return soap_sender_fault (soap,
|
|
"Bad requested users' type",
|
|
"User roles allowed are 2 (students) or 3 (teachers)");
|
|
Role = API_SvcRole_to_RolRole[userRole];
|
|
|
|
/***** Create a list of groups selected *****/
|
|
API_GetLstGrpsSel (groups);
|
|
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps)
|
|
/***** Get list of groups types and groups in current course *****/
|
|
Grp_GetListGrpTypesInCurrentCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
|
|
|
|
/***** Get list of users *****/
|
|
Usr_GetListUsrs (Hie_CRS,Role);
|
|
API_CopyListUsers (soap,
|
|
Role,getUsersOut);
|
|
Usr_FreeUsrsList (Role);
|
|
|
|
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps)
|
|
{
|
|
/***** 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;
|
|
struct Sch_Search Search;
|
|
char SearchQuery[Sch_MAX_BYTES_SEARCH_QUERY + 1];
|
|
Rol_Role_t Role;
|
|
bool FilterTooShort = false;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_findUsers;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (courseCode > 0) ? (long) courseCode :
|
|
-1L;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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");
|
|
|
|
if (Gbl.Hierarchy.Level == Hie_CRS) // Course selected
|
|
/***** Check course *****/
|
|
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod,
|
|
-1L)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get some of my data *****/
|
|
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
if (Gbl.Hierarchy.Level == Hie_CRS) // Course selected
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
if (Gbl.Hierarchy.Level == Hie_CRS)
|
|
/***** Get degree of current course *****/
|
|
Gbl.Hierarchy.Node[Hie_DEG].HieCod = Crs_DB_GetDegCodOfCourseByCod (Gbl.Hierarchy.Node[Hie_CRS].HieCod);
|
|
|
|
/***** Check requested users' role *****/
|
|
if (userRole < API_ROLE_UNKNOWN ||
|
|
userRole > API_ROLE_TEACHER)
|
|
return soap_sender_fault (soap,
|
|
"Bad requested users' type",
|
|
"User roles allowed are 0 (all), 1 (guests), 2 (students) or 3 (teachers)");
|
|
Role = API_SvcRole_to_RolRole[userRole];
|
|
|
|
/***** Query users beloging to course or group from database *****/
|
|
Search.WhatToSearch = Sch_SEARCH_USERS;
|
|
Str_Copy (Search.Str,filter,sizeof (Search.Str) - 1);
|
|
|
|
if (Search.Str[0]) // Search some users
|
|
{
|
|
Gbl.Scope.Current = (Gbl.Hierarchy.Level == Hie_CRS) ? Hie_CRS :
|
|
Hie_SYS;
|
|
if (Sch_BuildSearchQuery (SearchQuery,&Search,
|
|
"CONCAT_WS(' ',FirstName,Surname1,Surname2)",
|
|
NULL,NULL))
|
|
{
|
|
/***** Create temporary table with candidate users *****/
|
|
// Search is faster (aproximately x2) using temporary tables
|
|
Usr_DB_CreateTmpTableAndSearchCandidateUsrs (SearchQuery);
|
|
|
|
/***** Search for users *****/
|
|
Usr_SearchListUsrs (Role);
|
|
API_CopyListUsers (soap,
|
|
Role,getUsersOut);
|
|
Usr_FreeUsrsList (Role);
|
|
|
|
/***** Drop temporary table with candidate users *****/
|
|
Usr_DB_DropTmpTableWithCandidateUsrs ();
|
|
}
|
|
else
|
|
FilterTooShort = true;
|
|
}
|
|
else
|
|
FilterTooShort = true;
|
|
|
|
/***** Return error in filter? *****/
|
|
if (FilterTooShort)
|
|
{
|
|
getUsersOut->numUsers = -1; // < 0 ==> filter too short
|
|
getUsersOut->usersArray.__size = 0;
|
|
getUsersOut->usersArray.__ptr = NULL;
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Copy users from list **************************/
|
|
/*****************************************************************************/
|
|
|
|
static void API_CopyListUsers (struct soap *soap,
|
|
Rol_Role_t Role,
|
|
struct swad__getUsersOutput *getUsersOut)
|
|
{
|
|
unsigned NumUsrs;
|
|
unsigned NumUsr;
|
|
struct Usr_Data UsrDat;
|
|
Usr_Can_t ICanSeeUsrID;
|
|
|
|
/***** Initialize result *****/
|
|
getUsersOut->numUsers = 0;
|
|
getUsersOut->usersArray.__size = 0;
|
|
getUsersOut->usersArray.__ptr = NULL;
|
|
|
|
NumUsrs = Gbl.Usrs.LstUsrs[Role].NumUsrs;
|
|
if (NumUsrs)
|
|
{
|
|
getUsersOut->numUsers = (int) NumUsrs;
|
|
getUsersOut->usersArray.__size = (int) NumUsrs;
|
|
getUsersOut->usersArray.__ptr = soap_malloc (soap,
|
|
(getUsersOut->usersArray.__size) *
|
|
sizeof (*(getUsersOut->usersArray.__ptr)));
|
|
|
|
/***** Initialize structure with user's data *****/
|
|
Usr_UsrDataConstructor (&UsrDat);
|
|
|
|
/***** List data of users *****/
|
|
for (NumUsr = 0;
|
|
NumUsr < NumUsrs;
|
|
NumUsr++)
|
|
{
|
|
/* Copy user's basic data from list */
|
|
Usr_CopyBasicUsrDataFromList (&UsrDat,&Gbl.Usrs.LstUsrs[Role].Lst[NumUsr]);
|
|
|
|
/* Get list of user's IDs */
|
|
ID_GetListIDsFromUsrCod (&UsrDat);
|
|
ICanSeeUsrID = ID_ICanSeeOtherUsrIDs (&UsrDat);
|
|
|
|
/* Get nickname */
|
|
Nck_DB_GetNicknameFromUsrCod (UsrDat.UsrCod,UsrDat.Nickname);
|
|
|
|
/* Copy user's data into output structure */
|
|
API_CopyUsrData (soap,
|
|
&(getUsersOut->usersArray.__ptr[NumUsr]),
|
|
&UsrDat,
|
|
ICanSeeUsrID);
|
|
}
|
|
|
|
/***** Free memory used for user's data *****/
|
|
Usr_UsrDataDestructor (&UsrDat);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************** 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;
|
|
unsigned NumGrpTyp;
|
|
unsigned NumGrpTypes;
|
|
long OpenTime;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getGroupTypes;
|
|
|
|
/***** Initialize hierarchy *****/
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
Hie_InitHierarchy ();
|
|
|
|
/***** Open groups of this course that must be opened
|
|
if open time is in the past *****/
|
|
Grp_OpenGroupsAutomatically ();
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Query group types in a course from database *****/
|
|
NumGrpTypes = Grp_DB_GetAllGrpTypesInCrs (&mysql_res,courseCode);
|
|
|
|
getGroupTypesOut->numGroupTypes = (int) NumGrpTypes;
|
|
getGroupTypesOut->groupTypesArray.__size = (int) NumGrpTypes;
|
|
|
|
if (NumGrpTypes == 0)
|
|
getGroupTypesOut->groupTypesArray.__ptr = NULL;
|
|
else // Groups found
|
|
{
|
|
getGroupTypesOut->groupTypesArray.__ptr = soap_malloc (soap,
|
|
(getGroupTypesOut->groupTypesArray.__size) *
|
|
sizeof (*(getGroupTypesOut->groupTypesArray.__ptr)));
|
|
|
|
for (NumGrpTyp = 0;
|
|
NumGrpTyp < NumGrpTypes;
|
|
NumGrpTyp++)
|
|
{
|
|
/* Get next group */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get group type code (row[0]) */
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumGrpTyp].groupTypeCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get group type name (row[1]) */
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumGrpTyp].groupTypeName =
|
|
soap_malloc (soap,Grp_MAX_BYTES_GROUP_TYPE_NAME + 1);
|
|
Str_Copy (getGroupTypesOut->groupTypesArray.__ptr[NumGrpTyp].groupTypeName,
|
|
row[1],Grp_MAX_BYTES_GROUP_TYPE_NAME);
|
|
|
|
/* Get whether enrolment is mandatory ('Y') or voluntary ('N') (row[2]) */
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumGrpTyp].mandatory = (row[2][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get whether user can enrol in multiple groups ('Y') or only in one group ('N') (row[3]) */
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumGrpTyp].multiple = (row[3][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
// Whether groups of this type must be opened (row[4]) ignored here
|
|
|
|
/* Get time of opening (row[5]) */
|
|
OpenTime = 0L;
|
|
if (row[5])
|
|
sscanf (row[5],"%ld",&OpenTime);
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumGrpTyp].openTime = OpenTime;
|
|
|
|
// Number of groups of this type (row[6]) ignored here
|
|
}
|
|
}
|
|
|
|
/***** 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 NumGrps;
|
|
unsigned NumGrp;
|
|
long GrpCod;
|
|
unsigned MaxStudents;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getGroups;
|
|
|
|
/***** Initialize hierarchy *****/
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
Hie_InitHierarchy ();
|
|
|
|
/***** Open groups of this course that must be opened
|
|
if open time is in the past *****/
|
|
Grp_OpenGroupsAutomatically ();
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Query groups in a course from database *****/
|
|
NumGrps = Grp_DB_GetGrpsInCrs (&mysql_res,courseCode);
|
|
|
|
getGroupsOut->numGroups = (int) NumGrps;
|
|
getGroupsOut->groupsArray.__size = (int) NumGrps;
|
|
|
|
if (NumGrps == 0)
|
|
getGroupsOut->groupsArray.__ptr = NULL;
|
|
else // Groups found
|
|
{
|
|
getGroupsOut->groupsArray.__ptr = soap_malloc (soap,
|
|
(getGroupsOut->groupsArray.__size) *
|
|
sizeof (*(getGroupsOut->groupsArray.__ptr)));
|
|
|
|
for (NumGrp = 0;
|
|
NumGrp < NumGrps;
|
|
NumGrp++)
|
|
{
|
|
/* Get next group */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get group type code (row[0]) */
|
|
getGroupsOut->groupsArray.__ptr[NumGrp].groupTypeCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get group type name (row[1]) */
|
|
getGroupsOut->groupsArray.__ptr[NumGrp].groupTypeName =
|
|
soap_malloc (soap,Grp_MAX_BYTES_GROUP_TYPE_NAME + 1);
|
|
Str_Copy (getGroupsOut->groupsArray.__ptr[NumGrp].groupTypeName,row[1],
|
|
Grp_MAX_BYTES_GROUP_TYPE_NAME);
|
|
|
|
/* Get group code (row[2]) */
|
|
GrpCod = Str_ConvertStrCodToLongCod (row[2]);
|
|
getGroupsOut->groupsArray.__ptr[NumGrp].groupCode = (int) GrpCod;
|
|
|
|
/* Get group name (row[3]) */
|
|
getGroupsOut->groupsArray.__ptr[NumGrp].groupName =
|
|
soap_malloc (soap,Grp_MAX_BYTES_GROUP_NAME + 1);
|
|
Str_Copy (getGroupsOut->groupsArray.__ptr[NumGrp].groupName,row[3],
|
|
Grp_MAX_BYTES_GROUP_NAME);
|
|
|
|
/* Get max number of students of group (row[4]) and number of current students */
|
|
MaxStudents = Grp_ConvertToNumMaxStdsGrp (row[4]);
|
|
getGroupsOut->groupsArray.__ptr[NumGrp].maxStudents = (MaxStudents > Grp_MAX_STUDENTS_IN_A_GROUP) ? -1 :
|
|
(int) MaxStudents;
|
|
|
|
/* Get number of current students */
|
|
getGroupsOut->groupsArray.__ptr[NumGrp].numStudents = (int) Grp_DB_CountNumUsrsInGrp (Rol_STD,GrpCod);
|
|
|
|
/* Get whether group is open ('Y') or closed ('N') (row[5]) */
|
|
getGroupsOut->groupsArray.__ptr[NumGrp].open = (row[5][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get whether group have file zones ('Y') or not ('N') (row[6]) */
|
|
getGroupsOut->groupsArray.__ptr[NumGrp].fileZones = (row[6][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get whether I belong to this group or not */
|
|
getGroupsOut->groupsArray.__ptr[NumGrp].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;
|
|
char LongStr[Cns_MAX_DIGITS_LONG + 1];
|
|
unsigned NumGrps;
|
|
unsigned NumGrp;
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
long GrpCod;
|
|
unsigned MaxStudents;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_sendMyGroups;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Get the group codes which I want to join to *****/
|
|
LstGrpsIWant.NumGrps = 0;
|
|
LstGrpsIWant.GrpCods = NULL;
|
|
|
|
if (myGroups[0])
|
|
{
|
|
/***** Count number of desired groups *****/
|
|
for (NumGrp = 0, Ptr = myGroups;
|
|
*Ptr;
|
|
NumGrp++)
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DIGITS_LONG);
|
|
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 ();
|
|
for (NumGrp = 0, Ptr = myGroups;
|
|
*Ptr;
|
|
NumGrp++)
|
|
{
|
|
/* Find next string in text until comma (leading and trailing spaces are removed) */
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DIGITS_LONG);
|
|
LstGrpsIWant.GrpCods[NumGrp] = Str_ConvertStrCodToLongCod (LongStr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***** 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 *****/
|
|
NumGrps = Grp_DB_GetGrpsInCrs (&mysql_res,courseCode);
|
|
|
|
SendMyGroupsOut->numGroups = (int) NumGrps;
|
|
SendMyGroupsOut->groupsArray.__size = (int) NumGrps;
|
|
|
|
if (NumGrps == 0)
|
|
SendMyGroupsOut->groupsArray.__ptr = NULL;
|
|
else // Groups found
|
|
{
|
|
SendMyGroupsOut->groupsArray.__ptr = soap_malloc (soap,
|
|
(SendMyGroupsOut->groupsArray.__size) *
|
|
sizeof (*(SendMyGroupsOut->groupsArray.__ptr)));
|
|
|
|
for (NumGrp = 0;
|
|
NumGrp < NumGrps;
|
|
NumGrp++)
|
|
{
|
|
/* Get next group */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get group type code (row[0]) */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumGrp].groupTypeCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get group type name (row[1]) */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumGrp].groupTypeName =
|
|
soap_malloc (soap,Grp_MAX_BYTES_GROUP_TYPE_NAME + 1);
|
|
Str_Copy (SendMyGroupsOut->groupsArray.__ptr[NumGrp].groupTypeName,row[1],
|
|
Grp_MAX_BYTES_GROUP_TYPE_NAME);
|
|
|
|
/* Get group code (row[2]) */
|
|
GrpCod = Str_ConvertStrCodToLongCod (row[2]);
|
|
SendMyGroupsOut->groupsArray.__ptr[NumGrp].groupCode = (int) GrpCod;
|
|
|
|
/* Get group name (row[3]) */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumGrp].groupName =
|
|
soap_malloc (soap,Grp_MAX_BYTES_GROUP_NAME + 1);
|
|
Str_Copy (SendMyGroupsOut->groupsArray.__ptr[NumGrp].groupName,row[3],
|
|
Grp_MAX_BYTES_GROUP_NAME);
|
|
|
|
/* Get max number of students of group (row[4]) and number of current students */
|
|
MaxStudents = Grp_ConvertToNumMaxStdsGrp (row[4]);
|
|
SendMyGroupsOut->groupsArray.__ptr[NumGrp].maxStudents = (MaxStudents > Grp_MAX_STUDENTS_IN_A_GROUP) ? -1 :
|
|
(int) MaxStudents;
|
|
|
|
/* Get number of current students */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumGrp].numStudents = (int) Grp_DB_CountNumUsrsInGrp (Rol_STD,GrpCod);
|
|
|
|
/* Get whether group is open ('Y') or closed ('N') (row[5])
|
|
and whether group have file zones ('Y') or not ('N') (row[6]) */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumGrp].open = (row[5][0] == 'Y') ? 1 :
|
|
0;
|
|
SendMyGroupsOut->groupsArray.__ptr[NumGrp].fileZones = (row[6][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get whether I belong to this group or not */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumGrp].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 *************/
|
|
/*****************************************************************************/
|
|
|
|
static void API_CopyUsrData (struct soap *soap,
|
|
struct swad__user *Usr,struct Usr_Data *UsrDat,
|
|
Usr_Can_t ICanSeeUsrID)
|
|
{
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
const char *FirstID;
|
|
size_t Length;
|
|
|
|
/* Copy user's code */
|
|
Usr->userCode = UsrDat->UsrCod;
|
|
|
|
/* Copy user's nickname */
|
|
Length = strlen (UsrDat->Nickname);
|
|
Usr->userNickname = soap_malloc (soap,Length + 1);
|
|
Str_Copy (Usr->userNickname,UsrDat->Nickname,Length);
|
|
|
|
/* Copy user's first ID */
|
|
if (ICanSeeUsrID == Usr_CAN && UsrDat->IDs.List)
|
|
FirstID = UsrDat->IDs.List[0].ID;
|
|
else // Hide user's ID
|
|
FirstID = "********";
|
|
Length = strlen (FirstID);
|
|
Usr->userID = soap_malloc (soap,Length + 1);
|
|
Str_Copy (Usr->userID,FirstID,Length);
|
|
|
|
/* Copy user's surname1 */
|
|
Length = strlen (UsrDat->Surname1);
|
|
Usr->userSurname1 = soap_malloc (soap,Length + 1);
|
|
Str_Copy (Usr->userSurname1,UsrDat->Surname1,Length);
|
|
|
|
/* Copy user's surname2 */
|
|
Length = strlen (UsrDat->Surname2);
|
|
Usr->userSurname2 = soap_malloc (soap,Length + 1);
|
|
Str_Copy (Usr->userSurname2,UsrDat->Surname2,Length);
|
|
|
|
/* Copy user's first name */
|
|
Length = strlen (UsrDat->FrstName);
|
|
Usr->userFirstname = soap_malloc (soap,Length + 1);
|
|
Str_Copy (Usr->userFirstname,UsrDat->FrstName,Length);
|
|
|
|
/* User's photo URL */
|
|
Pho_BuildLinkToPhoto (UsrDat,PhotoURL);
|
|
Length = strlen (PhotoURL);
|
|
Usr->userPhoto = soap_malloc (soap,Length + 1);
|
|
Str_Copy (Usr->userPhoto,PhotoURL,Length);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************** 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;
|
|
unsigned NumAttEvents;
|
|
unsigned NumAttEvent;
|
|
struct Att_Event Event;
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
size_t Length;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getAttendanceEvents;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check if I am a teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
/***** Query list of attendance events *****/
|
|
NumAttEvents = Att_DB_GetAllEventsData (&mysql_res,courseCode);
|
|
|
|
getAttendanceEventsOut->eventsArray.__size =
|
|
getAttendanceEventsOut->numEvents = (int) NumAttEvents;
|
|
|
|
if (getAttendanceEventsOut->numEvents == 0)
|
|
getAttendanceEventsOut->eventsArray.__ptr = NULL;
|
|
else // Events found
|
|
{
|
|
getAttendanceEventsOut->eventsArray.__ptr = soap_malloc (soap,
|
|
(getAttendanceEventsOut->eventsArray.__size) *
|
|
sizeof (*(getAttendanceEventsOut->eventsArray.__ptr)));
|
|
|
|
for (NumAttEvent = 0;
|
|
NumAttEvent < NumAttEvents;
|
|
NumAttEvent++)
|
|
{
|
|
/* Get next group */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get attendance event (except Txt) */
|
|
Att_GetEventDataFromRow (row,&Event);
|
|
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].attendanceEventCode = (int) Event.AttCod;
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].hidden = (Event.HiddenOrVisible == HidVis_HIDDEN) ? 1 :
|
|
0;
|
|
Gbl.Usrs.Other.UsrDat.UsrCod = Event.UsrCod;
|
|
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod)) // Get some user's data from database
|
|
{
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname1 =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname1,
|
|
Gbl.Usrs.Other.UsrDat.Surname1,Length);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname2 =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname2,
|
|
Gbl.Usrs.Other.UsrDat.Surname2,Length);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.FrstName);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userFirstname =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userFirstname,
|
|
Gbl.Usrs.Other.UsrDat.FrstName,Length);
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
|
|
Length = strlen (PhotoURL);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userPhoto =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userPhoto,
|
|
PhotoURL,Length);
|
|
}
|
|
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;
|
|
}
|
|
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].startTime = (int) Event.TimeUTC[Dat_STR_TIME];
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].endTime = (int) Event.TimeUTC[Dat_END_TIME];
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].commentsTeachersVisible = (Event.ClosedOrOpen == CloOpe_OPEN) ? 1 :
|
|
0;
|
|
Length = strlen (Event.Title);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].title =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].title,
|
|
Event.Title,Length);
|
|
|
|
/* Get Txt (row[9]) */
|
|
Length = strlen (row[9]);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].text =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].text,
|
|
row[9],Length);
|
|
|
|
/* Get list of groups for this attendance event */
|
|
API_GetListGrpsInAttendanceEventFromDB (soap,
|
|
Event.AttCod,
|
|
&(getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].groups));
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**************** Get lists of groups of an attendance event *****************/
|
|
/*****************************************************************************/
|
|
|
|
static void API_GetListGrpsInAttendanceEventFromDB (struct soap *soap,
|
|
long AttCod,char **ListGroups)
|
|
{
|
|
MYSQL_RES *mysql_res;
|
|
long NumGrps;
|
|
long NumGrp;
|
|
long GrpCod;
|
|
char GrpCodStr[Cns_MAX_DIGITS_LONG + 1];
|
|
size_t Length;
|
|
|
|
/***** Get list of groups *****/
|
|
if ((NumGrps = Att_DB_GetGrpCodsAssociatedToEvent (&mysql_res,AttCod))) // Events found
|
|
{
|
|
Length = NumGrps * (10 + 1) - 1;
|
|
*ListGroups = soap_malloc (soap,Length + 1);
|
|
(*ListGroups)[0] = '\0';
|
|
|
|
for (NumGrp = 0;
|
|
NumGrp < NumGrps;
|
|
NumGrp++)
|
|
{
|
|
/* Get next group */
|
|
GrpCod = DB_GetNextCode (mysql_res);
|
|
snprintf (GrpCodStr,sizeof (GrpCodStr),NumGrp ? ",%ld" :
|
|
"%ld",
|
|
GrpCod);
|
|
Str_Concat (*ListGroups,GrpCodStr,Length);
|
|
}
|
|
}
|
|
else
|
|
*ListGroups = NULL;
|
|
|
|
/***** 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;
|
|
struct Att_Event Event;
|
|
bool ItsANewAttEvent;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_sendAttendanceEvent;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check if I am a teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
/**** Get data of attendance event *****/
|
|
/* Event code */
|
|
Event.AttCod = (long) attendanceEventCode;
|
|
|
|
/* Course code */
|
|
if (Event.AttCod > 0) // The event already exists
|
|
{
|
|
Att_GetEventDataByCod (&Event);
|
|
if (Event.CrsCod != (long) courseCode)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Attendance event does not belong to course");
|
|
ItsANewAttEvent = false;
|
|
}
|
|
else
|
|
{
|
|
ItsANewAttEvent = true;
|
|
Event.CrsCod = (long) courseCode;
|
|
}
|
|
|
|
/* Is event hidden? */
|
|
Event.HiddenOrVisible = (hidden ? HidVis_HIDDEN :
|
|
HidVis_VISIBLE);
|
|
|
|
/* User's code (really not used) */
|
|
Event.UsrCod = Gbl.Usrs.Me.UsrDat.UsrCod;
|
|
|
|
/* startTime and endTime */
|
|
Event.TimeUTC[Dat_STR_TIME] = (time_t) startTime;
|
|
Event.TimeUTC[Dat_END_TIME] = (time_t) endTime;
|
|
|
|
/* Are teacher's comments visible? */
|
|
Event.CommentTchVisible = (commentsTeachersVisible ? true :
|
|
false);
|
|
|
|
/* Title */
|
|
if (!title[0])
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Title of attendance event is empty");
|
|
Str_Copy (Event.Title,title,sizeof (Event.Title) - 1);
|
|
|
|
/* Create a list of groups selected */
|
|
API_GetLstGrpsSel (groups);
|
|
|
|
/***** Create or update attendance event *****/
|
|
if (ItsANewAttEvent)
|
|
Att_CreateEvent (&Event,text); // Add new attendance event to database
|
|
else
|
|
Att_UpdateEvent (&Event,text); // Modify existing attendance event
|
|
|
|
/***** Free memory for list of selected groups *****/
|
|
Grp_FreeListCodSelectedGrps ();
|
|
|
|
sendAttendanceEventOut->attendanceEventCode = Event.AttCod;
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************ Remove an attendance event *************************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__removeAttendanceEvent (struct soap *soap,
|
|
char *wsKey,int attendanceEventCode, // input
|
|
struct swad__removeAttendanceEventOutput *removeAttendanceEventOut) // output
|
|
{
|
|
int ReturnCode;
|
|
struct Att_Event Event;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_removeAttendanceEvent;
|
|
removeAttendanceEventOut->attendanceEventCode = 0;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 data of attendance event *****/
|
|
/* Event code */
|
|
Event.AttCod = (long) attendanceEventCode;
|
|
|
|
/* Course code */
|
|
if (Event.AttCod > 0) // The event already exists
|
|
{
|
|
Att_GetEventDataByCod (&Event);
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = Event.CrsCod;
|
|
}
|
|
else
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Attendance event does not exist");
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check if I am a teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
/***** Remove the attendance event from database *****/
|
|
Att_RemoveEventFromDB (Event.AttCod);
|
|
|
|
removeAttendanceEventOut->attendanceEventCode = Event.AttCod;
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************** Create a list of groups selected *********************/
|
|
/*****************************************************************************/
|
|
|
|
static void API_GetLstGrpsSel (const char *Groups)
|
|
{
|
|
const char *Ptr;
|
|
char LongStr[Cns_MAX_DIGITS_LONG + 1];
|
|
unsigned NumGrp;
|
|
|
|
/***** Count number of groups *****/
|
|
for (Ptr = Groups, NumGrp = 0;
|
|
*Ptr;
|
|
NumGrp++)
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DIGITS_LONG);
|
|
Gbl.Crs.Grps.LstGrpsSel.NumGrps = NumGrp;
|
|
|
|
/***** Create a list of groups selected *****/
|
|
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps)
|
|
{
|
|
// Here NestedCalls is always 0
|
|
Gbl.Crs.Grps.LstGrpsSel.NestedCalls++;
|
|
// 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 ();
|
|
|
|
for (Ptr = Groups, NumGrp = 0;
|
|
*Ptr;
|
|
)
|
|
{
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DIGITS_LONG);
|
|
Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrp] = Str_ConvertStrCodToLongCod (LongStr);
|
|
if (Grp_DB_CheckIfGrpBelongsToCrs (Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrp],Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
NumGrp++;
|
|
}
|
|
Gbl.Crs.Grps.LstGrpsSel.NumGrps = NumGrp; // Update number of groups
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********** 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;
|
|
struct Att_Event Event;
|
|
bool AttEventIsAsociatedToGrps;
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumUsrs;
|
|
unsigned NumUsr;
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
size_t Length;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getAttendanceUsers;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course of this attendance event *****/
|
|
Event.AttCod = (long) attendanceEventCode;
|
|
Att_GetEventDataByCod (&Event);
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = Event.CrsCod;
|
|
|
|
/***** Get some of my data *****/
|
|
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check if I am a teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
/***** Query list of attendance users *****/
|
|
AttEventIsAsociatedToGrps = Grp_DB_CheckIfAssociatedToGrps ("att_groups",
|
|
"AttCod",
|
|
Event.AttCod);
|
|
|
|
NumUsrs = Att_DB_GetListUsrsInEvent (&mysql_res,Event.AttCod,AttEventIsAsociatedToGrps);
|
|
|
|
getAttendanceUsersOut->numUsers =
|
|
getAttendanceUsersOut->usersArray.__size = (int) NumUsrs;
|
|
|
|
if (NumUsrs) // Users found
|
|
{
|
|
getAttendanceUsersOut->usersArray.__ptr = soap_malloc (soap,
|
|
(getAttendanceUsersOut->usersArray.__size) *
|
|
sizeof (*(getAttendanceUsersOut->usersArray.__ptr)));
|
|
|
|
for (NumUsr = 0;
|
|
NumUsr < NumUsrs;
|
|
NumUsr++)
|
|
{
|
|
/* 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[NumUsr].userCode = (int) Gbl.Usrs.Other.UsrDat.UsrCod;
|
|
|
|
/* Get user's data */
|
|
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,-1L)) // Get some user's data from database
|
|
{
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Nickname);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userNickname =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userNickname,
|
|
Gbl.Usrs.Other.UsrDat.Nickname,Length);
|
|
|
|
if (Gbl.Usrs.Other.UsrDat.IDs.Num)
|
|
{
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.IDs.List[0].ID); // TODO: What user's ID?
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userID =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userID,
|
|
Gbl.Usrs.Other.UsrDat.IDs.List[0].ID,Length);
|
|
}
|
|
else
|
|
{
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userID =
|
|
soap_malloc (soap,1);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userID[0] = '\0';
|
|
}
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname1 =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname1,
|
|
Gbl.Usrs.Other.UsrDat.Surname1,Length);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname2 =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname2,
|
|
Gbl.Usrs.Other.UsrDat.Surname2,Length);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.FrstName);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userFirstname =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userFirstname,
|
|
Gbl.Usrs.Other.UsrDat.FrstName,Length);
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
|
|
Length = strlen (PhotoURL);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userPhoto =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getAttendanceUsersOut->usersArray.__ptr[NumUsr].userPhoto,
|
|
PhotoURL,Length);
|
|
}
|
|
else
|
|
{
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userNickname = NULL;
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userID = NULL;
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname1 = NULL;
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userSurname2 = NULL;
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userFirstname = NULL;
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].userPhoto = NULL;
|
|
}
|
|
|
|
/* Get if user is present or not (row[1]) */
|
|
getAttendanceUsersOut->usersArray.__ptr[NumUsr].present = (row[1][0] == 'Y') ? 1 :
|
|
0;
|
|
}
|
|
}
|
|
else
|
|
getAttendanceUsersOut->usersArray.__ptr = NULL;
|
|
|
|
/***** 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;
|
|
struct Att_Event Event;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_sendAttendanceUsers;
|
|
|
|
/***** Initialize output *****/
|
|
sendAttendanceUsersOut->success = 0;
|
|
sendAttendanceUsersOut->numUsers = 0;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course of this attendance event *****/
|
|
Event.AttCod = (long) attendanceEventCode;
|
|
if (!Att_GetEventDataByCod (&Event))
|
|
return SOAP_OK; // return with success = 0
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = Event.CrsCod;
|
|
|
|
/***** Get some of my data *****/
|
|
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check if I am a teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
/***** Set users as present *****/
|
|
Att_DB_SetUsrsAsPresent (Event.AttCod,users,setOthersAsAbsent);
|
|
|
|
/***** Purge absent users without comments from table *****/
|
|
if (setOthersAsAbsent)
|
|
Att_DB_RemoveUsrsAbsentWithoutCommentsFromEvent (Event.AttCod);
|
|
|
|
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 bool (*Hie_GetDataByCod[Hie_NUM_LEVELS]) (struct Hie_Node *Node);
|
|
extern const char *Ntf_WSNotifyEvents[Ntf_NUM_NOTIFY_EVENTS];
|
|
extern const char *Txt_Forum;
|
|
extern const char *Txt_HIERARCHY_SINGUL_Abc[Hie_NUM_LEVELS];
|
|
int ReturnCode;
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumNotifs;
|
|
unsigned NumNotif;
|
|
long NtfCod;
|
|
Ntf_NotifyEvent_t NotifyEvent;
|
|
long EventTime;
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
struct Hie_Node Hie[Hie_NUM_LEVELS];
|
|
long Cod;
|
|
struct For_Forum ForumSelected;
|
|
char ForumName[For_MAX_BYTES_FORUM_NAME + 1];
|
|
char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1];
|
|
char *ContentStr;
|
|
Ntf_Status_t Status;
|
|
size_t Length;
|
|
Hie_Level_t Level;
|
|
unsigned Col;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getNotifications;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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;
|
|
|
|
/***** Get my language from database *****/
|
|
if ((ReturnCode = API_GetMyLanguage (soap)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get my notifications from database *****/
|
|
if ((NumNotifs = Ntf_DB_GetMyRecentNotifications (&mysql_res,(time_t) beginTime))) // Notifications found
|
|
{
|
|
getNotificationsOut->numNotifications =
|
|
getNotificationsOut->notificationsArray.__size = (int) NumNotifs;
|
|
getNotificationsOut->notificationsArray.__ptr = soap_malloc (soap,
|
|
(getNotificationsOut->notificationsArray.__size) *
|
|
sizeof (*(getNotificationsOut->notificationsArray.__ptr)));
|
|
|
|
for (NumNotif = 0;
|
|
NumNotif < NumNotifs;
|
|
NumNotif++)
|
|
{
|
|
/* Get next notification */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get unique notification code (row[0]) */
|
|
NtfCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].notifCode = (int) NtfCod;
|
|
|
|
/* Get notification event type (row[1]) */
|
|
NotifyEvent = Ntf_GetNotifyEventFromStr (row[1]);
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].eventType =
|
|
soap_malloc (soap,Ntf_MAX_BYTES_NOTIFY_EVENT + 1);
|
|
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].eventType,
|
|
Ntf_WSNotifyEvents[NotifyEvent],Ntf_MAX_BYTES_NOTIFY_EVENT);
|
|
|
|
/* Get time of the event (row[2]) */
|
|
EventTime = 0L;
|
|
if (row[2])
|
|
sscanf (row[2],"%ld",&EventTime);
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].eventTime = EventTime;
|
|
|
|
/* Get user's code of the user who caused the event (row[3]) */
|
|
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[3]);
|
|
|
|
/* Get institution code, center code, degree code and course code
|
|
(row[4], row[5], row[6] and row[7]) */
|
|
for (Level = Hie_INS, Col = 4;
|
|
Level <= Hie_CRS;
|
|
Level++, Col++)
|
|
{
|
|
Hie[Level].HieCod = Str_ConvertStrCodToLongCod (row[Col]);
|
|
Hie_GetDataByCod[Level] (&Hie[Level]);
|
|
}
|
|
|
|
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Hie[Hie_CRS].HieCod)) // Get some user's data from database
|
|
{
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].userNickname =
|
|
soap_malloc (soap,Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1);
|
|
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userNickname,
|
|
Gbl.Usrs.Other.UsrDat.Nickname,
|
|
Nck_MAX_BYTES_NICK_WITHOUT_ARROBA);
|
|
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].userSurname1 =
|
|
soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
|
|
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userSurname1,
|
|
Gbl.Usrs.Other.UsrDat.Surname1,
|
|
Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
|
|
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].userSurname2 =
|
|
soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
|
|
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userSurname2,
|
|
Gbl.Usrs.Other.UsrDat.Surname2,
|
|
Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
|
|
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].userFirstname =
|
|
soap_malloc (soap,Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME + 1);
|
|
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userFirstname,
|
|
Gbl.Usrs.Other.UsrDat.FrstName,
|
|
Usr_MAX_BYTES_FIRSTNAME_OR_SURNAME);
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].userPhoto =
|
|
soap_malloc (soap,WWW_MAX_BYTES_WWW + 1);
|
|
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userPhoto,
|
|
PhotoURL,WWW_MAX_BYTES_WWW);
|
|
}
|
|
else
|
|
{
|
|
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;
|
|
}
|
|
|
|
/* Get message/post/... code (row[8]) */
|
|
Cod = Str_ConvertStrCodToLongCod (row[8]);
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].eventCode = (int) Cod;
|
|
|
|
/* Set location */
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].location =
|
|
soap_malloc (soap,Ntf_MAX_BYTES_NOTIFY_LOCATION + 1);
|
|
|
|
if (NotifyEvent == Ntf_EVENT_FORUM_POST_COURSE ||
|
|
NotifyEvent == Ntf_EVENT_FORUM_REPLY)
|
|
{
|
|
For_GetThreadForumTypeAndHieCodOfAPost (Cod,&ForumSelected);
|
|
For_SetForumName (&ForumSelected,
|
|
ForumName,Gbl.Prefs.Language,false); // Set forum name in recipient's language
|
|
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
|
|
Txt_Forum,ForumName);
|
|
}
|
|
else
|
|
{
|
|
for (Level = Hie_CRS;
|
|
Level >= Hie_INS;
|
|
Level--)
|
|
if (Hie[Level].HieCod > 0)
|
|
{
|
|
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
|
|
Txt_HIERARCHY_SINGUL_Abc[Level],Hie[Level].ShrtName);
|
|
break;
|
|
}
|
|
if (Level < Hie_INS)
|
|
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"-",
|
|
Ntf_MAX_BYTES_NOTIFY_LOCATION);
|
|
}
|
|
|
|
/* Get status (row[9]) */
|
|
if (sscanf (row[9],"%u",&Status) != 1)
|
|
Status = (Ntf_Status_t) 0;
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].status = (int) Status;
|
|
|
|
/* Get summary and content */
|
|
ContentStr = NULL;
|
|
Ntf_GetNotifSummaryAndContent (SummaryStr,&ContentStr,NotifyEvent,
|
|
Cod,Hie[Hie_CRS].HieCod,Gbl.Usrs.Me.UsrDat.UsrCod,
|
|
Ntf_GET_CONTENT);
|
|
|
|
Length = strlen (SummaryStr);
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].summary =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].summary,
|
|
SummaryStr,Length);
|
|
|
|
if (ContentStr == NULL)
|
|
{
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].content =
|
|
soap_malloc (soap,1);
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].content[0] = '\0';
|
|
}
|
|
else
|
|
{
|
|
Length = strlen (ContentStr);
|
|
getNotificationsOut->notificationsArray.__ptr[NumNotif].content =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].content,
|
|
ContentStr,Length);
|
|
|
|
/* Free memory used by content string */
|
|
free (ContentStr);
|
|
ContentStr = NULL;
|
|
}
|
|
}
|
|
}
|
|
else // No notifications found
|
|
{
|
|
getNotificationsOut->numNotifications = 0;
|
|
getNotificationsOut->notificationsArray.__size = 0;
|
|
getNotificationsOut->notificationsArray.__ptr = NULL;
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************* Get my language from database *************************/
|
|
/*****************************************************************************/
|
|
|
|
static int API_GetMyLanguage (struct soap *soap)
|
|
{
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
bool UsrFound;
|
|
|
|
/***** Get user's language *****/
|
|
if ((UsrFound = Set_DB_GetMyLanguage (&mysql_res)))
|
|
{
|
|
/***** Get language from database *****/
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get language (row[0]) */
|
|
Gbl.Prefs.Language = Lan_GetLanguageFromStr (row[0]);
|
|
if (Gbl.Prefs.Language == Lan_LANGUAGE_UNKNOWN) // Language stored in database is unknown
|
|
Gbl.Prefs.Language = Cfg_DEFAULT_LANGUAGE;
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
if (!UsrFound)
|
|
return soap_receiver_fault (soap,
|
|
"Can not get user's language from database",
|
|
"User doen't exist in database");
|
|
|
|
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;
|
|
char LongStr[Cns_MAX_DIGITS_LONG + 1];
|
|
unsigned NumNtf;
|
|
unsigned NumNtfsMarkedAsRead = 0;
|
|
long NtfCod;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_markNotificationsAsRead;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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;
|
|
|
|
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) */
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DIGITS_LONG);
|
|
if ((NtfCod = Str_ConvertStrCodToLongCod (LongStr)) > 0)
|
|
{
|
|
/***** Mark notification as read in the database *****/
|
|
Ntf_DB_MarkNotifAsSeenUsingNtfCod (NtfCod);
|
|
NumNtfsMarkedAsRead++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***** Return notification code *****/
|
|
markNotificationsAsReadOut->numNotifications = (int) NumNtfsMarkedAsRead;
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************** Send a message to one or more users **********************/
|
|
/*****************************************************************************/
|
|
|
|
#define API_MAX_BYTES_QUERY_RECIPIENTS (10 * 1024 - 1)
|
|
|
|
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;
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumUsrs;
|
|
unsigned NumUsr;
|
|
bool NotifyByEmail;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_sendMessage;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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;
|
|
|
|
/***** Check if the message is a reply to a previous message *****/
|
|
if (messageCode)
|
|
{
|
|
/***** Check if the original message was really received by me *****/
|
|
if (!Msg_DB_CheckIfMsgHasBeenReceivedByMe ((long) messageCode))
|
|
return soap_sender_fault (soap,
|
|
"Can not send reply message",
|
|
"Original message does not exist");
|
|
|
|
/***** Get the recipient of the message *****/
|
|
if ((ReplyUsrCod = Msg_DB_GetSender ((long) messageCode)) <= 0)
|
|
return soap_sender_fault (soap,
|
|
"Can not send reply message",
|
|
"Original message does not exist");
|
|
}
|
|
|
|
/***** Query database to get users *****/
|
|
NumUsrs = Msg_DB_GetRecipientsCods (&mysql_res,ReplyUsrCod,to);
|
|
|
|
/***** Initialize output structure *****/
|
|
sendMessageOut->numUsers =
|
|
sendMessageOut->usersArray.__size = (int) NumUsrs;
|
|
sendMessageOut->usersArray.__ptr = NULL;
|
|
|
|
/***** Get users *****/
|
|
if (NumUsrs) // There are a recipient to reply or nicknames in "to"
|
|
{
|
|
sendMessageOut->usersArray.__ptr = soap_malloc (soap,
|
|
(sendMessageOut->usersArray.__size) *
|
|
sizeof (*(sendMessageOut->usersArray.__ptr)));
|
|
|
|
for (NumUsr = 0;
|
|
NumUsr < NumUsrs;
|
|
NumUsr++)
|
|
{
|
|
/* 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_CRS))
|
|
{
|
|
/* This received message must be notified by email? */
|
|
NotifyByEmail = (Usr_ItsMe (Gbl.Usrs.Other.UsrDat.UsrCod) == Usr_OTHER &&
|
|
(Gbl.Usrs.Other.UsrDat.NtfEvents.SendEmail & (1 << Ntf_EVENT_MESSAGE)));
|
|
|
|
/* Send message to this user */
|
|
if ((ReturnCode = API_SendMessageToUsr ((long) messageCode,
|
|
ReplyUsrCod,
|
|
Gbl.Usrs.Other.UsrDat.UsrCod,
|
|
NotifyByEmail,
|
|
subject,
|
|
body)) != SOAP_OK)
|
|
{
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
return ReturnCode;
|
|
}
|
|
|
|
/* Copy user's data into output structure */
|
|
API_CopyUsrData (soap,
|
|
&(sendMessageOut->usersArray.__ptr[NumUsr]),
|
|
&Gbl.Usrs.Other.UsrDat,
|
|
Usr_CAN_NOT);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************* Send a message to one user ************************/
|
|
/*****************************************************************************/
|
|
|
|
static int API_SendMessageToUsr (long OriginalMsgCod,
|
|
long ReplyUsrCod,long RecipientUsrCod,
|
|
bool NotifyByEmail,
|
|
const char *Subject,const char *Content)
|
|
{
|
|
static bool MsgAlreadyInserted = false;
|
|
static long MsgCod;
|
|
|
|
/***** 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 */
|
|
MsgCod = Msg_DB_CreateNewMsg (Subject,Content,
|
|
-1L); // No media content
|
|
|
|
/* Insert message in sent messages */
|
|
Msg_DB_CreateSntMsg (MsgCod,
|
|
-1L); // No origin course
|
|
|
|
MsgAlreadyInserted = true;
|
|
}
|
|
|
|
/***** Insert message received in the database *****/
|
|
Msg_DB_CreateRcvMsg (MsgCod,RecipientUsrCod,NotifyByEmail);
|
|
|
|
/***** Create notification for this recipient.
|
|
If this recipient wants to receive notifications by email,
|
|
activate the sending of a notification *****/
|
|
Ntf_DB_StoreNotifyEventToUsr (Ntf_EVENT_MESSAGE,RecipientUsrCod,MsgCod,
|
|
(Ntf_Status_t) (NotifyByEmail ? Ntf_STATUS_BIT_EMAIL :
|
|
0),
|
|
-1L,-1L,-1L,-1L);
|
|
|
|
/***** If this recipient is the original sender of a message been replied... *****/
|
|
if (RecipientUsrCod == ReplyUsrCod)
|
|
/***** ...then update received message setting Replied field to true *****/
|
|
Msg_DB_SetRcvMsgAsReplied (OriginalMsgCod);
|
|
|
|
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;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_sendNotice;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check course and group codes *****/
|
|
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod,
|
|
-1L)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get degree of current course *****/
|
|
Gbl.Hierarchy.Node[Hie_DEG].HieCod = Crs_DB_GetDegCodOfCourseByCod (Gbl.Hierarchy.Node[Hie_CRS].HieCod);
|
|
|
|
/***** Check if I am a teacher *****/
|
|
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
/***** Insert notice in the database *****/
|
|
/* Get the code of the inserted item */
|
|
NotCod = Not_DB_InsertNotice (body);
|
|
|
|
/***** Create notifications *****/
|
|
// TODO: create notifications
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
/***** Return notification code *****/
|
|
sendNoticeOut->noticeCode = (int) NotCod;
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************** Return test configuration in a course ********************/
|
|
/*****************************************************************************/
|
|
|
|
#define TstPrn_MAX_BYTES_FEEDBACK_TYPE 32
|
|
|
|
int swad__getTestConfig (struct soap *soap,
|
|
char *wsKey,int courseCode, // input
|
|
struct swad__getTestConfigOutput *getTestConfigOut) // output
|
|
{
|
|
int ReturnCode;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getTestConfig;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Get degree of current course *****/
|
|
Gbl.Hierarchy.Node[Hie_DEG].HieCod = Crs_DB_GetDegCodOfCourseByCod (Gbl.Hierarchy.Node[Hie_CRS].HieCod);
|
|
|
|
/***** Set default result to empty *****/
|
|
getTestConfigOut->numQuestions =
|
|
getTestConfigOut->minQuestions =
|
|
getTestConfigOut->defQuestions =
|
|
getTestConfigOut->maxQuestions = 0;
|
|
getTestConfigOut->visibility = TstVis_MIN_VISIBILITY;
|
|
|
|
/* TODO: Remove these lines in 2021 */
|
|
getTestConfigOut->feedback = soap_malloc (soap,TstPrn_MAX_BYTES_FEEDBACK_TYPE + 1);
|
|
getTestConfigOut->feedback[0] = '\0';
|
|
|
|
/***** Get test configuration *****/
|
|
TstCfg_GetConfig ();
|
|
getTestConfigOut->pluggable = (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES) ? 1 :
|
|
0;
|
|
getTestConfigOut->minQuestions = (int) TstCfg_GetConfigMin ();
|
|
getTestConfigOut->defQuestions = (int) TstCfg_GetConfigDef ();
|
|
getTestConfigOut->maxQuestions = (int) TstCfg_GetConfigMax ();
|
|
getTestConfigOut->visibility = (int) TstCfg_GetConfigVisibility ();
|
|
|
|
/* Convert from visibility to old feedback */
|
|
/* TODO: Remove these lines in 2021 */
|
|
if (!TstVis_IsVisibleTotalScore (TstCfg_GetConfigVisibility ()))
|
|
Str_Copy (getTestConfigOut->feedback,"nothing",
|
|
TstPrn_MAX_BYTES_FEEDBACK_TYPE);
|
|
else if (!TstVis_IsVisibleEachQstScore (TstCfg_GetConfigVisibility ()))
|
|
Str_Copy (getTestConfigOut->feedback,"totalResult",
|
|
TstPrn_MAX_BYTES_FEEDBACK_TYPE);
|
|
else if (!TstVis_IsVisibleCorrectAns (TstCfg_GetConfigVisibility ()))
|
|
Str_Copy (getTestConfigOut->feedback,"eachResult",
|
|
TstPrn_MAX_BYTES_FEEDBACK_TYPE);
|
|
else if (!TstVis_IsVisibleFeedbackTxt (TstCfg_GetConfigVisibility ()))
|
|
Str_Copy (getTestConfigOut->feedback,"eachGoodBad",
|
|
TstPrn_MAX_BYTES_FEEDBACK_TYPE);
|
|
else
|
|
Str_Copy (getTestConfigOut->feedback,"fullFeedback",
|
|
TstPrn_MAX_BYTES_FEEDBACK_TYPE);
|
|
|
|
/***** Get number of tests *****/
|
|
if (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES &&
|
|
TstCfg_GetConfigMax () > 0)
|
|
getTestConfigOut->numQuestions = (int) Qst_DB_GetNumQstsInCrs ((long) courseCode);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************* 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;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getTests;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Get degree of current course *****/
|
|
Gbl.Hierarchy.Node[Hie_DEG].HieCod = Crs_DB_GetDegCodOfCourseByCod (Gbl.Hierarchy.Node[Hie_CRS].HieCod);
|
|
|
|
/***** 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 *****/
|
|
if (TstCfg_CheckIfPluggableIsUnknownAndCrsHasTests ())
|
|
{
|
|
/***** Get tags *****/
|
|
if ((ReturnCode = API_GetTstTags (soap,
|
|
(long) courseCode,getTestsOut)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get questions *****/
|
|
if ((ReturnCode = API_GetTstQuestions (soap,
|
|
(long) courseCode,(time_t) beginTime,getTestsOut)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get answers *****/
|
|
if ((ReturnCode = API_GetTstAnswers (soap,
|
|
(long) courseCode,(time_t) beginTime,getTestsOut)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get tags for each question *****/
|
|
if ((ReturnCode = API_GetTstQuestionTags (soap,
|
|
(long) courseCode,(time_t) beginTime,getTestsOut)) != SOAP_OK)
|
|
return ReturnCode;
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**** Get test tags (only not hidden) from database giving a course code *****/
|
|
/*****************************************************************************/
|
|
|
|
static int API_GetTstTags (struct soap *soap,
|
|
long CrsCod,struct swad__getTestsOutput *getTestsOut)
|
|
{
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumTags;
|
|
unsigned NumTag;
|
|
|
|
/***** Get available tags from database *****/
|
|
NumTags = Tag_DB_GetEnabledTagsFromCrs (&mysql_res,CrsCod);
|
|
|
|
getTestsOut->tagsArray.__size = (int) NumTags;
|
|
|
|
if (NumTags == 0)
|
|
getTestsOut->tagsArray.__ptr = NULL;
|
|
else // Tags found
|
|
{
|
|
getTestsOut->tagsArray.__ptr = soap_malloc (soap,
|
|
(getTestsOut->tagsArray.__size) *
|
|
sizeof (*(getTestsOut->tagsArray.__ptr)));
|
|
|
|
for (NumTag = 0;
|
|
NumTag < NumTags;
|
|
NumTag++)
|
|
{
|
|
/* Get next tag */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get tag code (row[0]) */
|
|
getTestsOut->tagsArray.__ptr[NumTag].tagCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* 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],
|
|
Tag_MAX_BYTES_TAG);
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******* Get recent test questions from database giving a course code ********/
|
|
/*****************************************************************************/
|
|
|
|
static int API_GetTstQuestions (struct soap *soap,
|
|
long CrsCod,time_t BeginTime,
|
|
struct swad__getTestsOutput *getTestsOut)
|
|
{
|
|
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumQsts;
|
|
unsigned NumQst;
|
|
Qst_AnswerType_t AnswerType;
|
|
|
|
/***** Get recent test questions from database *****/
|
|
// DISTINCT is necessary to not repeat questions
|
|
NumQsts = Qst_DB_GetRecentQuestions (&mysql_res,CrsCod,BeginTime);
|
|
|
|
getTestsOut->questionsArray.__size = (int) NumQsts;
|
|
|
|
if (NumQsts == 0)
|
|
getTestsOut->questionsArray.__ptr = NULL;
|
|
else // Questions found
|
|
{
|
|
getTestsOut->questionsArray.__ptr = soap_malloc (soap,
|
|
(getTestsOut->questionsArray.__size) *
|
|
sizeof (*(getTestsOut->questionsArray.__ptr)));
|
|
|
|
for (NumQst = 0;
|
|
NumQst < NumQsts;
|
|
NumQst++)
|
|
{
|
|
/* Get next question */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get question code (row[0]) */
|
|
getTestsOut->questionsArray.__ptr[NumQst].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get answer type (row[1]) */
|
|
AnswerType = Qst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
|
|
getTestsOut->questionsArray.__ptr[NumQst].answerType =
|
|
soap_malloc (soap,Qst_MAX_BYTES_ANSWER_TYPE + 1);
|
|
Str_Copy (getTestsOut->questionsArray.__ptr[NumQst].answerType,
|
|
Qst_StrAnswerTypesXML[AnswerType],
|
|
Qst_MAX_BYTES_ANSWER_TYPE);
|
|
|
|
/* Get shuffle (row[2]) */
|
|
getTestsOut->questionsArray.__ptr[NumQst].shuffle = (row[2][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get question stem (row[3]) */
|
|
getTestsOut->questionsArray.__ptr[NumQst].stem =
|
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
|
Str_Copy (getTestsOut->questionsArray.__ptr[NumQst].stem,row[3],
|
|
Cns_MAX_BYTES_TEXT);
|
|
|
|
/* Get question feedback (row[4]) */
|
|
getTestsOut->questionsArray.__ptr[NumQst].feedback =
|
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
|
Str_Copy (getTestsOut->questionsArray.__ptr[NumQst].feedback,row[4],
|
|
Cns_MAX_BYTES_TEXT);
|
|
}
|
|
}
|
|
|
|
/***** 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 **/
|
|
/*****************************************************************************/
|
|
|
|
static int API_GetTstAnswers (struct soap *soap,
|
|
long CrsCod,time_t BeginTime,
|
|
struct swad__getTestsOutput *getTestsOut)
|
|
{
|
|
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumAnss;
|
|
unsigned NumAns;
|
|
unsigned Index;
|
|
|
|
/***** Get answers to recent test questions from database *****/
|
|
NumAnss = Qst_DB_GetRecentAnswers (&mysql_res,CrsCod,BeginTime);
|
|
|
|
getTestsOut->answersArray.__size = (int) NumAnss;
|
|
|
|
if (NumAnss == 0)
|
|
getTestsOut->answersArray.__ptr = NULL;
|
|
else // Answers found
|
|
{
|
|
getTestsOut->answersArray.__ptr = soap_malloc (soap,
|
|
(getTestsOut->answersArray.__size) *
|
|
sizeof (*(getTestsOut->answersArray.__ptr)));
|
|
|
|
for (NumAns = 0;
|
|
NumAns < NumAnss;
|
|
NumAns++)
|
|
{
|
|
/* Get next question */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get question code (row[0]) */
|
|
getTestsOut->answersArray.__ptr[NumAns].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get answer index (row[1]) */
|
|
if (sscanf (row[1],"%u",&Index) == 1)
|
|
getTestsOut->answersArray.__ptr[NumAns].answerIndex = (int) Index;
|
|
else
|
|
getTestsOut->answersArray.__ptr[NumAns].answerIndex = 0; // error
|
|
|
|
/* Get correct (row[2]) */
|
|
getTestsOut->answersArray.__ptr[NumAns].correct = (row[2][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get answer (row[3]) */
|
|
getTestsOut->answersArray.__ptr[NumAns].answerText =
|
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
|
Str_Copy (getTestsOut->answersArray.__ptr[NumAns].answerText,
|
|
row[3],Cns_MAX_BYTES_TEXT);
|
|
|
|
/* Get feedback (row[4]) */
|
|
getTestsOut->answersArray.__ptr[NumAns].answerFeedback =
|
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
|
Str_Copy (getTestsOut->answersArray.__ptr[NumAns].answerFeedback,
|
|
row[4],Cns_MAX_BYTES_TEXT);
|
|
}
|
|
}
|
|
|
|
/***** 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 ****/
|
|
/*****************************************************************************/
|
|
|
|
static int API_GetTstQuestionTags (struct soap *soap,
|
|
long CrsCod,time_t BeginTime,
|
|
struct swad__getTestsOutput *getTestsOut)
|
|
{
|
|
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumQstTags;
|
|
unsigned NumQstTag;
|
|
unsigned Index;
|
|
|
|
/***** Get recent test questions from database *****/
|
|
NumQstTags = Tag_DB_GetRecentTags (&mysql_res,CrsCod,BeginTime);
|
|
|
|
getTestsOut->questionTagsArray.__size = (int) NumQstTags;
|
|
|
|
if (NumQstTags == 0)
|
|
getTestsOut->questionTagsArray.__ptr = NULL;
|
|
else // Questions-tags found
|
|
{
|
|
getTestsOut->questionTagsArray.__ptr = soap_malloc (soap,
|
|
(getTestsOut->questionTagsArray.__size) *
|
|
sizeof (*(getTestsOut->questionTagsArray.__ptr)));
|
|
|
|
for (NumQstTag = 0;
|
|
NumQstTag < NumQstTags;
|
|
NumQstTag++)
|
|
{
|
|
/* Get next question */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get question code (row[0]) */
|
|
getTestsOut->questionTagsArray.__ptr[NumQstTag].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get tag code (row[1]) */
|
|
getTestsOut->questionTagsArray.__ptr[NumQstTag].tagCode = (int) Str_ConvertStrCodToLongCod (row[1]);
|
|
|
|
/* Get tag index (row[2]) */
|
|
if (sscanf (row[2],"%u",&Index) == 1)
|
|
getTestsOut->questionTagsArray.__ptr[NumQstTag].tagIndex = (int) Index;
|
|
else
|
|
getTestsOut->questionTagsArray.__ptr[NumQstTag].tagIndex = 0; // error
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************** Return one test question for Trivial game *****************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getTrivialQuestion (struct soap *soap,
|
|
char *wsKey,char *degrees,float lowerScore,float upperScore, // input
|
|
struct swad__getTrivialQuestionOutput *getTrivialQuestionOut) // output
|
|
{
|
|
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
|
int ReturnCode;
|
|
const char *Ptr;
|
|
char LongStr[Cns_MAX_DIGITS_LONG + 1];
|
|
char DegreesStr[API_MAX_BYTES_DEGREES_STR + 1];
|
|
char DegStr[ 1 + 1 + Cns_MAX_DIGITS_LONG + 1 + 1];
|
|
// DegStr=", ' - number ' \0"
|
|
long DegCod;
|
|
bool FirstDegree = true;
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumAnss;
|
|
unsigned NumAns;
|
|
long QstCod = -1L;
|
|
Qst_AnswerType_t AnswerType;
|
|
unsigned Index;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getTrivialQuestion;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** 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) */
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DIGITS_LONG);
|
|
|
|
/* 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);
|
|
FirstDegree = false;
|
|
}
|
|
else
|
|
{
|
|
snprintf (DegStr,sizeof (DegStr),",%ld",DegCod);
|
|
Str_Concat (DegreesStr,DegStr,sizeof (DegreesStr) - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!DegreesStr[0]) // Degrees not found
|
|
return soap_sender_fault (soap,
|
|
"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)
|
|
return soap_sender_fault (soap,
|
|
"Bad score interval",
|
|
"lowerScore or upperScore values not valid");
|
|
|
|
/***** Get test questions *****/
|
|
if (Qst_DB_GetTrivialQst (&mysql_res,DegreesStr,lowerScore,upperScore)) // Question found
|
|
{
|
|
/* Get 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]);
|
|
getTrivialQuestionOut->question.answerType =
|
|
soap_malloc (soap,Qst_MAX_BYTES_ANSWER_TYPE + 1);
|
|
Str_Copy (getTrivialQuestionOut->question.answerType,
|
|
Qst_StrAnswerTypesXML[AnswerType],Qst_MAX_BYTES_ANSWER_TYPE);
|
|
|
|
/* Get shuffle (row[2]) */
|
|
getTrivialQuestionOut->question.shuffle = (row[2][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get question stem (row[3]) */
|
|
getTrivialQuestionOut->question.stem =
|
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
|
Str_Copy (getTrivialQuestionOut->question.stem,row[3],Cns_MAX_BYTES_TEXT);
|
|
|
|
/* Get question feedback (row[4]) */
|
|
getTrivialQuestionOut->question.feedback =
|
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
|
Str_Copy (getTrivialQuestionOut->question.feedback,row[4],Cns_MAX_BYTES_TEXT);
|
|
}
|
|
else // Empty question
|
|
{
|
|
/* Question code (row[0]) */
|
|
QstCod = -1L;
|
|
getTrivialQuestionOut->question.questionCode = -1;
|
|
|
|
/* Answer type (row[1]) */
|
|
getTrivialQuestionOut->question.answerType = soap_malloc (soap,1);
|
|
getTrivialQuestionOut->question.answerType[0] = '\0';
|
|
|
|
/* Shuffle (row[2]) */
|
|
getTrivialQuestionOut->question.shuffle = 0;
|
|
|
|
/* Question stem (row[3]) */
|
|
getTrivialQuestionOut->question.stem = soap_malloc (soap,1);
|
|
getTrivialQuestionOut->question.stem[0] = '\0';
|
|
|
|
/* Get question feedback (row[4]) */
|
|
getTrivialQuestionOut->question.feedback = soap_malloc (soap,1);
|
|
getTrivialQuestionOut->question.feedback[0] = '\0';
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
if (QstCod > 0)
|
|
{
|
|
/***** Get answer from database *****/
|
|
NumAnss = Qst_DB_GetAnswersData (&mysql_res,QstCod,
|
|
false); // Don't shuffle
|
|
|
|
getTrivialQuestionOut->answersArray.__size = (int) NumAnss;
|
|
|
|
if (NumAnss == 0)
|
|
getTrivialQuestionOut->answersArray.__ptr = NULL;
|
|
else // Answers found
|
|
{
|
|
getTrivialQuestionOut->answersArray.__ptr = soap_malloc (soap,
|
|
(getTrivialQuestionOut->answersArray.__size) *
|
|
sizeof (*(getTrivialQuestionOut->answersArray.__ptr)));
|
|
|
|
for (NumAns = 0;
|
|
NumAns < NumAnss;
|
|
NumAns++)
|
|
{
|
|
/* Get next question */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get question code */
|
|
getTrivialQuestionOut->answersArray.__ptr[NumAns].questionCode = (int) QstCod;
|
|
|
|
/* Get answer index (row[0]) */
|
|
if (sscanf (row[0],"%u",&Index) == 1)
|
|
getTrivialQuestionOut->answersArray.__ptr[NumAns].answerIndex = (int) Index;
|
|
else
|
|
getTrivialQuestionOut->answersArray.__ptr[NumAns].answerIndex = 0; // error
|
|
|
|
/* Get answer (row[1]) */
|
|
getTrivialQuestionOut->answersArray.__ptr[NumAns].answerText =
|
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
|
Str_Copy (getTrivialQuestionOut->answersArray.__ptr[NumAns].answerText,
|
|
row[3],Cns_MAX_BYTES_TEXT);
|
|
|
|
/* Get feedback (row[2]) */
|
|
getTrivialQuestionOut->answersArray.__ptr[NumAns].answerFeedback =
|
|
soap_malloc (soap,Cns_MAX_BYTES_TEXT + 1);
|
|
Str_Copy (getTrivialQuestionOut->answersArray.__ptr[NumAns].answerFeedback,
|
|
row[4],Cns_MAX_BYTES_TEXT);
|
|
|
|
// Media code (row[3]) ignored here
|
|
|
|
/* Get correct (row[4]) */
|
|
getTrivialQuestionOut->answersArray.__ptr[NumAns].correct = (row[4][0] == 'Y') ? 1 :
|
|
0;
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********************** 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;
|
|
int NumGame;
|
|
long GamCod;
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
long StartTime;
|
|
long EndTime;
|
|
size_t Length;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getGames;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check if I am logged as student in the course *****/
|
|
if (Gbl.Usrs.Me.Role.Logged != Rol_STD)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must be a student in the course");
|
|
|
|
/***** Query list of games available for me *****/
|
|
NumGames = Gam_DB_GetListAvailableGames (&mysql_res);
|
|
getGamesOut->gamesArray.__size =
|
|
getGamesOut->numGames = (int) NumGames;
|
|
|
|
if (getGamesOut->numGames == 0)
|
|
getGamesOut->gamesArray.__ptr = NULL;
|
|
else // Games found
|
|
{
|
|
getGamesOut->gamesArray.__ptr = soap_malloc (soap,
|
|
(getGamesOut->gamesArray.__size) *
|
|
sizeof (*(getGamesOut->gamesArray.__ptr)));
|
|
|
|
for (NumGame = 0;
|
|
NumGame < getGamesOut->numGames;
|
|
NumGame++)
|
|
{
|
|
/* Get next game */
|
|
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.Node[Hie_CRS].HieCod)) // Get some user's data from database
|
|
{
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
|
|
getGamesOut->gamesArray.__ptr[NumGame].userSurname1 =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].userSurname1,
|
|
Gbl.Usrs.Other.UsrDat.Surname1,Length);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
|
|
getGamesOut->gamesArray.__ptr[NumGame].userSurname2 =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].userSurname2,
|
|
Gbl.Usrs.Other.UsrDat.Surname2,Length);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.FrstName);
|
|
getGamesOut->gamesArray.__ptr[NumGame].userFirstname =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].userFirstname,
|
|
Gbl.Usrs.Other.UsrDat.FrstName,Length);
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
|
|
Length = strlen (PhotoURL);
|
|
getGamesOut->gamesArray.__ptr[NumGame].userPhoto =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].userPhoto,
|
|
PhotoURL,Length);
|
|
}
|
|
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;
|
|
|
|
/* 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;
|
|
|
|
/* Get visibility (row[5]) */
|
|
getGamesOut->gamesArray.__ptr[NumGame].visibility = TstVis_GetVisibilityFromStr (row[5]);
|
|
|
|
/* Get title of the game (row[6]) */
|
|
Length = strlen (row[6]);
|
|
getGamesOut->gamesArray.__ptr[NumGame].title =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].title,row[6],Length);
|
|
|
|
/* Get Txt (row[7]) */
|
|
Length = strlen (row[7]);
|
|
getGamesOut->gamesArray.__ptr[NumGame].text =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getGamesOut->gamesArray.__ptr[NumGame].text,row[7],Length);
|
|
}
|
|
}
|
|
|
|
/***** 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,
|
|
char *wsKey,int courseCode,int gameCode, // input
|
|
struct swad__getMatchesOutput *getMatchesOut) // output
|
|
{
|
|
int ReturnCode;
|
|
struct Gam_Game Game;
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumMatches;
|
|
int NumMatch;
|
|
long MchCod;
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
long StartTime;
|
|
long EndTime;
|
|
size_t Length;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getMatches;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** Reset game *****/
|
|
Gam_ResetGame (&Game);
|
|
|
|
/***** Get game data from database *****/
|
|
Game.GamCod = (long) gameCode;
|
|
if (Game.GamCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"Bad game code",
|
|
"Game code must be a integer greater than 0");
|
|
Gam_GetGameDataByCod (&Game);
|
|
|
|
/***** Get some of my data *****/
|
|
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check if I am logged as student in the course *****/
|
|
if (Gbl.Usrs.Me.Role.Logged != Rol_STD)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must be a student in the course");
|
|
|
|
/***** Query list of matches available for me *****/
|
|
NumMatches = Mch_DB_GetAvailableMatchesInGame (&mysql_res,Game.GamCod);
|
|
getMatchesOut->matchesArray.__size =
|
|
getMatchesOut->numMatches = (int) NumMatches;
|
|
|
|
if (getMatchesOut->numMatches == 0)
|
|
getMatchesOut->matchesArray.__ptr = NULL;
|
|
else // Matches found
|
|
{
|
|
getMatchesOut->matchesArray.__ptr = soap_malloc (soap,
|
|
(getMatchesOut->matchesArray.__size) *
|
|
sizeof (*(getMatchesOut->matchesArray.__ptr)));
|
|
|
|
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.Node[Hie_CRS].HieCod)) // Get some user's data from database
|
|
{
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
|
|
getMatchesOut->matchesArray.__ptr[NumMatch].userSurname1 =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getMatchesOut->matchesArray.__ptr[NumMatch].userSurname1,
|
|
Gbl.Usrs.Other.UsrDat.Surname1,Length);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
|
|
getMatchesOut->matchesArray.__ptr[NumMatch].userSurname2 =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getMatchesOut->matchesArray.__ptr[NumMatch].userSurname2,
|
|
Gbl.Usrs.Other.UsrDat.Surname2,Length);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.FrstName);
|
|
getMatchesOut->matchesArray.__ptr[NumMatch].userFirstname =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getMatchesOut->matchesArray.__ptr[NumMatch].userFirstname,
|
|
Gbl.Usrs.Other.UsrDat.FrstName,Length);
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
|
|
Length = strlen (PhotoURL);
|
|
getMatchesOut->matchesArray.__ptr[NumMatch].userPhoto =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getMatchesOut->matchesArray.__ptr[NumMatch].userPhoto,
|
|
PhotoURL,Length);
|
|
}
|
|
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]);
|
|
getMatchesOut->matchesArray.__ptr[NumMatch].title =
|
|
soap_malloc (soap,Length + 1);
|
|
Str_Copy (getMatchesOut->matchesArray.__ptr[NumMatch].title,row[4],
|
|
Length);
|
|
|
|
/* Get current question index (row[5]) */
|
|
getMatchesOut->matchesArray.__ptr[NumMatch].questionIndex = (int) Str_ConvertStrToUnsigned (row[5]);
|
|
|
|
/* Get list of groups for this match */
|
|
API_GetListGrpsInMatchFromDB (soap,
|
|
MchCod,&(getMatchesOut->matchesArray.__ptr[NumMatch].groups));
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********** Get match status to be refreshed in student's screen ************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getMatchStatus (struct soap *soap,
|
|
char *wsKey,int courseCode,int gameCode,int matchCode, // input
|
|
struct swad__getMatchStatusOutput *getMatchStatusOut) // output
|
|
{
|
|
int ReturnCode;
|
|
struct Gam_Game Game;
|
|
struct Mch_Match Match;
|
|
struct Mch_UsrAnswer UsrAnswer;
|
|
|
|
/***** Reset game and match *****/
|
|
Gam_ResetGame (&Game);
|
|
Mch_ResetMatch (&Match);
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getMatchStatus;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
Game.GamCod = (long) gameCode;
|
|
Match.MchCod = (long) matchCode;
|
|
|
|
/***** Default output *****/
|
|
getMatchStatusOut->matchCode = -1;
|
|
getMatchStatusOut->questionIndex = -1;
|
|
getMatchStatusOut->numAnswers = -1;
|
|
getMatchStatusOut->answerIndex = -1;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 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_GetGameDataByCod (&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_GetMatchDataByCod (&Match);
|
|
|
|
/* Check that match belongs to game */
|
|
if (Match.GamCod != Game.GamCod)
|
|
return soap_sender_fault (soap,
|
|
"Bad game code",
|
|
"Match does not belong to game");
|
|
|
|
/***** Get some of my data *****/
|
|
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check if I am logged as student in the course *****/
|
|
if (Gbl.Usrs.Me.Role.Logged != Rol_STD)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must be a student in the course");
|
|
|
|
/***** Can I play this match? *****/
|
|
if (Mch_CheckIfICanPlayThisMatchBasedOnGrps (&Match) == Usr_CAN_NOT)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester can not join this match");
|
|
|
|
/***** Set default match code *****/
|
|
getMatchStatusOut->matchCode = 0; // == 0 ==> wait
|
|
|
|
/***** Set index of question inside the game *****/
|
|
getMatchStatusOut->questionIndex = (int) Match.Status.QstInd;
|
|
|
|
if (Match.Status.Playing && // Match is being played
|
|
Match.Status.Showing != Mch_END) // Unfinished
|
|
/***** Join match *****/
|
|
/* Update players */
|
|
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
|
|
|
|
/***** Set number of answers (options) in question and student's answer (<0 ==> no answer) *****/
|
|
switch (Match.Status.Showing)
|
|
{
|
|
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_DB_GetNumAnswersQst (Match.Status.QstCod);
|
|
Mch_GetQstAnsFromDB (Match.MchCod,
|
|
Gbl.Usrs.Me.UsrDat.UsrCod,
|
|
Match.Status.QstInd,
|
|
&UsrAnswer);
|
|
getMatchStatusOut->answerIndex = UsrAnswer.NumOpt;
|
|
break;
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************* Send an answer to the current question in a match *************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__answerMatchQuestion (struct soap *soap,
|
|
char *wsKey,int courseCode,int gameCode,int matchCode,int questionIndex,int numOption, // input
|
|
struct swad__answerMatchQuestionOutput *answerMatchQuestionOut) // output
|
|
{
|
|
int ReturnCode;
|
|
struct Gam_Game Game;
|
|
struct Mch_Match Match;
|
|
unsigned QstInd; // 0 means that the game has not started. First question has index 1.
|
|
struct Mch_UsrAnswer UsrAnswer;
|
|
|
|
/***** Reset game and match *****/
|
|
Gam_ResetGame (&Game);
|
|
Mch_ResetMatch (&Match);
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_answerMatchQuestion;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
Game.GamCod = (long) gameCode;
|
|
Match.MchCod = (long) matchCode;
|
|
|
|
/***** Set default output *****/
|
|
/* <= 0 on error
|
|
> 0 on sucess */
|
|
answerMatchQuestionOut->matchCode = -1;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 course code is correct *****/
|
|
if (Gbl.Hierarchy.Node[Hie_CRS].HieCod <= 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_GetGameDataByCod (&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_GetMatchDataByCod (&Match);
|
|
|
|
/***** Check that match belongs to game *****/
|
|
if (Match.GamCod != Game.GamCod)
|
|
return soap_sender_fault (soap,
|
|
"Bad game code",
|
|
"Match does not belong to game");
|
|
|
|
/***** 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)
|
|
/***** Remove my answer to this question *****/
|
|
Mch_RemoveMyQuestionAnswer (&Match,QstInd);
|
|
else
|
|
{
|
|
/***** Store answer *****/
|
|
UsrAnswer.NumOpt = (unsigned) numOption;
|
|
Mch_StoreQuestionAnswer (&Match,QstInd,&UsrAnswer);
|
|
}
|
|
|
|
/***** Set success output *****/
|
|
answerMatchQuestionOut->matchCode = Match.MchCod;
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********************** Get lists of groups of a match **********************/
|
|
/*****************************************************************************/
|
|
|
|
static void API_GetListGrpsInMatchFromDB (struct soap *soap,
|
|
long MchCod,char **ListGroups)
|
|
{
|
|
MYSQL_RES *mysql_res;
|
|
long NumGrps;
|
|
long NumGrp;
|
|
long GrpCod;
|
|
char GrpCodStr[Cns_MAX_DIGITS_LONG + 1];
|
|
size_t Length;
|
|
|
|
/***** Get list of groups *****/
|
|
if ((NumGrps = Mch_DB_GetGrpCodsAssociatedToMatch (&mysql_res,MchCod))) // Groups found
|
|
{
|
|
Length = NumGrps * (Cns_MAX_DIGITS_LONG + 1) - 1;
|
|
*ListGroups = soap_malloc (soap,Length + 1);
|
|
(*ListGroups)[0] = '\0';
|
|
|
|
for (NumGrp = 0;
|
|
NumGrp < NumGrps;
|
|
NumGrp++)
|
|
{
|
|
/* Get next group */
|
|
GrpCod = DB_GetNextCode (mysql_res);
|
|
snprintf (GrpCodStr,sizeof (GrpCodStr),NumGrp ? ",%ld" :
|
|
"%ld",
|
|
GrpCod);
|
|
Str_Concat (*ListGroups,GrpCodStr,Length);
|
|
}
|
|
}
|
|
else
|
|
*ListGroups = NULL;
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*************** 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;
|
|
char XMLFileName[PATH_MAX + 1];
|
|
FILE *XML;
|
|
unsigned long FileSize;
|
|
unsigned long NumBytesRead;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getDirectoryTree;
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (long) courseCode;
|
|
Gbl.Crs.Grps.GrpCod = (long) groupCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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");
|
|
|
|
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check course and group codes *****/
|
|
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod,
|
|
Gbl.Crs.Grps.GrpCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Check if I belong to course/group *****/
|
|
if (Gbl.Crs.Grps.GrpCod > 0)
|
|
if (!Grp_GetIfIBelongToGrp (Gbl.Crs.Grps.GrpCod))
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to group");
|
|
|
|
/***** Check if tree code is correct *****/
|
|
if (treeCode <= 0 || treeCode > 3)
|
|
return soap_sender_fault (soap,
|
|
"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
|
|
Gbl.FileBrowser.Type = Brw_SHOW_DOC_GRP;
|
|
break;
|
|
case 2: // Shared files
|
|
Gbl.FileBrowser.Type = Brw_ADMI_SHR_GRP;
|
|
break;
|
|
case 3: // Marks
|
|
Gbl.FileBrowser.Type = Brw_SHOW_MRK_GRP;
|
|
break;
|
|
}
|
|
else // groupCode <= 0
|
|
switch (treeCode)
|
|
{
|
|
case 1: // Documents
|
|
Gbl.FileBrowser.Type = Brw_SHOW_DOC_CRS;
|
|
break;
|
|
case 2: // Shared files
|
|
Gbl.FileBrowser.Type = Brw_ADMI_SHR_CRS;
|
|
break;
|
|
case 3: // Marks
|
|
Gbl.FileBrowser.Type = Brw_SHOW_MRK_CRS;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
return soap_sender_fault (soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/* Initialize path to private directory */
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod = (courseCode > 0) ? (long) courseCode :
|
|
-1L;
|
|
Gbl.Crs.Grps.GrpCod = (groupCode > 0) ? (long) groupCode :
|
|
-1L;
|
|
|
|
snprintf (Gbl.Crs.Path.AbsPriv,sizeof (Gbl.Crs.Path.AbsPriv),"%s/%ld",
|
|
Cfg_PATH_CRS_PRIVATE,Gbl.Hierarchy.Node[Hie_CRS].HieCod);
|
|
Brw_InitializeFileBrowser ();
|
|
Str_Copy (Gbl.FileBrowser.FilFolLnk.Path,Brw_RootFolderInternalNames[Gbl.FileBrowser.Type],
|
|
sizeof (Gbl.FileBrowser.FilFolLnk.Path) - 1);
|
|
Str_Copy (Gbl.FileBrowser.FilFolLnk.Name,".",
|
|
sizeof (Gbl.FileBrowser.FilFolLnk.Name) - 1);
|
|
Brw_SetFullPathInTree ();
|
|
|
|
/* Check if exists the directory for HTML output. If not exists, create it */
|
|
Fil_CreateDirIfNotExists (Cfg_PATH_OUT_PRIVATE);
|
|
|
|
/* Create a unique name for the file */
|
|
snprintf (XMLFileName,sizeof (XMLFileName),"%s/%s.xml",
|
|
Cfg_PATH_OUT_PRIVATE,Cry_GetUniqueNameEncrypted ());
|
|
|
|
/* Open file for writing and reading */
|
|
if ((XML = fopen (XMLFileName,"w+t")) == NULL)
|
|
return soap_receiver_fault (soap,
|
|
"Can not get tree",
|
|
"Can not create temporary XML file");
|
|
|
|
/* Get directory tree into XML file */
|
|
XML_WriteStartFile (XML,"tree",false);
|
|
if (Brw_CheckIfFileOrFolderIsHiddenOrVisible (Brw_IS_FOLDER,
|
|
Gbl.FileBrowser.FilFolLnk.Full) == HidVis_VISIBLE)
|
|
API_ListDir (XML,1,
|
|
Gbl.FileBrowser.Path.RootFolder,
|
|
Brw_RootFolderInternalNames[Gbl.FileBrowser.Type]);
|
|
XML_WriteEndFile (XML,"tree");
|
|
|
|
/* Compute file size */
|
|
// fseek (XML,0L,SEEK_END);
|
|
FileSize = (unsigned long) ftell (XML);
|
|
fseek (XML,0L,SEEK_SET);
|
|
|
|
/* Copy XML content from file to memory */
|
|
getDirectoryTreeOut->tree = soap_malloc (soap,FileSize + 1);
|
|
NumBytesRead = fread (getDirectoryTreeOut->tree,1,FileSize,XML);
|
|
getDirectoryTreeOut->tree[NumBytesRead] = '\0';
|
|
|
|
/* Close and remove XML file */
|
|
fclose (XML);
|
|
unlink (XMLFileName);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************ List a directory recursively ***********************/
|
|
/*****************************************************************************/
|
|
|
|
static void API_ListDir (FILE *XML,unsigned Level,
|
|
const char *Path,const char *PathInTree)
|
|
{
|
|
extern const char *Txt_NEW_LINE;
|
|
struct dirent **FileList;
|
|
int NumFile;
|
|
int NumFiles;
|
|
char PathFileRel[PATH_MAX + 1 + NAME_MAX + 1];
|
|
char PathFileInExplTree[PATH_MAX + 1 + NAME_MAX + 1];
|
|
struct stat FileStatus;
|
|
|
|
/***** Scan directory *****/
|
|
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",
|
|
Path,FileList[NumFile]->d_name);
|
|
snprintf (PathFileInExplTree,sizeof (PathFileInExplTree),"%s/%s",
|
|
PathInTree,FileList[NumFile]->d_name);
|
|
|
|
Str_Copy (Gbl.FileBrowser.FilFolLnk.Path,PathInTree,
|
|
sizeof (Gbl.FileBrowser.FilFolLnk.Path) - 1);
|
|
Str_Copy (Gbl.FileBrowser.FilFolLnk.Name,FileList[NumFile]->d_name,
|
|
sizeof (Gbl.FileBrowser.FilFolLnk.Name) - 1);
|
|
|
|
if (!lstat (PathFileRel,&FileStatus)) // On success ==> 0 is returned
|
|
{
|
|
/***** Construct the full path of the file or folder *****/
|
|
Brw_SetFullPathInTree ();
|
|
|
|
if (S_ISDIR (FileStatus.st_mode)) // It's a directory
|
|
{
|
|
/***** Write a row for the subdirectory *****/
|
|
if (API_WriteRowFileBrowser (XML,Level,
|
|
Brw_IS_FOLDER,
|
|
FileList[NumFile]->d_name))
|
|
{
|
|
/* List subtree starting at this this directory */
|
|
API_ListDir (XML,Level + 1,
|
|
PathFileRel,PathFileInExplTree);
|
|
|
|
/* Indent and end dir */
|
|
API_IndentXMLLine (XML,Level);
|
|
fprintf (XML,"</dir>%s",Txt_NEW_LINE);
|
|
}
|
|
}
|
|
else if (S_ISREG (FileStatus.st_mode)) // It's a regular file
|
|
API_WriteRowFileBrowser (XML,Level,
|
|
Str_FileIs (FileList[NumFile]->d_name,"url") ? Brw_IS_LINK :
|
|
Brw_IS_FILE,
|
|
FileList[NumFile]->d_name);
|
|
}
|
|
}
|
|
|
|
free (FileList[NumFile]);
|
|
}
|
|
free (FileList);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********************** 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
|
|
|
|
static bool API_WriteRowFileBrowser (FILE *XML,unsigned Level,
|
|
Brw_FileType_t FileType,
|
|
const char *FileName)
|
|
{
|
|
extern const char *Txt_NEW_LINE;
|
|
extern const char *Txt_LICENSES[Brw_NUM_LICENSES];
|
|
struct Brw_FileMetadata FileMetadata;
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
|
|
/***** Is this row hidden or visible? *****/
|
|
if (Gbl.FileBrowser.Type == Brw_SHOW_DOC_CRS ||
|
|
Gbl.FileBrowser.Type == Brw_SHOW_DOC_GRP)
|
|
if (Brw_CheckIfFileOrFolderIsHiddenOrVisible (FileType,
|
|
Gbl.FileBrowser.FilFolLnk.Full) == HidVis_HIDDEN)
|
|
return false;
|
|
|
|
/***** XML row *****/
|
|
/* Indent */
|
|
API_IndentXMLLine (XML,Level);
|
|
|
|
/* Write file or folder data */
|
|
if (FileType == Brw_IS_FOLDER)
|
|
fprintf (XML,"<dir name=\"%s\">%s",
|
|
FileName,Txt_NEW_LINE);
|
|
else // File or link
|
|
{
|
|
/* Get file metadata */
|
|
Brw_GetFileMetadataByPath (&FileMetadata);
|
|
Brw_GetFileTypeSizeAndDate (&FileMetadata);
|
|
|
|
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,
|
|
Gbl.FileBrowser.FilFolLnk.Full,false,Brw_LICENSE_DEFAULT);
|
|
|
|
Gbl.Usrs.Other.UsrDat.UsrCod = FileMetadata.PublisherUsrCod;
|
|
Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,
|
|
Usr_DONT_GET_PREFS,
|
|
Usr_DONT_GET_ROLE_IN_CRS);
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,PhotoURL);
|
|
|
|
fprintf (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 *****************************/
|
|
/*****************************************************************************/
|
|
|
|
static void API_IndentXMLLine (FILE *XML,unsigned Level)
|
|
{
|
|
for ( ;
|
|
Level;
|
|
Level--)
|
|
fprintf (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 Brw_FileMetadata FileMetadata;
|
|
char URL[WWW_MAX_BYTES_WWW + 1];
|
|
char PhotoURL[WWW_MAX_BYTES_WWW + 1];
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getFile;
|
|
|
|
/***** Allocate space for strings *****/
|
|
getFileOut->fileName = soap_malloc (soap,NAME_MAX + 1);
|
|
getFileOut->URL = soap_malloc (soap,WWW_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,WWW_MAX_BYTES_WWW + 1);
|
|
|
|
/***** 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 *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 file metadata *****/
|
|
FileMetadata.FilCod = (long) fileCode;
|
|
if (FileMetadata.FilCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"Bad file code",
|
|
"File code must be a integer greater than 0");
|
|
|
|
Brw_GetFileMetadataByCod (&FileMetadata);
|
|
if (FileMetadata.FilCod <= 0)
|
|
return soap_sender_fault (soap,
|
|
"File does not exist, please refresh",
|
|
"The file requested does not exists");
|
|
|
|
/***** Set course and group codes *****/
|
|
Brw_GetCrsGrpFromFileMetadata (FileMetadata.FileBrowser,FileMetadata.Cod,
|
|
&Gbl.Hierarchy.Node[Hie_INS].HieCod,
|
|
&Gbl.Hierarchy.Node[Hie_CTR].HieCod,
|
|
&Gbl.Hierarchy.Node[Hie_DEG].HieCod,
|
|
&Gbl.Hierarchy.Node[Hie_CRS].HieCod,
|
|
&Gbl.Crs.Grps.GrpCod);
|
|
Hie_InitHierarchy ();
|
|
|
|
/***** Get some of my data *****/
|
|
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check course and group codes *****/
|
|
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod,
|
|
Gbl.Crs.Grps.GrpCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Check if I belong to group *****/
|
|
if (Gbl.Crs.Grps.GrpCod > 0)
|
|
if (!Grp_GetIfIBelongToGrp (Gbl.Crs.Grps.GrpCod))
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to group");
|
|
|
|
/***** Check if file is in a valid zone *****/
|
|
Gbl.FileBrowser.Type = FileMetadata.FileBrowser;
|
|
switch (Gbl.FileBrowser.Type)
|
|
{
|
|
case Brw_ADMI_DOC_CRS:
|
|
case Brw_ADMI_DOC_GRP:
|
|
case Brw_ADMI_SHR_CRS:
|
|
case Brw_ADMI_SHR_GRP:
|
|
break;
|
|
case Brw_ADMI_MRK_CRS:
|
|
case Brw_ADMI_MRK_GRP:
|
|
// Downloading a file of marks is only allowed for teachers
|
|
if (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs != Rol_TCH)
|
|
return soap_receiver_fault (soap,
|
|
"Wrong tree",
|
|
"Wrong file zone");
|
|
break;
|
|
default:
|
|
return soap_sender_fault (soap,
|
|
"Wrong tree",
|
|
"Wrong file zone");
|
|
}
|
|
|
|
/***** Set paths *****/
|
|
Brw_InitializeFileBrowser ();
|
|
Str_Copy (Gbl.FileBrowser.FilFolLnk.Path,FileMetadata.FilFolLnk.Path,
|
|
sizeof (Gbl.FileBrowser.FilFolLnk.Path) - 1);
|
|
Str_Copy (Gbl.FileBrowser.FilFolLnk.Name,FileMetadata.FilFolLnk.Name,
|
|
sizeof (Gbl.FileBrowser.FilFolLnk.Name) - 1);
|
|
Brw_SetFullPathInTree ();
|
|
|
|
/***** Get file size and date *****/
|
|
Brw_GetFileTypeSizeAndDate (&FileMetadata);
|
|
|
|
/***** Update number of views *****/
|
|
Brw_GetAndUpdateFileViews (&FileMetadata);
|
|
|
|
/***** Create and get link to download the file *****/
|
|
Brw_GetLinkToDownloadFile (FileMetadata.FilFolLnk.Path,
|
|
FileMetadata.FilFolLnk.Name,
|
|
URL);
|
|
|
|
/***** Copy data into output structure *****/
|
|
Str_Copy (getFileOut->fileName,FileMetadata.FilFolLnk.Name,NAME_MAX);
|
|
|
|
Str_Copy (getFileOut->URL,URL,WWW_MAX_BYTES_WWW);
|
|
|
|
getFileOut->size = (int) FileMetadata.Size;
|
|
|
|
getFileOut->time = (int) FileMetadata.Time;
|
|
|
|
Str_Copy (getFileOut->license,Txt_LICENSES[FileMetadata.License],
|
|
Brw_MAX_BYTES_LICENSE);
|
|
|
|
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_CRS))
|
|
{
|
|
/* Copy publisher's data into output structure */
|
|
Str_Copy (getFileOut->publisherName,Gbl.Usrs.Other.UsrDat.FullName,
|
|
Usr_MAX_BYTES_FULL_NAME);
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL);
|
|
Str_Copy (getFileOut->publisherPhoto,PhotoURL,WWW_MAX_BYTES_WWW);
|
|
}
|
|
|
|
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 Brw_FileMetadata FileMetadata;
|
|
char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1]; // Not used
|
|
char *ContentStr;
|
|
size_t Length;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getMarks;
|
|
getMarksOut->content = NULL;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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 file metadata *****/
|
|
FileMetadata.FilCod = (long) fileCode;
|
|
Brw_GetFileMetadataByCod (&FileMetadata);
|
|
|
|
if (FileMetadata.FilFolLnk.Type != Brw_IS_FILE ||
|
|
FileMetadata.IsHidden ||
|
|
(FileMetadata.FileBrowser != Brw_ADMI_MRK_CRS &&
|
|
FileMetadata.FileBrowser != Brw_ADMI_MRK_GRP))
|
|
return soap_receiver_fault (soap,
|
|
"Bad file code",
|
|
"You can not get marks from this file");
|
|
|
|
/***** Set course and group codes *****/
|
|
Brw_GetCrsGrpFromFileMetadata (FileMetadata.FileBrowser,FileMetadata.Cod,
|
|
&Gbl.Hierarchy.Node[Hie_INS].HieCod,
|
|
&Gbl.Hierarchy.Node[Hie_CTR].HieCod,
|
|
&Gbl.Hierarchy.Node[Hie_DEG].HieCod,
|
|
&Gbl.Hierarchy.Node[Hie_CRS].HieCod,
|
|
&Gbl.Crs.Grps.GrpCod);
|
|
|
|
/***** Check course and group codes *****/
|
|
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
|
|
Gbl.Hierarchy.Node[Hie_CRS].HieCod,
|
|
Gbl.Crs.Grps.GrpCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get some of my data *****/
|
|
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** 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)
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Check if I belong to group *****/
|
|
if (Gbl.Crs.Grps.GrpCod > 0)
|
|
if (!Grp_GetIfIBelongToGrp (Gbl.Crs.Grps.GrpCod))
|
|
return soap_receiver_fault (soap,
|
|
"Request forbidden",
|
|
"Requester must belong to group");
|
|
|
|
/***** Get content *****/
|
|
ContentStr = NULL;
|
|
Mrk_GetNotifMyMarks (SummaryStr, // Not used
|
|
&ContentStr,
|
|
FileMetadata.FilCod,Gbl.Usrs.Me.UsrDat.UsrCod,
|
|
Ntf_GET_CONTENT);
|
|
if (ContentStr != NULL)
|
|
{
|
|
Length = strlen (ContentStr);
|
|
getMarksOut->content = soap_malloc (soap,Length + 1);
|
|
Str_Copy (getMarksOut->content,ContentStr,Length);
|
|
free (ContentStr);
|
|
ContentStr = NULL;
|
|
}
|
|
else
|
|
{
|
|
getMarksOut->content = soap_malloc (soap,1);
|
|
getMarksOut->content[0] = '\0';
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**************** Get locations associated to a MAC address ******************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getLocation (struct soap *soap,
|
|
char *wsKey,char *MAC, // input
|
|
struct swad__getLocationOutput *getLocationOut) // output
|
|
{
|
|
int ReturnCode;
|
|
unsigned long long MACnum;
|
|
MYSQL_RES *mysql_res;
|
|
unsigned NumLocs;
|
|
|
|
/***** Initializations *****/
|
|
API_Set_gSOAP_RuntimeEnv (soap);
|
|
Gbl.WebService.Function = API_getLocation;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = API_CheckAPIKey (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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Convert MAC string to number *****/
|
|
if (sscanf (MAC,"%llx",&MACnum) != 1)
|
|
return soap_receiver_fault (soap,
|
|
"Bad MAC",
|
|
"MAC address format should be 12 hexadecimal digits");
|
|
|
|
/***** Get location *****/
|
|
NumLocs = Roo_DB_GetLocationByMAC (&mysql_res,MACnum);
|
|
|
|
API_GetLocationData (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_CheckAPIKey (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.Node[Hie_CRS].HieCod))
|
|
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;
|
|
|
|
/***** Check in (insert pair user-room) in the database *****/
|
|
/* Get the code of the inserted item */
|
|
ChkCod = Roo_DB_CheckIn (roomCode);
|
|
|
|
/***** 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_CheckAPIKey (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.
|
|
*/
|
|
switch (Roo_DB_CheckIfICanSeeUsrLocation ((long) userCode))
|
|
{
|
|
case Usr_CAN:
|
|
/***** Get list of locations *****/
|
|
NumLocs = Roo_DB_GetUsrLastLocation (&mysql_res,(long) userCode);
|
|
API_GetLocationData (soap,
|
|
&(getLastLocationOut->location),
|
|
&(getLastLocationOut->checkinTime), // Get check in time
|
|
&mysql_res,NumLocs);
|
|
break;
|
|
case Usr_CAN_NOT:
|
|
default:
|
|
/* I can not see user's location ==> reset output */
|
|
API_ResetLocation (soap, &(getLastLocationOut->location));
|
|
getLastLocationOut->checkinTime = 0L;
|
|
break;
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************* Get assignment data *******************************/
|
|
/*****************************************************************************/
|
|
|
|
static void API_GetLocationData (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 *****/
|
|
if (NumLocs) // Rooms found
|
|
{
|
|
/* Get row */
|
|
row = mysql_fetch_row (*mysql_res);
|
|
/*
|
|
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)
|
|
*/
|
|
|
|
/* Get institution code (row[0]) */
|
|
location->institutionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get institution short name (row[1]) */
|
|
Length = strlen (row[1]);
|
|
location->institutionShortName = soap_malloc (soap,Length + 1);
|
|
Str_Copy (location->institutionShortName,row[1],Length);
|
|
|
|
/* Get institution full name (row[2]) */
|
|
Length = strlen (row[2]);
|
|
location->institutionFullName = soap_malloc (soap,Length + 1);
|
|
Str_Copy (location->institutionFullName,row[2],Length);
|
|
|
|
/* Get center code (row[3]) */
|
|
location->centerCode = (int) Str_ConvertStrCodToLongCod (row[3]);
|
|
|
|
/* Get center short name (row[4]) */
|
|
Length = strlen (row[4]);
|
|
location->centerShortName = soap_malloc (soap,Length + 1);
|
|
Str_Copy (location->centerShortName,row[4],Length);
|
|
|
|
/* Get center full name (row[5]) */
|
|
Length = strlen (row[5]);
|
|
location->centerFullName = soap_malloc (soap,Length + 1);
|
|
Str_Copy (location->centerFullName,row[5],Length);
|
|
|
|
/* Get building code (row[6]) */
|
|
location->buildingCode = (int) Str_ConvertStrCodToLongCod (row[6]);
|
|
|
|
/* Get building short name (row[7]) */
|
|
Length = strlen (row[7]);
|
|
location->buildingShortName = soap_malloc (soap,Length + 1);
|
|
Str_Copy (location->buildingShortName,row[7],Length);
|
|
|
|
/* Get building full name (row[8]) */
|
|
Length = strlen (row[8]);
|
|
location->buildingFullName = soap_malloc (soap,Length + 1);
|
|
Str_Copy (location->buildingFullName,row[8],Length);
|
|
|
|
/* Get floor (row[9]) */
|
|
location->floor = (int) Str_ConvertStrCodToLongCod (row[9]);
|
|
|
|
/* Get room code (row[10]) */
|
|
location->roomCode = (int) Str_ConvertStrCodToLongCod (row[10]);
|
|
|
|
/* Get room short name (row[11]) */
|
|
Length = strlen (row[11]);
|
|
location->roomShortName = soap_malloc (soap,Length + 1);
|
|
Str_Copy (location->roomShortName,row[11],Length);
|
|
|
|
/* Get room full name (row[12]) */
|
|
Length = strlen (row[12]);
|
|
location->roomFullName = soap_malloc (soap,Length + 1);
|
|
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);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No room found ==> reset output */
|
|
API_ResetLocation (soap,location);
|
|
|
|
if (CheckInTime)
|
|
*CheckInTime = 0L;
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (mysql_res);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************* Get assignment data *******************************/
|
|
/*****************************************************************************/
|
|
|
|
static void API_ResetLocation (struct soap *soap,
|
|
struct swad__location *location)
|
|
{
|
|
location->institutionCode = -1;
|
|
location->institutionShortName = soap_malloc (soap,1);
|
|
location->institutionShortName[0] = '\0';
|
|
location->institutionFullName = soap_malloc (soap,1);
|
|
location->institutionFullName[0] = '\0';
|
|
|
|
location->centerCode = -1;
|
|
location->centerShortName = soap_malloc (soap,1);
|
|
location->centerShortName[0] = '\0';
|
|
location->centerFullName = soap_malloc (soap,1);
|
|
location->centerFullName[0] = '\0';
|
|
|
|
location->buildingCode = -1;
|
|
location->buildingShortName = soap_malloc (soap,1);
|
|
location->buildingShortName[0] = '\0';
|
|
location->buildingFullName = soap_malloc (soap,1);
|
|
location->buildingFullName[0] = '\0';
|
|
|
|
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';
|
|
}
|