swad-core/swad_API.c

5451 lines
209 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-2023 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_level.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_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,
bool UsrIDIsVisible);
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_GetDataOfLocation (struct soap *soap,
struct swad__location *location,
time_t *CheckInTime,
MYSQL_RES **mysql_res,
unsigned NumLocs);
static void API_ResetLocation (struct soap *soap,
struct swad__location *location);
/*****************************************************************************/
/******* 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,
true); // I am creating my own account
/***** 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[Cns_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,Cns_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,Cns_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
{
int ReturnCode;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
char PhotoURL[Cns_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,Cns_MAX_BYTES_WWW + 1);
loginBySessionKeyOut->userBirthday = soap_malloc (soap,Dat_LENGTH_YYYYMMDD + 1);
loginBySessionKeyOut->degreeName = soap_malloc (soap,Cns_HIERARCHY_MAX_BYTES_FULL_NAME + 1);
loginBySessionKeyOut->courseName = soap_malloc (soap,Cns_HIERARCHY_MAX_BYTES_FULL_NAME + 1);
/***** 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.Crs.CrsCod = Str_ConvertStrCodToLongCod (row[2]);
Crs_GetDataOfCourseByCod (&Gbl.Hierarchy.Crs);
loginBySessionKeyOut->courseCode = (int) Gbl.Hierarchy.Crs.CrsCod;
Str_Copy (loginBySessionKeyOut->courseName,Gbl.Hierarchy.Crs.FullName,
Cns_HIERARCHY_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.Crs.CrsCod); // Get some user's data from database
/***** Get degree (row[1]) *****/
Gbl.Hierarchy.Deg.DegCod = Str_ConvertStrCodToLongCod (row[1]);
Deg_GetDataOfDegreeByCod (&Gbl.Hierarchy.Deg);
loginBySessionKeyOut->degreeCode = (int) Gbl.Hierarchy.Deg.DegCod;
Str_Copy (loginBySessionKeyOut->degreeName,Gbl.Hierarchy.Deg.FullName,
Cns_HIERARCHY_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.Deg.DegCod = Crs_DB_GetCurrentDegCodFromCurrentCrsCod ();
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,Cns_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.Crs.CrsCod = (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_CURRENT_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,Cns_HIERARCHY_MAX_BYTES_SHRT_NAME + 1);
getCoursesOut->coursesArray.__ptr[NumCrs].courseFullName =
soap_malloc (soap,Cns_HIERARCHY_MAX_BYTES_FULL_NAME + 1);
Str_Copy (getCoursesOut->coursesArray.__ptr[NumCrs].courseShortName,
row[1],Cns_HIERARCHY_MAX_BYTES_SHRT_NAME);
Str_Copy (getCoursesOut->coursesArray.__ptr[NumCrs].courseFullName,
row[2],Cns_HIERARCHY_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_INTRODUCTION ] = "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.Crs.CrsCod = (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.Crs.CrsCod,
-1L)) != SOAP_OK)
return ReturnCode;
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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.Crs.CrsCod,
Gbl.Crs.Info.Type,
&FromDB);
Length = strlen (NamesInWSForInfoSrc[FromDB.Src]);
getCourseInfo->infoSrc = soap_malloc (soap,Length + 1);
Str_Copy (getCourseInfo->infoSrc,NamesInWSForInfoSrc[FromDB.Src],Length);
/***** 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,Cns_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.Crs.CrsCod);
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.Crs.CrsCod,Gbl.Crs.Info.Type,
TxtHTML,NULL);
if (TxtHTML[0])
{
/***** Create a unique name for the file *****/
snprintf (FileNameHTMLTmp,sizeof (FileNameHTMLTmp),"%s/%s_info.html",
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,false); // Convert from HTML to recpectful HTML
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.Crs.CrsCod,Gbl.Crs.Info.Type,PathRelDirHTML);
/***** Open file with web page *****/
/* 1. Check if index.html exists */
snprintf (PathRelFileHTML,sizeof (PathRelFileHTML),"%s/index.html",
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.Crs.CrsCod = (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.Crs.CrsCod,
-1L)) != SOAP_OK)
return ReturnCode;
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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.Deg.DegCod = Crs_DB_GetCurrentDegCodFromCurrentCrsCod ();
/***** 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 (HieLvl_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.Crs.CrsCod = (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 == HieLvl_CRS) // Course selected
/***** Check course *****/
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
-1L)) != SOAP_OK)
return ReturnCode;
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
if (Gbl.Hierarchy.Level == HieLvl_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 == HieLvl_CRS)
/***** Get degree of current course *****/
Gbl.Hierarchy.Deg.DegCod = Crs_DB_GetCurrentDegCodFromCurrentCrsCod ();
/***** 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 == HieLvl_CRS) ? HieLvl_CRS :
HieLvl_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;
bool ICanSeeUsrID;
/***** Initialize result *****/
getUsersOut->numUsers = 0;
getUsersOut->usersArray.__size = 0;
getUsersOut->usersArray.__ptr = NULL;
NumUsrs = Gbl.Usrs.LstUsrs[Role].NumUsrs;
if (NumUsrs)
{
getUsersOut->numUsers = (int) NumUsrs;
getUsersOut->usersArray.__size = (int) NumUsrs;
getUsersOut->usersArray.__ptr = soap_malloc (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.Crs.CrsCod = (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.Crs.CrsCod <= 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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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.Crs.CrsCod = (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.Crs.CrsCod <= 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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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_DECIMAL_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.Crs.CrsCod = (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.Crs.CrsCod <= 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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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_DECIMAL_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_DECIMAL_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,
bool UsrIDIsVisible)
{
char PhotoURL[Cns_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 (UsrIDIsVisible && 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;
long AttCod;
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
long StartTime;
long EndTime;
size_t Length;
/***** Initializations *****/
API_Set_gSOAP_RuntimeEnv (soap);
Gbl.WebService.Function = API_getAttendanceEvents;
Gbl.Hierarchy.Crs.CrsCod = (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.Crs.CrsCod <= 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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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_GetDataOfAllAttEvents (&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 code (row[0]) */
AttCod = Str_ConvertStrCodToLongCod (row[0]);
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].attendanceEventCode = (int) AttCod;
/* Get whether the attendance event is hidden or not (row[1]) */
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].hidden = (row[1][0] == 'Y') ? 1 :
0;
/* Get user's code of the user who created the event (row[2]) */
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[2]);
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Gbl.Hierarchy.Crs.CrsCod)) // Get some user's data from database
{
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
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;
}
/* Get event start time (row[3]) */
StartTime = 0L;
if (row[3])
sscanf (row[3],"%ld",&StartTime);
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].startTime = StartTime;
/* Get event end time (row[4]) */
EndTime = 0L;
if (row[4])
sscanf (row[4],"%ld",&EndTime);
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].endTime = EndTime;
/* Get whether teachers comments are visible ('Y') or hidden ('N') (row[5]) */
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].commentsTeachersVisible = (row[5][0] == 'Y') ? 1 :
0;
/* Get title of the event (row[6]) */
Length = strlen (row[6]);
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].title =
soap_malloc (soap,Length + 1);
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].title,
row[6],Length);
/* Get Txt (row[7]) */
Length = strlen (row[7]);
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].text =
soap_malloc (soap,Length + 1);
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].text,
row[7],Length);
/* Get list of groups for this attendance event */
API_GetListGrpsInAttendanceEventFromDB (soap,
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_DECIMAL_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.Crs.CrsCod = (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.Crs.CrsCod <= 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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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_GetDataOfAttEventByCod (&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.Hidden = (hidden ? true :
false);
/* 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_CreateAttEvent (&Event,text); // Add new attendance event to database
else
Att_UpdateAttEvent (&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_GetDataOfAttEventByCod (&Event);
Gbl.Hierarchy.Crs.CrsCod = Event.CrsCod;
}
else
return soap_receiver_fault (soap,
"Request forbidden",
"Attendance event does not exist");
/***** Check if course code is correct *****/
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
return soap_sender_fault (soap,
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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_RemoveAttEventFromDB (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_DECIMAL_DIGITS_LONG + 1];
unsigned NumGrp;
/***** Count number of groups *****/
for (Ptr = Groups, NumGrp = 0;
*Ptr;
NumGrp++)
Str_GetNextStringUntilComma (&Ptr,LongStr,Cns_MAX_DECIMAL_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_DECIMAL_DIGITS_LONG);
Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrp] = Str_ConvertStrCodToLongCod (LongStr);
if (Grp_DB_CheckIfGrpBelongsToCrs (Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrp],Gbl.Hierarchy.Crs.CrsCod))
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[Cns_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_GetDataOfAttEventByCod (&Event);
Gbl.Hierarchy.Crs.CrsCod = Event.CrsCod;
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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_GetListUsrsInAttEvent (&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_GetDataOfAttEventByCod (&Event))
return SOAP_OK; // return with success = 0
Gbl.Hierarchy.Crs.CrsCod = Event.CrsCod;
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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_RemoveUsrsAbsentWithoutCommentsFromAttEvent (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 const char *Ntf_WSNotifyEvents[Ntf_NUM_NOTIFY_EVENTS];
extern const char *Txt_Forum;
extern const char *Txt_Course;
extern const char *Txt_Degree;
extern const char *Txt_Center;
extern const char *Txt_Institution;
int ReturnCode;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumNotifs;
unsigned NumNotif;
long NtfCod;
Ntf_NotifyEvent_t NotifyEvent;
long EventTime;
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
struct Hie_Hierarchy Hie;
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;
/***** 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 course (row[7]) */
Hie.Crs.CrsCod = Str_ConvertStrCodToLongCod (row[7]);
Crs_GetDataOfCourseByCod (&Hie.Crs);
/* Get user's code of the user who caused the event (row[3]) */
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[3]);
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Hie.Crs.CrsCod)) // 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,Cns_MAX_BYTES_WWW + 1);
Str_Copy (getNotificationsOut->notificationsArray.__ptr[NumNotif].userPhoto,
PhotoURL,Cns_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 institution (row[4]) */
Hie.Ins.InsCod = Str_ConvertStrCodToLongCod (row[4]);
Ins_GetDataOfInstitByCod (&Hie.Ins);
/* Get center (row[5]) */
Hie.Ctr.CtrCod = Str_ConvertStrCodToLongCod (row[5]);
Ctr_GetDataOfCenterByCod (&Hie.Ctr);
/* Get degree (row[6]) */
Hie.Deg.DegCod = Str_ConvertStrCodToLongCod (row[6]);
Deg_GetDataOfDegreeByCod (&Hie.Deg);
/* 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_GetForumTypeAndLocationOfAPost (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 if (Hie.Crs.CrsCod > 0)
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
Txt_Course,Hie.Crs.ShrtName);
else if (Hie.Deg.DegCod > 0)
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
Txt_Degree,Hie.Deg.ShrtName);
else if (Hie.Ctr.CtrCod > 0)
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
Txt_Center,Hie.Ctr.ShrtName);
else if (Hie.Ins.InsCod > 0)
sprintf (getNotificationsOut->notificationsArray.__ptr[NumNotif].location,"%s: %s",
Txt_Institution,Hie.Ins.ShrtName);
else
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.Crs.CrsCod,Gbl.Usrs.Me.UsrDat.UsrCod,
true);
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_DECIMAL_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_DECIMAL_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_CURRENT_CRS))
{
/* This received message must be notified by email? */
NotifyByEmail = (!Usr_ItsMe (Gbl.Usrs.Other.UsrDat.UsrCod) &&
(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,
false);
}
}
}
/***** 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.Crs.CrsCod = (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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** Check course and group codes *****/
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
-1L)) != SOAP_OK)
return ReturnCode;
/***** Get degree of current course *****/
Gbl.Hierarchy.Deg.DegCod = Crs_DB_GetCurrentDegCodFromCurrentCrsCod ();
/***** 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.Crs.CrsCod = (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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** Check if course code is correct *****/
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
return soap_sender_fault (soap,
"Bad course code",
"Course code must be a integer greater than 0");
/***** 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.Deg.DegCod = Crs_DB_GetCurrentDegCodFromCurrentCrsCod ();
/***** 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.Crs.CrsCod = (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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** Check if course code is correct *****/
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
return soap_sender_fault (soap,
"Bad course code",
"Course code must be a integer greater than 0");
/***** 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.Deg.DegCod = Crs_DB_GetCurrentDegCodFromCurrentCrsCod ();
/***** 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_DECIMAL_DIGITS_LONG + 1];
char DegreesStr[API_MAX_BYTES_DEGREES_STR + 1];
char DegStr[ 1 + 1 + Cns_MAX_DECIMAL_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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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_DECIMAL_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_GetDataOfAnswers (&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[Cns_MAX_BYTES_WWW + 1];
long StartTime;
long EndTime;
size_t Length;
/***** Initializations *****/
API_Set_gSOAP_RuntimeEnv (soap);
Gbl.WebService.Function = API_getGames;
Gbl.Hierarchy.Crs.CrsCod = (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.Crs.CrsCod <= 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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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.Crs.CrsCod)) // 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[Cns_MAX_BYTES_WWW + 1];
long StartTime;
long EndTime;
size_t Length;
/***** Initializations *****/
API_Set_gSOAP_RuntimeEnv (soap);
Gbl.WebService.Function = API_getMatches;
Gbl.Hierarchy.Crs.CrsCod = (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.Crs.CrsCod <= 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_GetDataOfGameByCod (&Game);
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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.Crs.CrsCod)) // 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;
bool ICanPlayThisMatchBasedOnGrps;
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.Crs.CrsCod = (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.Crs.CrsCod <= 0)
return soap_sender_fault (soap,
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get game data from database *****/
if (Game.GamCod <= 0)
return soap_sender_fault (soap,
"Bad game code",
"Game code must be a integer greater than 0");
Gam_GetDataOfGameByCod (&Game);
/***** Get match data from database *****/
if (Match.MchCod <= 0)
return soap_sender_fault (soap,
"Bad match code",
"Match code must be a integer greater than 0");
Mch_GetDataOfMatchByCod (&Match);
/* 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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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? *****/
ICanPlayThisMatchBasedOnGrps = Mch_CheckIfICanPlayThisMatchBasedOnGrps (&Match);
if (!ICanPlayThisMatchBasedOnGrps)
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.Crs.CrsCod = (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.Crs.CrsCod <= 0)
return soap_sender_fault (soap,
"Bad course code",
"Course code must be a integer greater than 0");
/***** Get game data from database *****/
if (Game.GamCod <= 0)
return soap_sender_fault (soap,
"Bad game code",
"Game code must be a integer greater than 0");
Gam_GetDataOfGameByCod (&Game);
/***** Get match data from database *****/
if (Match.MchCod <= 0)
return soap_sender_fault (soap,
"Bad match code",
"Match code must be a integer greater than 0");
Mch_GetDataOfMatchByCod (&Match);
/***** 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_DECIMAL_DIGITS_LONG + 1];
size_t Length;
/***** Get list of groups *****/
if ((NumGrps = Mch_DB_GetGrpCodsAssociatedToMatch (&mysql_res,MchCod))) // Groups found
{
Length = NumGrps * (Cns_MAX_DECIMAL_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.Crs.CrsCod = (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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** Check course and group codes *****/
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
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.Crs.CrsCod = (courseCode > 0) ? (long) courseCode :
-1L;
Gbl.Crs.Grps.GrpCod = (groupCode > 0) ? (long) groupCode :
-1L;
snprintf (Gbl.Crs.PathPriv,sizeof (Gbl.Crs.PathPriv),"%s/%ld",
Cfg_PATH_CRS_PRIVATE,Gbl.Hierarchy.Crs.CrsCod);
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_CheckIfFileOrFolderIsSetAsHiddenInDB (Brw_IS_FOLDER,
Gbl.FileBrowser.FilFolLnk.Full)) // If root folder is visible
API_ListDir (XML,1,
Gbl.FileBrowser.Priv.PathRootFolder,
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[Cns_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_CheckIfFileOrFolderIsSetAsHiddenInDB (FileType,
Gbl.FileBrowser.FilFolLnk.Full))
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_CURRENT_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[Cns_MAX_BYTES_WWW + 1];
char PhotoURL[Cns_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,Cns_MAX_BYTES_WWW + 1);
getFileOut->license = soap_malloc (soap,Brw_MAX_BYTES_LICENSE + 1);
getFileOut->publisherName = soap_malloc (soap,Usr_MAX_BYTES_FULL_NAME + 1);
getFileOut->publisherPhoto = soap_malloc (soap,Cns_MAX_BYTES_WWW + 1);
/***** 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.Ins.InsCod,
&Gbl.Hierarchy.Ctr.CtrCod,
&Gbl.Hierarchy.Deg.DegCod,
&Gbl.Hierarchy.Crs.CrsCod,
&Gbl.Crs.Grps.GrpCod);
Hie_InitHierarchy ();
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** Check course and group codes *****/
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
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,Cns_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_CURRENT_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,Cns_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.Ins.InsCod,
&Gbl.Hierarchy.Ctr.CtrCod,
&Gbl.Hierarchy.Deg.DegCod,
&Gbl.Hierarchy.Crs.CrsCod,
&Gbl.Crs.Grps.GrpCod);
/***** Check course and group codes *****/
if ((ReturnCode = API_CheckCourseAndGroupCodes (soap,
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Crs.Grps.GrpCod)) != SOAP_OK)
return ReturnCode;
/***** Get some of my data *****/
if (!API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.Hierarchy.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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,true);
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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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_GetDataOfLocation (soap,
&(getLocationOut->location),
NULL, // Don't get check in time
&mysql_res,NumLocs);
return SOAP_OK;
}
/*****************************************************************************/
/***************** Check in (send user's current location) *******************/
/*****************************************************************************/
int swad__sendMyLocation (struct soap *soap,
char *wsKey,int roomCode, // input
struct swad__sendMyLocationOutput *sendMyLocationOut) // output
{
int ReturnCode;
long ChkCod;
/***** Initializations *****/
API_Set_gSOAP_RuntimeEnv (soap);
Gbl.WebService.Function = API_sendMyLocation;
/***** Default values returned on error *****/
sendMyLocationOut->success = 0; // error
/***** Check web service key *****/
if ((ReturnCode = API_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.Crs.CrsCod))
return soap_receiver_fault (soap,
"Can not get user's data from database",
"User does not exist in database");
Gbl.Usrs.Me.Logged = true;
Gbl.Usrs.Me.Role.Logged = Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs;
/***** 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.
*/
if (Roo_DB_CheckIfICanSeeUsrLocation ((long) userCode))
{
/***** Get list of locations *****/
NumLocs = Roo_DB_GetUsrLastLocation (&mysql_res,(long) userCode);
API_GetDataOfLocation (soap,
&(getLastLocationOut->location),
&(getLastLocationOut->checkinTime), // Get check in time
&mysql_res,NumLocs);
}
else
{
/* I can not see user's location ==> reset output */
API_ResetLocation (soap, &(getLastLocationOut->location));
getLastLocationOut->checkinTime = 0L;
}
return SOAP_OK;
}
/*****************************************************************************/
/************************* Get assignment data *******************************/
/*****************************************************************************/
static void API_GetDataOfLocation (struct soap *soap,
struct swad__location *location,
time_t *CheckInTime,
MYSQL_RES **mysql_res,
unsigned NumLocs)
{
MYSQL_ROW row;
size_t Length;
/***** Get data of location from database *****/
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';
}