swad-core/swad_API.c

5432 lines
208 KiB
C

// swad_API.c: SWAD web API provided to external plugins
/*
SWAD (Shared Workspace At a Distance),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-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_GetLocationData (struct soap *soap,
struct swad__location *location,
time_t *CheckInTime,
MYSQL_RES **mysql_res,
unsigned NumLocs);
static void API_ResetLocation (struct soap *soap,
struct swad__location *location);
/*****************************************************************************/
/******* Function called when a web service if required by a plugin **********/
/*****************************************************************************/
static struct soap *API_soap = NULL; // gSOAP runtime environment
static void API_Set_gSOAP_RuntimeEnv (struct soap *soap)
{
API_soap = soap;
}
struct soap *API_Get_gSOAP_RuntimeEnv (void)
{
return API_soap;
}
/*****************************************************************************/
/******* Function called when a web service if required by a plugin **********/
/*****************************************************************************/
void API_WebService (void)
{
struct soap *soap;
if ((soap = soap_new ())) // Allocate and initialize runtime context
{
soap_serve (soap);
API_FreeSoapContext (soap);
}
}
/*****************************************************************************/
/******* Function called to exit on error when executing web service *********/
/*****************************************************************************/
void API_Exit (const char *DetailErrorMessage)
{
struct soap *soap = API_Get_gSOAP_RuntimeEnv ();
int ReturnCode = 0;
if (soap)
{
ReturnCode = (DetailErrorMessage ? soap_receiver_fault (soap,
"Error in swad web service",
DetailErrorMessage) :
0);
API_FreeSoapContext (soap);
}
exit (ReturnCode);
}
/*****************************************************************************/
/****************************** Free SOAP context ****************************/
/*****************************************************************************/
static void API_FreeSoapContext (struct soap *soap)
{
soap_destroy (soap); // delete managed C++ objects
soap_end (soap); // delete managed memory
soap_free (soap); // free the context
API_Set_gSOAP_RuntimeEnv (NULL); // set pointer to NULL in order to not try to free the context again
}
/*****************************************************************************/
/****** Check if the application key of the requester of a web service *******/
/****** is one of the application keys allowed in the plugins *******/
/*****************************************************************************/
static int API_GetPlgCodFromAppKey (struct soap *soap,
const char *appKey)
{
/***** Get plugin code from application key *****/
if ((Gbl.WebService.PlgCod = Plg_DB_GetPlgCodFromAppKey (appKey)) <= 0)
return soap_sender_fault (soap,
"Unknown application key",
"Unknown application");
return SOAP_OK;
}
/*****************************************************************************/
/****** Get the name of a web service function given the function code *******/
/*****************************************************************************/
const char *API_GetFunctionNameFromFunCod (long FunCod)
{
if (FunCod < 0 || FunCod > API_NUM_FUNCTIONS)
return API_Functions[0];
return API_Functions[FunCod];
}
/*****************************************************************************/
/****** Check if a session identifier is valid and exists in database ********/
/*****************************************************************************/
static int API_CheckIdSession (struct soap *soap,
const char *IdSes)
{
const char *Ptr;
unsigned i;
/***** Check if pointer is NULL *****/
if (IdSes == NULL)
return soap_sender_fault (soap,
"Bad session identifier",
"Session identifier is a null pointer");
/***** Check length of session identifier *****/
if (strlen (IdSes) != Cns_BYTES_SESSION_ID)
return soap_sender_fault (soap,
"Bad session identifier",
"The length of the session identifier is wrong");
/***** Check if session identifier is in base64url *****/
for (Ptr = IdSes;
*Ptr;
Ptr++)
{
for (i = 0;
i < 64;
i++) // Check if this character is one of the allowed characters
if (*Ptr == Str_BIN_TO_BASE64URL[i])
break;
if (i == 64) // Character not found
return soap_sender_fault (soap,
"Bad session identifier",
"The session identifier must contain only base64url characters");
}
/***** Query if session identifier already exists in database *****/
if (!Ses_DB_CheckIfSessionExists (IdSes))
return soap_receiver_fault (soap,
"Bad session identifier",
"Session identifier does not exist in database");
return SOAP_OK;
}
/*****************************************************************************/
/************** Check if a web service key exists in database ****************/
/*****************************************************************************/
static int API_CheckAPIKey (char APIKey[API_BYTES_KEY + 1])
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
/***** Set default user's code *****/
Gbl.Usrs.Me.UsrDat.UsrCod = -1L;
Gbl.Usrs.Me.Logged = false;
Gbl.WebService.PlgCod = -1L;
/***** Check that key does not exist in database *****/
if (API_DB_GetDataFromAPIKey (&mysql_res,APIKey))
{
row = mysql_fetch_row (mysql_res);
Gbl.Usrs.Me.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
Gbl.Usrs.Me.Logged = true;
Gbl.WebService.PlgCod = Str_ConvertStrCodToLongCod (row[1]);
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/** Check if a course code and a group code are valid and exist in database **/
/*****************************************************************************/
static int API_CheckCourseAndGroupCodes (struct soap *soap,
long CrsCod,long GrpCod)
{
/***** Check if course code is correct *****/
if (CrsCod <= 0)
return soap_sender_fault (soap,
"Bad course code",
"Course code must be a integer greater than 0");
/***** Query if course code already exists in database *****/
if (!Crs_DB_CheckIfCrsCodExists (CrsCod))
return soap_sender_fault (soap,
"Bad course code",
"Course code does not exist in database");
/***** Course code exists in database, so check if group code exists in database and belongs to course *****/
if (GrpCod > 0) // <= 0 means "the whole course"
if (!Grp_DB_CheckIfGrpBelongsToCrs (GrpCod,CrsCod))
return soap_sender_fault (soap,
"Bad group code",
"Group code does not exist in database or it's not a group of the specified course");
return SOAP_OK;
}
/*****************************************************************************/
/***** Generate a key used in subsequents calls to other web services ********/
/*****************************************************************************/
static int API_GenerateNewAPIKey (struct soap *soap,
long UsrCod,
char APIKey[API_BYTES_KEY + 1])
{
/***** Remove expired web service keys *****/
API_DB_RemoveOldAPIKeys ();
/***** Create a unique name for the key *****/
Str_Copy (APIKey,Cry_GetUniqueNameEncrypted (),API_BYTES_KEY);
/***** Check that key does not exist in database *****/
if (API_DB_CheckIfAPIKeyExists (APIKey))
return soap_receiver_fault (soap,
"Error when generating key",
"Generated key already existed in database");
/***** Insert key into database *****/
API_DB_CreateAPIKey (APIKey,UsrCod,Gbl.WebService.PlgCod);
return SOAP_OK;
}
/*****************************************************************************/
/************ Get user's data from database giving a user's code *************/
/*****************************************************************************/
// Return false if UsrDat->UsrCod does not exist ini database
static bool API_GetSomeUsrDataFromUsrCod (struct Usr_Data *UsrDat,long CrsCod)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
bool UsrFound;
/***** Check if user's code is valid *****/
if (UsrDat->UsrCod <= 0)
return false;
/***** Get some user's data *****/
if ((UsrFound = Usr_DB_GetSomeUsrDataFromUsrCod (&mysql_res,UsrDat->UsrCod)))
{
/***** Read some user's data *****/
row = mysql_fetch_row (mysql_res);
/* Get user's name (row[0], row[1], row[2]) and photo (row[3]) */
Str_Copy (UsrDat->Surname1,row[0],sizeof (UsrDat->Surname1) - 1);
Str_Copy (UsrDat->Surname2,row[1],sizeof (UsrDat->Surname2) - 1);
Str_Copy (UsrDat->FrstName,row[2],sizeof (UsrDat->FrstName) - 1);
Str_Copy (UsrDat->Photo ,row[3],sizeof (UsrDat->Photo ) - 1);
/* Get user's brithday (row[4]) */
Dat_GetDateFromYYYYMMDD (&(UsrDat->Birthday),row[4]);
/***** Get list of user's IDs *****/
ID_GetListIDsFromUsrCod (UsrDat);
/***** Get user's nickname *****/
Nck_DB_GetNicknameFromUsrCod (UsrDat->UsrCod,UsrDat->Nickname);
/***** Get user's role *****/
if (CrsCod > 0)
/* Get the role in the given course */
UsrDat->Roles.InCurrentCrs = Rol_DB_GetRoleUsrInCrs (UsrDat->UsrCod,CrsCod);
else
/* Get the maximum role in any course */
UsrDat->Roles.InCurrentCrs = Rol_DB_GetMaxRoleUsrInCrss (UsrDat->UsrCod);
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return UsrFound;
}
/*****************************************************************************/
/**************************** Get info of my marks ***************************/
/*****************************************************************************/
#define API_CHECK_NEW_ACCOUNT_OK 0
#define API_CHECK_NEW_ACCOUNT_NICKNAME_NOT_VALID -1
#define API_CHECK_NEW_ACCOUNT_NICKNAME_REGISTERED_BY_ANOTHER_USER -2
#define API_CHECK_NEW_ACCOUNT_EMAIL_NOT_VALID -3
#define API_CHECK_NEW_ACCOUNT_EMAIL_REGISTERED_BY_ANOTHER_USER -4
#define API_CHECK_NEW_ACCOUNT_PASSWORD_NOT_VALID -5
int swad__createAccount (struct soap *soap,
char *userNickname,char *userEmail,char *userPassword,char *appKey, // input
struct swad__createAccountOutput *createAccountOut) // output
{
char NewNickWithoutArr[Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1];
char NewEncryptedPassword[Pwd_BYTES_ENCRYPTED_PASSWORD + 1];
int Result;
int ReturnCode;
/***** Initializations *****/
API_Set_gSOAP_RuntimeEnv (soap);
Gbl.WebService.Function = API_createAccount;
/***** Allocate space for strings *****/
createAccountOut->wsKey = soap_malloc (soap,API_BYTES_KEY + 1);
/***** Default values returned on error *****/
createAccountOut->userCode = 0; // Undefined error
createAccountOut->wsKey[0] = '\0';
/***** Get plugin code *****/
if ((ReturnCode = API_GetPlgCodFromAppKey (soap,appKey)) != SOAP_OK)
return ReturnCode;
/***** Check parameters used to create the new account *****/
Result = API_CheckParsNewAccount (userNickname, // Input
NewNickWithoutArr, // Output
userEmail, // Input-output
userPassword, // Input
NewEncryptedPassword); // Output
if (Result < 0)
{
createAccountOut->userCode = Result;
return SOAP_OK;
}
/***** User's has no ID *****/
Gbl.Usrs.Me.UsrDat.IDs.Num = 0;
Gbl.Usrs.Me.UsrDat.IDs.List = NULL;
/***** Set password to the password typed by the user *****/
Str_Copy (Gbl.Usrs.Me.UsrDat.Password,NewEncryptedPassword,
sizeof (Gbl.Usrs.Me.UsrDat.Password) - 1);
/***** User does not exist in the platform, so create him/her! *****/
Acc_CreateNewUsr (&Gbl.Usrs.Me.UsrDat,Usr_ME);
/***** Save nickname *****/
Nck_DB_UpdateNick (Gbl.Usrs.Me.UsrDat.UsrCod,NewNickWithoutArr);
Str_Copy (Gbl.Usrs.Me.UsrDat.Nickname,NewNickWithoutArr,
sizeof (Gbl.Usrs.Me.UsrDat.Nickname) - 1);
/***** Save email *****/
if (Mai_UpdateEmailInDB (&Gbl.Usrs.Me.UsrDat,userEmail))
{
/* Email updated sucessfully */
Str_Copy (Gbl.Usrs.Me.UsrDat.Email,userEmail,
sizeof (Gbl.Usrs.Me.UsrDat.Email) - 1);
Gbl.Usrs.Me.UsrDat.EmailConfirmed = false;
}
/***** Copy new user's code *****/
createAccountOut->userCode = Gbl.Usrs.Me.UsrDat.UsrCod;
/***** Generate a key used in subsequents calls to other web services *****/
return API_GenerateNewAPIKey (soap,
(long) createAccountOut->userCode,
createAccountOut->wsKey);
}
/*****************************************************************************/
/************* Get parameters for the creation of a new account **************/
/*****************************************************************************/
// Return false on error
//char *userNickname,char *userEmail,char *userID,char *userPassword
static int API_CheckParsNewAccount (char *NewNickWithArr, // Input
char NewNickWithoutArr[Nck_MAX_BYTES_NICK_WITHOUT_ARROBA + 1], // Output
char *NewEmail, // Input-output
char *NewPlainPassword, // Input
char NewEncryptedPassword[Pwd_BYTES_ENCRYPTED_PASSWORD + 1]) // Output
{
char CopyOfNewNick[Nck_MAX_BYTES_NICK_WITH_ARROBA + 1];
/***** Step 1/3: Check new nickname *****/
/* Make a copy without possible starting arrobas */
if (Nck_CheckIfNickWithArrIsValid (NewNickWithArr)) // If new nickname is valid
{
/***** Remove leading arrobas *****/
Str_Copy (CopyOfNewNick,NewNickWithArr,sizeof (CopyOfNewNick) - 1);
Str_RemoveLeadingArrobas (CopyOfNewNick);
/***** Check if the new nickname matches any of the nicknames of other users *****/
if (Nck_DB_CheckIfNickMatchesAnyNick (CopyOfNewNick)) // Already without leading arrobas
return API_CHECK_NEW_ACCOUNT_NICKNAME_REGISTERED_BY_ANOTHER_USER;
/***** Output value of nickname without leading arrobas *****/
Str_Copy (NewNickWithoutArr,CopyOfNewNick,Nck_MAX_BYTES_NICK_WITHOUT_ARROBA);
}
else // New nickname is not valid
return API_CHECK_NEW_ACCOUNT_NICKNAME_NOT_VALID;
/***** Step 2/3: Check new email *****/
if (Mai_CheckIfEmailIsValid (NewEmail)) // New email is valid
{
/***** Check if the new email matches any of the confirmed emails of other users *****/
if (Mai_DB_CheckIfEmailExistsConfirmed (NewEmail)) // An email of another user is the same that my email
return API_CHECK_NEW_ACCOUNT_EMAIL_REGISTERED_BY_ANOTHER_USER;
}
else // New email is not valid
return API_CHECK_NEW_ACCOUNT_EMAIL_NOT_VALID;
/***** Step 3/3: Check new password *****/
Cry_EncryptSHA512Base64 (NewPlainPassword,NewEncryptedPassword);
if (!Pwd_SlowCheckIfPasswordIsGood (NewPlainPassword,NewEncryptedPassword,-1L)) // New password is good?
return API_CHECK_NEW_ACCOUNT_PASSWORD_NOT_VALID;
return API_CHECK_NEW_ACCOUNT_OK;
}
/*****************************************************************************/
/****************** Login user by user, password and key *********************/
/*****************************************************************************/
int swad__loginByUserPasswordKey (struct soap *soap,
char *userID,char *userPassword,char *appKey, // input
struct swad__loginByUserPasswordKeyOutput *loginByUserPasswordKeyOut) // output
{
char UsrIDNickOrEmail[Cns_MAX_BYTES_USR_LOGIN + 1];
int ReturnCode;
char PhotoURL[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_GetCourseDataByCod (&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_GetDegreeDataByCod (&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,Str_DONT_REMOVE_SPACES);
ALn_InsertLinks (TxtHTML,Cns_MAX_BYTES_LONG_TEXT,60); // Insert links
/* Write text */
fprintf (FileHTMLTmp,"%s",TxtHTML);
/***** Write end of page into file *****/
fprintf (FileHTMLTmp,"</div>\n"
"</html>\n"
"</body>\n");
/***** Compute length of file *****/
Length = (size_t) ftell (FileHTMLTmp);
/***** Allocate memory for buffer *****/
if ((*HTMLBuffer = malloc (Length + 1)) == NULL)
{
fclose (FileHTMLTmp);
unlink (FileNameHTMLTmp);
return soap_receiver_fault (soap,
"Plain text can not be copied into buffer",
"Not enough memory for buffer");
}
/***** Copy file content into buffer *****/
fseek (FileHTMLTmp,0L,SEEK_SET);
if (fread (*HTMLBuffer,sizeof (char),Length,FileHTMLTmp) != Length)
{
fclose (FileHTMLTmp);
unlink (FileNameHTMLTmp);
return soap_receiver_fault (soap,
"Plain text can not be copied into buffer",
"Error reading file into buffer");
}
(*HTMLBuffer)[Length] = '\0';
/***** Close and remove temporary file *****/
fclose (FileHTMLTmp);
unlink (FileNameHTMLTmp);
}
return SOAP_OK;
}
/*****************************************************************************/
/************* Check if exists and write page into HTML buffer ***************/
/*****************************************************************************/
static int API_WritePageIntoHTMLBuffer (struct soap *soap,
char **HTMLBuffer)
{
char PathRelDirHTML[PATH_MAX + 1];
char PathRelFileHTML[PATH_MAX + 1 + 10 + 1];
FILE *FileHTML;
bool FileExists = false;
size_t Length;
/***** Initialize buffer *****/
*HTMLBuffer = NULL;
/***** Build path of directory containing web page *****/
Inf_BuildPathPage (Gbl.Hierarchy.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;
struct Att_Event Event;
char PhotoURL[Cns_MAX_BYTES_WWW + 1];
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_GetAllEventsData (&mysql_res,courseCode);
getAttendanceEventsOut->eventsArray.__size =
getAttendanceEventsOut->numEvents = (int) NumAttEvents;
if (getAttendanceEventsOut->numEvents == 0)
getAttendanceEventsOut->eventsArray.__ptr = NULL;
else // Events found
{
getAttendanceEventsOut->eventsArray.__ptr = soap_malloc (soap,
(getAttendanceEventsOut->eventsArray.__size) *
sizeof (*(getAttendanceEventsOut->eventsArray.__ptr)));
for (NumAttEvent = 0;
NumAttEvent < NumAttEvents;
NumAttEvent++)
{
/* Get next group */
row = mysql_fetch_row (mysql_res);
/* Get attendance event (except Txt) */
Att_GetEventDataFromRow (row,&Event);
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].attendanceEventCode = (int) Event.AttCod;
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].hidden = (Event.HiddenOrVisible == HidVis_HIDDEN) ? 1 :
0;
Gbl.Usrs.Other.UsrDat.UsrCod = Event.UsrCod;
if (API_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Gbl.Hierarchy.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;
}
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].startTime = (int) Event.TimeUTC[Dat_STR_TIME];
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].endTime = (int) Event.TimeUTC[Dat_END_TIME];
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].commentsTeachersVisible = Event.Open ? 1 :
0;
Length = strlen (Event.Title);
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].title =
soap_malloc (soap,Length + 1);
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].title,
Event.Title,Length);
/* Get Txt (row[9]) */
Length = strlen (row[9]);
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].text =
soap_malloc (soap,Length + 1);
Str_Copy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].text,
row[9],Length);
/* Get list of groups for this attendance event */
API_GetListGrpsInAttendanceEventFromDB (soap,
Event.AttCod,
&(getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].groups));
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return SOAP_OK;
}
/*****************************************************************************/
/**************** Get lists of groups of an attendance event *****************/
/*****************************************************************************/
static void API_GetListGrpsInAttendanceEventFromDB (struct soap *soap,
long AttCod,char **ListGroups)
{
MYSQL_RES *mysql_res;
long NumGrps;
long NumGrp;
long GrpCod;
char GrpCodStr[Cns_MAX_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_GetEventDataByCod (&Event);
if (Event.CrsCod != (long) courseCode)
return soap_receiver_fault (soap,
"Request forbidden",
"Attendance event does not belong to course");
ItsANewAttEvent = false;
}
else
{
ItsANewAttEvent = true;
Event.CrsCod = (long) courseCode;
}
/* Is event hidden? */
Event.HiddenOrVisible = (hidden ? HidVis_HIDDEN :
HidVis_VISIBLE);
/* User's code (really not used) */
Event.UsrCod = Gbl.Usrs.Me.UsrDat.UsrCod;
/* startTime and endTime */
Event.TimeUTC[Dat_STR_TIME] = (time_t) startTime;
Event.TimeUTC[Dat_END_TIME] = (time_t) endTime;
/* Are teacher's comments visible? */
Event.CommentTchVisible = (commentsTeachersVisible ? true :
false);
/* Title */
if (!title[0])
return soap_receiver_fault (soap,
"Request forbidden",
"Title of attendance event is empty");
Str_Copy (Event.Title,title,sizeof (Event.Title) - 1);
/* Create a list of groups selected */
API_GetLstGrpsSel (groups);
/***** Create or update attendance event *****/
if (ItsANewAttEvent)
Att_CreateEvent (&Event,text); // Add new attendance event to database
else
Att_UpdateEvent (&Event,text); // Modify existing attendance event
/***** Free memory for list of selected groups *****/
Grp_FreeListCodSelectedGrps ();
sendAttendanceEventOut->attendanceEventCode = Event.AttCod;
return SOAP_OK;
}
/*****************************************************************************/
/************************ Remove an attendance event *************************/
/*****************************************************************************/
int swad__removeAttendanceEvent (struct soap *soap,
char *wsKey,int attendanceEventCode, // input
struct swad__removeAttendanceEventOutput *removeAttendanceEventOut) // output
{
int ReturnCode;
struct Att_Event Event;
/***** Initializations *****/
API_Set_gSOAP_RuntimeEnv (soap);
Gbl.WebService.Function = API_removeAttendanceEvent;
removeAttendanceEventOut->attendanceEventCode = 0;
/***** Check web service key *****/
if ((ReturnCode = API_CheckAPIKey (wsKey)) != SOAP_OK)
return ReturnCode;
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
return soap_receiver_fault (soap,
"Bad web service key",
"Web service key does not exist in database");
/**** Get data of attendance event *****/
/* Event code */
Event.AttCod = (long) attendanceEventCode;
/* Course code */
if (Event.AttCod > 0) // The event already exists
{
Att_GetEventDataByCod (&Event);
Gbl.Hierarchy.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_RemoveEventFromDB (Event.AttCod);
removeAttendanceEventOut->attendanceEventCode = Event.AttCod;
return SOAP_OK;
}
/*****************************************************************************/
/********************** Create a list of groups selected *********************/
/*****************************************************************************/
static void API_GetLstGrpsSel (const char *Groups)
{
const char *Ptr;
char LongStr[Cns_MAX_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_GetEventDataByCod (&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",