mirror of
https://github.com/acanas/swad-core.git
synced 2024-09-22 00:00:40 +02:00
4410 lines
175 KiB
C
4410 lines
175 KiB
C
// swad_web_service.c: SWAD web service 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-2015 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 = swad.o swad_action.o swad_assignment.o swad_file_browser.o swad_chat.o swad_connected.o swad_course.o swad_cryptography.o swad_centre.o swad_date.o swad_database.o swad_degree.o swad_department.o swad_exam.o swad_file.o swad_forum.o swad_group.o swad_holiday.o swad_import.o swad_institution.o swad_layout.o swad_link.o swad_changelog.o swad_message.o swad_notice.o swad_notification.o swad_pagination.o swad_parameter.o swad_place.o swad_plugin.o swad_preference.o swad_record.o swad_session.o swad_statistic.o swad_string.o swad_syllabus.o swad_theme.o swad_test.o swad_timetable.o swad_text.o swad_user.o swad_web_service.o sha2.o
|
|
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 <linux/stddef.h> // For NULL
|
|
#include <locale.h> // For setlocale, LC_NUMERIC...
|
|
#include <sys/stat.h> // For lstat
|
|
#include <string.h>
|
|
#include <stdsoap2.h>
|
|
|
|
#include "soap/soapH.h" // gSOAP header
|
|
#include "soap/swad.nsmap" // Namespaces map used
|
|
|
|
#include "swad_account.h"
|
|
#include "swad_database.h"
|
|
#include "swad_file_browser.h"
|
|
#include "swad_global.h"
|
|
#include "swad_ID.h"
|
|
#include "swad_notice.h"
|
|
#include "swad_notification.h"
|
|
#include "swad_password.h"
|
|
#include "swad_user.h"
|
|
#include "swad_web_service.h"
|
|
|
|
/*****************************************************************************/
|
|
/************** External global variables from others modules ****************/
|
|
/*****************************************************************************/
|
|
|
|
extern struct Globals Gbl;
|
|
extern const char Str_BIN_TO_BASE64URL[64];
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private constants *****************************/
|
|
/*****************************************************************************/
|
|
|
|
// Add new functions at the end
|
|
static const char *Svc_Functions[1+Svc_NUM_FUNCTIONS] =
|
|
{
|
|
"?", // 0 ==> unknown function
|
|
"loginBySession", // 1
|
|
"loginByUserPassword", // 2 (deprecated)
|
|
"loginByUserPasswordKey", // 3
|
|
"getCourses", // 4
|
|
"getUsers", // 5
|
|
"getNotifications", // 6
|
|
"getTestConfig", // 7
|
|
"getTests", // 8
|
|
"sendMessage", // 9
|
|
"sendNotice", // 10
|
|
"getDirectoryTree", // 11
|
|
"getGroups", // 12
|
|
"getGroupTypes", // 13
|
|
"sendMyGroups", // 14
|
|
"getFile", // 15
|
|
"markNotificationsAsRead", // 16
|
|
"getNewPassword", // 17
|
|
"getCourseInfo", // 18
|
|
"getAttendanceEvents", // 19
|
|
"sendAttendanceEvent", // 20
|
|
"getAttendanceUsers", // 21
|
|
"sendAttendanceUsers", // 22
|
|
"createAccount", // 23
|
|
"getMarks", // 24
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/********************************* Data types ********************************/
|
|
/*****************************************************************************/
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private prototypes ****************************/
|
|
/*****************************************************************************/
|
|
|
|
// static int Svc_CheckIfIPIsAllowed (void);
|
|
static int Svc_GetPlgCodFromAppKey (const char *appKey);
|
|
static int Svc_CheckIdSession (const char *IdSession);
|
|
static int Svc_CheckWSKey (char *WSKey);
|
|
|
|
static int Svc_CheckCourseAndGroupCodes (long CrsCod,long GrpCod);
|
|
static int Svc_GenerateNewWSKey (long UsrCod,char *WSKey);
|
|
static int Svc_RemoveOldWSKeys (void);
|
|
static int Svc_GetCurrentDegCodFromCurrentCrsCod (void);
|
|
static int Svc_GetSomeUsrDataFromUsrCod (struct UsrData *UsrDat,long CrsCod);
|
|
static int Svc_GetRoleFromInternalRole (Rol_Role_t Role);
|
|
|
|
static int Svc_CheckParamsNewAccount (char *NewNicknameWithArroba, // Input
|
|
char *NewNicknameWithoutArroba, // Output
|
|
char *NewEmail, // Input-output
|
|
char *NewPlainPassword, // Input
|
|
char *NewEncryptedPassword); // Output
|
|
|
|
static void Svc_CopyUsrData (struct swad__user *Usr,struct UsrData *UsrDat,bool UsrIDIsVisible);
|
|
|
|
static void Svc_GetListGrpsInAttendanceEvent (long AttCod,char **ListGroups);
|
|
|
|
static int Svc_GetMyLanguage (void);
|
|
|
|
static int Svc_sendMessageToUsr (long OriginalMsgCod,long SenderUsrCod,long ReplyUsrCod,long RecipientUsrCod,bool NotifyByEmail,const char *Subject,const char *Content);
|
|
|
|
static int Svc_GetTstConfig (long CrsCod);
|
|
static int Svc_GetNumTestQuestionsInCrs (long CrsCod);
|
|
static int Svc_GetTstTags (long CrsCod,struct swad__getTestsOutput *getTestsOut);
|
|
static int Svc_GetTstQuestions (long CrsCod,long BeginTime,struct swad__getTestsOutput *getTestsOut);
|
|
static int Svc_GetTstAnswers (long CrsCod,long BeginTime,struct swad__getTestsOutput *getTestsOut);
|
|
static int Svc_GetTstQuestionTags (long CrsCod,long BeginTime,struct swad__getTestsOutput *getTestsOut);
|
|
|
|
static void Svc_ListDir (unsigned Level,const char *Path,const char *PathInTree);
|
|
static bool Svc_WriteRowFileBrowser (unsigned Level,Brw_FileType_t FileType,const char *FileName);
|
|
static void Svc_IndentXMLLine (unsigned Level);
|
|
|
|
/*****************************************************************************/
|
|
/******* Function called when a web service if required by a plugin **********/
|
|
/*****************************************************************************/
|
|
|
|
void Svc_WebService (void)
|
|
{
|
|
struct soap *soap;
|
|
|
|
if ((soap = soap_new ())) // Allocate and initialize runtime context
|
|
{
|
|
soap_serve (soap);
|
|
|
|
soap_end (soap); // Clean up and remove deserialized data
|
|
soap_free (soap); // Detach and free runtime context
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******* Function called to exit on error when executing web service *********/
|
|
/*****************************************************************************/
|
|
|
|
void Svc_Exit (const char *DetailErrorMessage)
|
|
{
|
|
int ReturnCode = (DetailErrorMessage ? soap_receiver_fault (Gbl.soap,
|
|
"Error in swad web service",
|
|
DetailErrorMessage) :
|
|
0);
|
|
|
|
soap_end (Gbl.soap); // Clean up and remove deserialized data
|
|
soap_free (Gbl.soap); // Detach and free runtime context
|
|
|
|
exit (ReturnCode);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********** Check if the IP of the requester of a web service ***************/
|
|
/*********** is one of the IP allowed in the plugins ***************/
|
|
/*****************************************************************************/
|
|
/*
|
|
static int Svc_CheckIfIPIsAllowed (void)
|
|
{
|
|
char IP[Cns_MAX_LENGTH_IP+1];
|
|
char Query[256+Cns_MAX_LENGTH_IP];
|
|
|
|
***** Get IP *****
|
|
if (getenv ("REMOTE_ADDR"))
|
|
{
|
|
strncpy (IP,getenv ("REMOTE_ADDR"),Cns_MAX_LENGTH_IP);
|
|
IP[Cns_MAX_LENGTH_IP] = '\0';
|
|
}
|
|
else
|
|
IP[0] = '\0';
|
|
|
|
***** Get number of plugins with a IP address *****
|
|
sprintf (Query,"SELECT COUNT(*) FROM plugins WHERE IP='%s'",IP);
|
|
if (!DB_QueryCOUNT (Query,"can not check IP"))
|
|
{
|
|
sprintf (Gbl.Message,"Sender's IP (%s) is forbidden",IP);
|
|
return soap_sender_fault (Gbl.soap,
|
|
Gbl.Message,
|
|
"The IP of the requester of a web service is not allowed");
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|
|
*/
|
|
/*****************************************************************************/
|
|
/****** Check if the application key of the requester of a web service *******/
|
|
/****** is one of the application keys allowed in the plugins *******/
|
|
/*****************************************************************************/
|
|
|
|
static int Svc_GetPlgCodFromAppKey (const char *appKey)
|
|
{
|
|
char Query[256+Plg_MAX_LENGTH_PLUGIN_APP_KEY];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
|
|
Gbl.WebService.PlgCod = -1L;
|
|
|
|
/***** Get number of plugins with a IP address *****/
|
|
sprintf (Query,"SELECT PlgCod FROM plugins WHERE AppKey='%s'",appKey);
|
|
if (DB_QuerySELECT (Query,&mysql_res,"can not check application key")) // Session found in table of sessions
|
|
{
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
Gbl.WebService.PlgCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
if (Gbl.WebService.PlgCod < 0)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Unknown application key",
|
|
"Unknown application");
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****** Get the name of a web service function given the function code *******/
|
|
/*****************************************************************************/
|
|
|
|
const char *Svc_GetFunctionNameFromFunCod (long FunCod)
|
|
{
|
|
if (FunCod < 0 || FunCod > Svc_NUM_FUNCTIONS)
|
|
return Svc_Functions[0];
|
|
return Svc_Functions[FunCod];
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****** Check if a session identifier is valid and exists in database ********/
|
|
/*****************************************************************************/
|
|
|
|
static int Svc_CheckIdSession (const char *IdSession)
|
|
{
|
|
const char *Ptr;
|
|
unsigned i;
|
|
char Query[512];
|
|
|
|
/***** Check if pointer is NULL *****/
|
|
if (IdSession == NULL)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad session identifier",
|
|
"Session identifier is a null pointer");
|
|
|
|
/***** Check length of session identifier *****/
|
|
if (strlen (IdSession) != Ses_LENGTH_SESSION_ID)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad session identifier",
|
|
"The length of the session identifier is wrong");
|
|
|
|
/***** Check if session identifier is in base64url *****/
|
|
for (Ptr = IdSession;
|
|
*Ptr;
|
|
Ptr++)
|
|
{
|
|
for (i = 0;
|
|
i < 64;
|
|
i++) // Check if this character is one of the allowed characters
|
|
if (*Ptr == Str_BIN_TO_BASE64URL[i])
|
|
break;
|
|
if (i == 64) // Character not found
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad session identifier",
|
|
"The session identifier must contain only base64url characters");
|
|
}
|
|
|
|
/***** Query if session identifier already exists in database *****/
|
|
sprintf (Query,"SELECT COUNT(*) FROM sessions WHERE SessionId='%s'",
|
|
IdSession);
|
|
if (DB_QueryCOUNT (Query,"can not get session data") != 1)
|
|
return soap_receiver_fault (Gbl.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 Svc_CheckWSKey (char *WSKey)
|
|
{
|
|
char Query[512];
|
|
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 *****/
|
|
sprintf (Query,"SELECT UsrCod,PlgCod FROM ws_keys WHERE WSKey='%s'",
|
|
WSKey);
|
|
if (DB_QuerySELECT (Query,&mysql_res,"can not get existence of key")) // Session found in table of sessions
|
|
{
|
|
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 Svc_CheckCourseAndGroupCodes (long CrsCod,long GrpCod)
|
|
{
|
|
char Query[512];
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (CrsCod <= 0)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** Query if course code already exists in database *****/
|
|
sprintf (Query,"SELECT COUNT(*) FROM courses WHERE CrsCod='%ld'",
|
|
CrsCod);
|
|
if (DB_QueryCOUNT (Query,"can not get course") != 1)
|
|
return soap_sender_fault (Gbl.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"
|
|
{
|
|
/***** Query if group code already exists in database *****/
|
|
sprintf (Query,"SELECT COUNT(*) FROM crs_grp_types,crs_grp"
|
|
" WHERE crs_grp_types.CrsCod='%ld' AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod AND crs_grp.GrpCod='%ld'",
|
|
CrsCod,GrpCod);
|
|
if (DB_QueryCOUNT (Query,"can not get group") != 1)
|
|
return soap_sender_fault (Gbl.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 Svc_GenerateNewWSKey (long UsrCod,char *WSKey)
|
|
{
|
|
int ReturnCode;
|
|
char Query[512];
|
|
|
|
/***** Remove expired web service keys *****/
|
|
if ((ReturnCode = Svc_RemoveOldWSKeys ()) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Create a unique name for the key *****/
|
|
strcpy (WSKey,Gbl.UniqueNameEncrypted);
|
|
|
|
/***** Check that key does not exist in database *****/
|
|
sprintf (Query,"SELECT COUNT(*) FROM ws_keys WHERE WSKey='%s'",
|
|
WSKey);
|
|
if (DB_QueryCOUNT (Query,"can not get existence of key"))
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Error when generating key",
|
|
"Generated key already existed in database");
|
|
|
|
/***** Insert key into database *****/
|
|
sprintf (Query,"INSERT INTO ws_keys (WSKey,UsrCod,PlgCod,LastTime)"
|
|
" VALUES ('%s','%ld','%ld',NOW())",
|
|
WSKey,UsrCod,Gbl.WebService.PlgCod);
|
|
DB_QueryINSERT (Query,"can not insert new key");
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************ Remove old web service keys ************************/
|
|
/*****************************************************************************/
|
|
|
|
static int Svc_RemoveOldWSKeys (void)
|
|
{
|
|
char Query[512];
|
|
|
|
/***** Remove expired sessions *****/
|
|
/* A session expire when last click (LastTime) is too old,
|
|
or when there was at least one refresh (navigator supports AJAX) and last refresh is too old (browser probably was closed) */
|
|
sprintf (Query,"DELETE LOW_PRIORITY FROM ws_keys WHERE"
|
|
" LastTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-'%lu')",
|
|
Cfg_TIME_TO_DELETE_WEB_SERVICE_KEY);
|
|
if (mysql_query (&Gbl.mysql,Query))
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Can not remove old web service keys from database",
|
|
mysql_error (&Gbl.mysql));
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************* Get degree code from course code **********************/
|
|
/*****************************************************************************/
|
|
|
|
static int Svc_GetCurrentDegCodFromCurrentCrsCod (void)
|
|
{
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
|
|
/***** Set default degree code *****/
|
|
Gbl.CurrentDeg.Deg.DegCod = -1L;
|
|
|
|
/***** Check that key does not exist in database *****/
|
|
sprintf (Query,"SELECT DegCod FROM courses WHERE CrsCod='%ld'",
|
|
Gbl.CurrentCrs.Crs.CrsCod);
|
|
if (DB_QuerySELECT (Query,&mysql_res,"can not get the degree of a course")) // Course found in table of courses
|
|
{
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
Gbl.CurrentDeg.Deg.DegCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************ Get user's data from database giving a user's code *************/
|
|
/*****************************************************************************/
|
|
// UsrDat->UsrCod must contain an existing user's code
|
|
|
|
static int Svc_GetSomeUsrDataFromUsrCod (struct UsrData *UsrDat,long CrsCod)
|
|
{
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
|
|
/***** Get some user's data *****/
|
|
/* Query database */
|
|
sprintf (Query,"SELECT Surname1,Surname2,FirstName,Photo,DATE_FORMAT(Birthday,'%%Y%%m%%d')"
|
|
" FROM usr_data WHERE UsrCod='%ld'",
|
|
UsrDat->UsrCod);
|
|
|
|
/* Check number of rows in result */
|
|
if (DB_QuerySELECT (Query,&mysql_res,"can not get user's data") != 1)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Can not get user's data from database",
|
|
"User does not exist in database");
|
|
|
|
/* Read some user's data */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get user's name */
|
|
strncpy (UsrDat->Surname1 ,row[0],sizeof (UsrDat->Surname1 )-1);
|
|
strncpy (UsrDat->Surname2 ,row[1],sizeof (UsrDat->Surname2 )-1);
|
|
strncpy (UsrDat->FirstName,row[2],sizeof (UsrDat->FirstName)-1);
|
|
|
|
UsrDat->Surname1 [sizeof (UsrDat->Surname1 )-1] = '\0';
|
|
UsrDat->Surname2 [sizeof (UsrDat->Surname2 )-1] = '\0';
|
|
UsrDat->FirstName[sizeof (UsrDat->FirstName)-1] = '\0';
|
|
|
|
/* Get user's photo */
|
|
strncpy (UsrDat->Photo,row[3],sizeof (UsrDat->Photo)-1);
|
|
UsrDat->Photo[sizeof (UsrDat->Photo)-1] = '\0';
|
|
|
|
/* Get user's brithday */
|
|
strncpy (UsrDat->Birthday.YYYYMMDD,row[4],4+2+2);
|
|
UsrDat->Birthday.YYYYMMDD[4+2+2] = '\0';
|
|
|
|
/* Free structure that stores the query result */
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
/***** Get list of user's IDs *****/
|
|
ID_GetListIDsFromUsrCod (UsrDat);
|
|
|
|
/***** Get user's nickname *****/
|
|
Nck_GetNicknameFromUsrCod (UsrDat->UsrCod,UsrDat->Nickname);
|
|
|
|
/***** Get user's role *****/
|
|
/* Query database */
|
|
if (CrsCod > 0)
|
|
sprintf (Query,"SELECT Role FROM crs_usr"
|
|
" WHERE CrsCod='%ld' AND UsrCod='%ld'",
|
|
CrsCod,UsrDat->UsrCod);
|
|
else
|
|
sprintf (Query,"SELECT MAX(Role)"
|
|
" FROM crs_usr WHERE UsrCod='%ld'",
|
|
UsrDat->UsrCod);
|
|
if (DB_QuerySELECT (Query,&mysql_res,"can not get user's role") == 1)
|
|
{
|
|
/* Read the maximum role */
|
|
row = mysql_fetch_row (mysql_res);
|
|
if (sscanf (row[0],"%u",&UsrDat->RoleInCurrentCrsDB) != 1)
|
|
UsrDat->RoleInCurrentCrsDB = Rol_UNKNOWN;
|
|
}
|
|
else
|
|
UsrDat->RoleInCurrentCrsDB = Rol__GUEST_;
|
|
|
|
/* Free structure that stores the query result */
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****** Get the role returned via web service from internal role code ********/
|
|
/*****************************************************************************/
|
|
|
|
static int Svc_GetRoleFromInternalRole (Rol_Role_t Role)
|
|
{
|
|
switch (Role)
|
|
{
|
|
case Rol__GUEST_:
|
|
case Rol_VISITOR:
|
|
return 1; // guest or visitor
|
|
case Rol_STUDENT:
|
|
return 2; // student
|
|
case Rol_TEACHER:
|
|
return 3; // teacher
|
|
default:
|
|
return 0; // unknown
|
|
}
|
|
return 0; // unknown
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**************************** Get info of my marks ***************************/
|
|
/*****************************************************************************/
|
|
|
|
#define Svc_CHECK_NEW_ACCOUNT_OK 0
|
|
#define Svc_CHECK_NEW_ACCOUNT_NICKNAME_NOT_VALID -1
|
|
#define Svc_CHECK_NEW_ACCOUNT_NICKNAME_REGISTERED_BY_ANOTHER_USER -2
|
|
#define Svc_CHECK_NEW_ACCOUNT_EMAIL_NOT_VALID -3
|
|
#define Svc_CHECK_NEW_ACCOUNT_EMAIL_REGISTERED_BY_ANOTHER_USER -4
|
|
#define Svc_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 NewNicknameWithoutArroba[Nck_MAX_BYTES_NICKNAME_WITH_ARROBA+1];
|
|
char NewEncryptedPassword[Cry_LENGTH_ENCRYPTED_STR_SHA512_BASE64+1];
|
|
int Result;
|
|
int ReturnCode;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_createAccount;
|
|
|
|
/***** Allocate space for strings *****/
|
|
createAccountOut->wsKey = (char *) soap_malloc (Gbl.soap,256);
|
|
|
|
/***** Default values returned on error *****/
|
|
createAccountOut->userCode = 0; // Undefined error
|
|
createAccountOut->wsKey[0] = '\0';
|
|
|
|
/***** Get plugin code *****/
|
|
if ((ReturnCode = Svc_GetPlgCodFromAppKey ((const char *) appKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Check parameters used to create the new account *****/
|
|
Result = Svc_CheckParamsNewAccount (userNickname, // Input
|
|
NewNicknameWithoutArroba,// 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 *****/
|
|
strcpy (Gbl.Usrs.Me.UsrDat.Password,NewEncryptedPassword);
|
|
|
|
/***** User does not exist in the platform, so create him/her! *****/
|
|
Acc_CreateNewUsr (&Gbl.Usrs.Me.UsrDat);
|
|
|
|
/***** Save nickname *****/
|
|
Nck_UpdateMyNick (NewNicknameWithoutArroba);
|
|
strcpy (Gbl.Usrs.Me.UsrDat.Nickname,NewNicknameWithoutArroba);
|
|
|
|
/***** Save e-mail *****/
|
|
if (Mai_UpdateEmailInDB (&Gbl.Usrs.Me.UsrDat,userEmail))
|
|
{
|
|
/* E-mail updated sucessfully */
|
|
strcpy (Gbl.Usrs.Me.UsrDat.Email,userEmail);
|
|
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 Svc_GenerateNewWSKey ((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 Svc_CheckParamsNewAccount (char *NewNicknameWithArroba, // Input
|
|
char *NewNicknameWithoutArroba, // Output
|
|
char *NewEmail, // Input-output
|
|
char *NewPlainPassword, // Input
|
|
char *NewEncryptedPassword) // Output
|
|
{
|
|
char Query[1024];
|
|
|
|
/***** Step 1/3: Check new nickname *****/
|
|
/* Make a copy without possible starting arrobas */
|
|
strncpy (NewNicknameWithoutArroba,NewNicknameWithArroba,Nck_MAX_BYTES_NICKNAME_WITH_ARROBA);
|
|
NewNicknameWithoutArroba[Nck_MAX_BYTES_NICKNAME_WITH_ARROBA] = '\0';
|
|
if (Nck_CheckIfNickWithArrobaIsValid (NewNicknameWithArroba)) // If new nickname is valid
|
|
{
|
|
/***** Remove arrobas at the beginning *****/
|
|
Str_RemoveLeadingArrobas (NewNicknameWithoutArroba);
|
|
|
|
/***** Check if the new nickname matches any of the nicknames of other users *****/
|
|
sprintf (Query,"SELECT COUNT(*) FROM usr_nicknames WHERE Nickname='%s'",
|
|
NewNicknameWithoutArroba);
|
|
if (DB_QueryCOUNT (Query,"can not check if nickname already existed")) // A nickname of another user is the same that this nickname
|
|
return Svc_CHECK_NEW_ACCOUNT_NICKNAME_REGISTERED_BY_ANOTHER_USER;
|
|
}
|
|
else // New nickname is not valid
|
|
return Svc_CHECK_NEW_ACCOUNT_NICKNAME_NOT_VALID;
|
|
|
|
/***** Step 2/3: Check new e-mail *****/
|
|
if (Mai_CheckIfEmailIsValid (NewEmail)) // New e-mail is valid
|
|
{
|
|
/***** Check if the new e-mail matches any of the confirmed e-mails of other users *****/
|
|
sprintf (Query,"SELECT COUNT(*) FROM usr_emails"
|
|
" WHERE E_mail='%s' AND Confirmed='Y'",
|
|
NewEmail);
|
|
if (DB_QueryCOUNT (Query,"can not check if e-mail already existed")) // An e-mail of another user is the same that my e-mail
|
|
return Svc_CHECK_NEW_ACCOUNT_EMAIL_REGISTERED_BY_ANOTHER_USER;
|
|
}
|
|
else // New e-mail is not valid
|
|
return Svc_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 Svc_CHECK_NEW_ACCOUNT_PASSWORD_NOT_VALID;
|
|
|
|
return Svc_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[512];
|
|
int ReturnCode;
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRows;
|
|
char PhotoURL[PATH_MAX+1];
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_loginByUserPasswordKey;
|
|
|
|
/***** Allocate space for strings *****/
|
|
loginByUserPasswordKeyOut->wsKey = (char *) soap_malloc (Gbl.soap,256);
|
|
loginByUserPasswordKeyOut->userNickname = (char *) soap_malloc (Gbl.soap,Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA+1);
|
|
loginByUserPasswordKeyOut->userID = (char *) soap_malloc (Gbl.soap,256);
|
|
loginByUserPasswordKeyOut->userFirstname = (char *) soap_malloc (Gbl.soap,256);
|
|
loginByUserPasswordKeyOut->userSurname1 = (char *) soap_malloc (Gbl.soap,256);
|
|
loginByUserPasswordKeyOut->userSurname2 = (char *) soap_malloc (Gbl.soap,256);
|
|
loginByUserPasswordKeyOut->userPhoto = (char *) soap_malloc (Gbl.soap,PATH_MAX+1);
|
|
loginByUserPasswordKeyOut->userBirthday = (char *) soap_malloc (Gbl.soap,8+2+2+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 = Svc_GetPlgCodFromAppKey ((const char *) appKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Check if user's e-mail, @nickname or ID are valid *****/
|
|
strncpy (UsrIDNickOrEmail,userID,255);
|
|
UsrIDNickOrEmail[255] = '\0';
|
|
if (Nck_CheckIfNickWithArrobaIsValid (UsrIDNickOrEmail)) // 1: It's a nickname
|
|
{
|
|
Str_RemoveLeadingArrobas (UsrIDNickOrEmail);
|
|
|
|
/* User has typed a nickname */
|
|
sprintf (Query,"SELECT usr_nicknames.UsrCod"
|
|
" FROM usr_nicknames,usr_data"
|
|
" WHERE usr_nicknames.Nickname='%s'"
|
|
" AND usr_nicknames.UsrCod=usr_data.UsrCod"
|
|
" AND usr_data.Password='%s'",
|
|
UsrIDNickOrEmail,userPassword);
|
|
}
|
|
else if (Mai_CheckIfEmailIsValid (Gbl.Usrs.Me.UsrIdLogin)) // 2: It's an e-mail
|
|
{
|
|
/* User has typed an e-mail */
|
|
// TODO: Get only if email confirmed?
|
|
sprintf (Query,"SELECT usr_emails.UsrCod"
|
|
" FROM usr_emails,usr_data"
|
|
" WHERE usr_emails.E_mail='%s'"
|
|
" AND usr_emails.UsrCod=usr_data.UsrCod"
|
|
" AND usr_data.Password='%s'",
|
|
UsrIDNickOrEmail,userPassword);
|
|
}
|
|
else // 3: It's not a nickname nor e-mail
|
|
{
|
|
// Users' IDs are always stored internally in capitals and without leading zeros
|
|
Str_RemoveLeadingZeros (UsrIDNickOrEmail);
|
|
Str_ConvertToUpperText (UsrIDNickOrEmail);
|
|
if (ID_CheckIfUsrIDIsValid (UsrIDNickOrEmail))
|
|
{
|
|
/* User has typed a valid user's ID (existing or not) */
|
|
// TODO: Get only if ID confirmed?
|
|
sprintf (Query,"SELECT usr_IDs.UsrCod FROM usr_IDs,usr_data"
|
|
" WHERE usr_IDs.UsrID='%s'"
|
|
" AND usr_IDs.UsrCod=usr_data.UsrCod"
|
|
" AND usr_data.Password='%s'",
|
|
UsrIDNickOrEmail,userPassword);
|
|
}
|
|
else // String is not a valid user's nickname, e-mail or ID
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad log in",
|
|
"User's ID or nickname don't exist or password is wrong");
|
|
}
|
|
|
|
/***** Get user's data from database *****/
|
|
if ((NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get user's data"))) // User found in table of users' data
|
|
{
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/***** Get user code (row[0]) *****/
|
|
Gbl.Usrs.Me.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
if (Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L) == SOAP_OK) // Get some user's data from database
|
|
{
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
loginByUserPasswordKeyOut->userCode = (int) Gbl.Usrs.Me.UsrDat.UsrCod;
|
|
|
|
strncpy (loginByUserPasswordKeyOut->userNickname,Gbl.Usrs.Me.UsrDat.Nickname,Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA);
|
|
loginByUserPasswordKeyOut->userNickname[Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA] = '\0';
|
|
|
|
strncpy (loginByUserPasswordKeyOut->userID,Gbl.Usrs.Me.UsrDat.IDs.List[0].ID,255); // TODO: What user's ID?
|
|
loginByUserPasswordKeyOut->userID[255] = '\0';
|
|
|
|
strncpy (loginByUserPasswordKeyOut->userSurname1,Gbl.Usrs.Me.UsrDat.Surname1,255);
|
|
loginByUserPasswordKeyOut->userSurname1[255] = '\0';
|
|
strncpy (loginByUserPasswordKeyOut->userSurname2,Gbl.Usrs.Me.UsrDat.Surname2,255);
|
|
loginByUserPasswordKeyOut->userSurname2[255] = '\0';
|
|
strncpy (loginByUserPasswordKeyOut->userFirstname,Gbl.Usrs.Me.UsrDat.FirstName,255);
|
|
loginByUserPasswordKeyOut->userFirstname[255] = '\0';
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,PhotoURL,false);
|
|
strncpy (loginByUserPasswordKeyOut->userPhoto,PhotoURL,PATH_MAX);
|
|
loginByUserPasswordKeyOut->userPhoto[PATH_MAX] = '\0';
|
|
|
|
strncpy (loginByUserPasswordKeyOut->userBirthday,Gbl.Usrs.Me.UsrDat.Birthday.YYYYMMDD,4+2+2);
|
|
loginByUserPasswordKeyOut->userBirthday[4+2+2] = '\0';
|
|
|
|
loginByUserPasswordKeyOut->userRole = Svc_GetRoleFromInternalRole (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB);
|
|
}
|
|
else
|
|
{
|
|
loginByUserPasswordKeyOut->userCode = -1;
|
|
loginByUserPasswordKeyOut->userID = NULL;
|
|
loginByUserPasswordKeyOut->userSurname1 = NULL;
|
|
loginByUserPasswordKeyOut->userSurname2 = NULL;
|
|
loginByUserPasswordKeyOut->userFirstname = NULL;
|
|
loginByUserPasswordKeyOut->userPhoto = NULL;
|
|
loginByUserPasswordKeyOut->userRole = 0;
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
if (NumRows == 1)
|
|
/***** Generate a key used in subsequents calls to other web services *****/
|
|
return Svc_GenerateNewWSKey ((long) loginByUserPasswordKeyOut->userCode,
|
|
loginByUserPasswordKeyOut->wsKey);
|
|
else
|
|
return soap_receiver_fault (Gbl.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;
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRows;
|
|
char PhotoURL[PATH_MAX+1];
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_loginBySessionKey;
|
|
|
|
/***** Allocate space for strings *****/
|
|
loginBySessionKeyOut->wsKey = (char *) soap_malloc (Gbl.soap,256);
|
|
loginBySessionKeyOut->userNickname = (char *) soap_malloc (Gbl.soap,Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA+1);
|
|
loginBySessionKeyOut->userID = (char *) soap_malloc (Gbl.soap,256);
|
|
loginBySessionKeyOut->userFirstname = (char *) soap_malloc (Gbl.soap,256);
|
|
loginBySessionKeyOut->userSurname1 = (char *) soap_malloc (Gbl.soap,256);
|
|
loginBySessionKeyOut->userSurname2 = (char *) soap_malloc (Gbl.soap,256);
|
|
loginBySessionKeyOut->userPhoto = (char *) soap_malloc (Gbl.soap,PATH_MAX+1);
|
|
loginBySessionKeyOut->userBirthday = (char *) soap_malloc (Gbl.soap,8+2+2+1);
|
|
loginBySessionKeyOut->degreeName = (char *) soap_malloc (Gbl.soap,256);
|
|
loginBySessionKeyOut->courseName = (char *) soap_malloc (Gbl.soap,256);
|
|
|
|
/***** 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 = 0; // unknown
|
|
loginBySessionKeyOut->degreeName[0] = '\0';
|
|
loginBySessionKeyOut->courseName[0] = '\0';
|
|
|
|
/***** Get plugin code *****/
|
|
if ((ReturnCode = Svc_GetPlgCodFromAppKey ((const char *) appKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Check IP of the sender *****/
|
|
// if ((ReturnCode = Svc_CheckIfIPIsAllowed ()) != SOAP_OK)
|
|
// return ReturnCode;
|
|
|
|
/***** Check length of session identifier *****/
|
|
if (sessionID == NULL)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"SessionID is null",
|
|
"Login by session");
|
|
|
|
/***** Check session identifier coming from an external plugin *****/
|
|
if ((ReturnCode = Svc_CheckIdSession (sessionID)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
// Now, we know that sessionID is a valid session identifier
|
|
/***** Query data of the session from database *****/
|
|
sprintf (Query,"SELECT UsrCod,DegCod,CrsCod FROM sessions"
|
|
" WHERE SessionId='%s'",sessionID);
|
|
if ((NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get session data"))) // Session found in table of sessions
|
|
{
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/***** Get course (row[2]) *****/
|
|
Gbl.CurrentCrs.Crs.CrsCod = Str_ConvertStrCodToLongCod (row[2]);
|
|
Crs_GetDataOfCourseByCod (&Gbl.CurrentCrs.Crs);
|
|
loginBySessionKeyOut->courseCode = (int) Gbl.CurrentCrs.Crs.CrsCod;
|
|
strncpy (loginBySessionKeyOut->courseName,Gbl.CurrentCrs.Crs.FullName,255);
|
|
loginBySessionKeyOut->courseName[255] = '\0';
|
|
|
|
/***** Get user code (row[0]) *****/
|
|
Gbl.Usrs.Me.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
if (Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod) == SOAP_OK) // Get some user's data from database
|
|
{
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
loginBySessionKeyOut->userCode = (int) Gbl.Usrs.Me.UsrDat.UsrCod;
|
|
|
|
strncpy (loginBySessionKeyOut->userNickname,Gbl.Usrs.Me.UsrDat.Nickname,Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA);
|
|
loginBySessionKeyOut->userNickname[Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA] = '\0';
|
|
|
|
strncpy (loginBySessionKeyOut->userID,Gbl.Usrs.Me.UsrDat.IDs.List[0].ID,255); // TODO: What user's ID?
|
|
loginBySessionKeyOut->userID[255] = '\0';
|
|
|
|
strncpy (loginBySessionKeyOut->userSurname1,Gbl.Usrs.Me.UsrDat.Surname1,255);
|
|
loginBySessionKeyOut->userSurname1[255] = '\0';
|
|
strncpy (loginBySessionKeyOut->userSurname2,Gbl.Usrs.Me.UsrDat.Surname2,255);
|
|
loginBySessionKeyOut->userSurname2[255] = '\0';
|
|
strncpy (loginBySessionKeyOut->userFirstname,Gbl.Usrs.Me.UsrDat.FirstName,255);
|
|
loginBySessionKeyOut->userFirstname[255] = '\0';
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,PhotoURL,false);
|
|
strncpy (loginBySessionKeyOut->userPhoto,PhotoURL,PATH_MAX);
|
|
loginBySessionKeyOut->userPhoto[PATH_MAX] = '\0';
|
|
|
|
strncpy (loginBySessionKeyOut->userBirthday,Gbl.Usrs.Me.UsrDat.Birthday.YYYYMMDD,4+2+2);
|
|
loginBySessionKeyOut->userBirthday[4+2+2] = '\0';
|
|
|
|
loginBySessionKeyOut->userRole = Svc_GetRoleFromInternalRole (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB);
|
|
}
|
|
else
|
|
{
|
|
loginBySessionKeyOut->userCode = -1;
|
|
loginBySessionKeyOut->userID = NULL;
|
|
loginBySessionKeyOut->userSurname1 = NULL;
|
|
loginBySessionKeyOut->userSurname2 = NULL;
|
|
loginBySessionKeyOut->userFirstname = NULL;
|
|
loginBySessionKeyOut->userPhoto = NULL;
|
|
loginBySessionKeyOut->userRole = 0;
|
|
}
|
|
|
|
/***** Get degree (row[1]) *****/
|
|
Gbl.CurrentDeg.Deg.DegCod = Str_ConvertStrCodToLongCod (row[1]);
|
|
Deg_GetDataOfDegreeByCod (&Gbl.CurrentDeg.Deg);
|
|
loginBySessionKeyOut->degreeCode = (int) Gbl.CurrentDeg.Deg.DegCod;
|
|
strncpy (loginBySessionKeyOut->degreeName,Gbl.CurrentDeg.Deg.FullName,255);
|
|
loginBySessionKeyOut->degreeName[255] = '\0';
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
/***** Get degree of current course *****/
|
|
if ((ReturnCode = Svc_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
if (NumRows == 1)
|
|
/***** Generate a key used in subsequents calls to other web services *****/
|
|
return Svc_GenerateNewWSKey ((long) loginBySessionKeyOut->userCode,
|
|
loginBySessionKeyOut->wsKey);
|
|
else
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad session identifier",
|
|
"Session identifier does not exist in database");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********************** Send a new password by e-mail ***********************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getNewPassword (struct soap *soap,
|
|
char *userID,char *appKey, // input
|
|
struct swad__getNewPasswordOutput *getNewPasswordOut) // output
|
|
{
|
|
int ReturnCode;
|
|
char UsrIDNickOrEmail[512];
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRows;
|
|
char NewRandomPlainPassword[Pwd_MAX_LENGTH_PLAIN_PASSWORD+1];
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getNewPassword;
|
|
|
|
/***** Default values returned on error *****/
|
|
getNewPasswordOut->success = 0; // error
|
|
|
|
/***** Get plugin code *****/
|
|
if ((ReturnCode = Svc_GetPlgCodFromAppKey ((const char *) appKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Check if user's e-mail, @nickname or ID are valid *****/
|
|
strncpy (UsrIDNickOrEmail,userID,255);
|
|
UsrIDNickOrEmail[255] = '\0';
|
|
if (Nck_CheckIfNickWithArrobaIsValid (UsrIDNickOrEmail)) // 1: It's a nickname
|
|
{
|
|
Str_RemoveLeadingArrobas (UsrIDNickOrEmail);
|
|
|
|
/* User has typed a nickname */
|
|
sprintf (Query,"SELECT UsrCod"
|
|
" FROM usr_nicknames"
|
|
" WHERE Nickname='%s'",
|
|
UsrIDNickOrEmail);
|
|
}
|
|
else if (Mai_CheckIfEmailIsValid (Gbl.Usrs.Me.UsrIdLogin)) // 2: It's an e-mail
|
|
{
|
|
/* User has typed an e-mail */
|
|
// TODO: Get only if email confirmed?
|
|
sprintf (Query,"SELECT UsrCod"
|
|
" FROM usr_emails"
|
|
" WHERE E_mail='%s'",
|
|
UsrIDNickOrEmail);
|
|
}
|
|
else // 3: It's not a nickname nor e-mail
|
|
{
|
|
// Users' IDs are always stored internally in capitals and without leading zeros
|
|
Str_RemoveLeadingZeros (UsrIDNickOrEmail);
|
|
Str_ConvertToUpperText (UsrIDNickOrEmail);
|
|
if (ID_CheckIfUsrIDIsValid (UsrIDNickOrEmail))
|
|
{
|
|
/* User has typed a valid user's ID (existing or not) */
|
|
// TODO: Get only if ID confirmed?
|
|
sprintf (Query,"SELECT UsrCod"
|
|
" FROM usr_IDs"
|
|
" WHERE UsrID='%s'",
|
|
UsrIDNickOrEmail);
|
|
}
|
|
else // String is not a valid user's nickname, e-mail or ID
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad log in",
|
|
"User's e-mail, nickname or ID don't exist");
|
|
}
|
|
|
|
/***** Get user's data from database *****/
|
|
if ((NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get user's data")) == 1) // One unique user found in table of users' data
|
|
{
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/***** Get user code (row[0]) *****/
|
|
Gbl.Usrs.Me.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
Usr_GetUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat); // Get my data
|
|
|
|
if (Gbl.Usrs.Me.UsrDat.Email[0])
|
|
if (Pwd_SendNewPasswordByEmail (NewRandomPlainPassword) == 0) // Message sent successfully
|
|
{
|
|
Pwd_SetMyPendingPassword (NewRandomPlainPassword);
|
|
getNewPasswordOut->success = 1;
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************ Return courses of a user ***************************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getCourses (struct soap *soap,
|
|
char *wsKey, // input
|
|
struct swad__getCoursesOutput *getCoursesOut) // output
|
|
{
|
|
int ReturnCode;
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow,NumRows;
|
|
Rol_Role_t Role;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getCourses;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Query my courses from database *****/
|
|
sprintf (Query,"SELECT courses.CrsCod,courses.ShortName,courses.FullName,crs_usr.Role FROM crs_usr,courses"
|
|
" WHERE crs_usr.UsrCod='%ld' AND crs_usr.CrsCod=courses.CrsCod"
|
|
" ORDER BY courses.FullName",
|
|
Gbl.Usrs.Me.UsrDat.UsrCod);
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get user's courses");
|
|
|
|
getCoursesOut->numCourses = (int) NumRows;
|
|
getCoursesOut->coursesArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getCoursesOut->coursesArray.__ptr = NULL;
|
|
else // Courses found
|
|
{
|
|
getCoursesOut->coursesArray.__ptr = soap_malloc (Gbl.soap,(getCoursesOut->coursesArray.__size) * sizeof (*(getCoursesOut->coursesArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next course */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get course code (row[0]) */
|
|
getCoursesOut->coursesArray.__ptr[NumRow].courseCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get course short name (row[1]) */
|
|
getCoursesOut->coursesArray.__ptr[NumRow].courseShortName = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getCoursesOut->coursesArray.__ptr[NumRow].courseShortName,row[1],255);
|
|
getCoursesOut->coursesArray.__ptr[NumRow].courseShortName[255] = '\0';
|
|
|
|
/* Get course full name (row[2]) */
|
|
getCoursesOut->coursesArray.__ptr[NumRow].courseFullName = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getCoursesOut->coursesArray.__ptr[NumRow].courseFullName,row[2],255);
|
|
getCoursesOut->coursesArray.__ptr[NumRow].courseFullName[255] = '\0';
|
|
|
|
/* Get role (row[3]) */
|
|
if (sscanf (row[3],"%u",&Role) != 1) // Role in this course
|
|
Role = Rol_UNKNOWN;
|
|
getCoursesOut->coursesArray.__ptr[NumRow].userRole = Svc_GetRoleFromInternalRole (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;
|
|
Inf_InfoType_t InfoType;
|
|
Inf_InfoSrc_t InfoSrc;
|
|
bool MustBeRead;
|
|
int Result = SOAP_OK;
|
|
const char *NamesInWSForInfoType[Inf_NUM_INFO_TYPES] =
|
|
{
|
|
"introduction", // Inf_INTRODUCTION
|
|
"guide", // Inf_TEACHING_GUIDE
|
|
"lectures", // Inf_LECTURES
|
|
"practicals", // Inf_PRACTICALS
|
|
"bibliography", // Inf_BIBLIOGRAPHY
|
|
"FAQ", // Inf_FAQ
|
|
"links", // Inf_LINKS
|
|
"assessment", // Inf_ASSESSMENT
|
|
};
|
|
const char *NamesInWSForInfoSrc[Inf_NUM_INFO_SOURCES] =
|
|
{
|
|
"none", // Inf_INFO_SRC_NONE
|
|
"editor", // Inf_INFO_SRC_EDITOR
|
|
"plainText", // Inf_INFO_SRC_PLAIN_TEXT
|
|
"richText", // Inf_INFO_SRC_RICH_TEXT
|
|
"page", // Inf_INFO_SRC_PAGE
|
|
"URL", // Inf_INFO_SRC_URL
|
|
};
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getCourseInfo;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Check course and group codes *****/
|
|
if ((ReturnCode = Svc_CheckCourseAndGroupCodes (Gbl.CurrentCrs.Crs.CrsCod,-1L)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if I am a student or teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
|
|
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Get info source *****/
|
|
for (InfoType = (Inf_InfoType_t) 0;
|
|
InfoType < Inf_NUM_INFO_TYPES;
|
|
InfoType++)
|
|
if (!strcmp (infoType,NamesInWSForInfoType[InfoType]))
|
|
break;
|
|
if (InfoType == Inf_NUM_INFO_TYPES) // Not found!
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad info type",
|
|
"Unknown requested info type");
|
|
Inf_GetInfoSrcFromDB (Gbl.CurrentCrs.Crs.CrsCod,InfoType,&InfoSrc,&MustBeRead);
|
|
getCourseInfo->infoSrc = (char *) soap_malloc (Gbl.soap,strlen (NamesInWSForInfoSrc[InfoSrc]) + 1);
|
|
strcpy (getCourseInfo->infoSrc,NamesInWSForInfoSrc[InfoSrc]);
|
|
|
|
/***** Set paths *****/
|
|
Deg_InitCurrentCourse ();
|
|
|
|
/***** Get info text *****/
|
|
getCourseInfo->infoTxt = NULL;
|
|
switch (InfoSrc)
|
|
{
|
|
case Inf_INFO_SRC_NONE: // No info available
|
|
break;
|
|
case Inf_INFO_SRC_EDITOR: // Internal editor (only for syllabus)
|
|
switch (InfoType)
|
|
{
|
|
case Inf_LECTURES: // Syllabus (lectures)
|
|
case Inf_PRACTICALS: // Syllabys (practicals)
|
|
Result = Syl_WriteSyllabusIntoHTMLBuffer (InfoType,&(getCourseInfo->infoTxt));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case Inf_INFO_SRC_PLAIN_TEXT: // Plain text
|
|
case Inf_INFO_SRC_RICH_TEXT: // Rich text (not yet available)
|
|
Result = Inf_WritePlainTextIntoHTMLBuffer (InfoType,&(getCourseInfo->infoTxt));
|
|
break;
|
|
case Inf_INFO_SRC_PAGE: // Web page hosted in SWAD server
|
|
Result = Inf_WritePageIntoHTMLBuffer (InfoType,&(getCourseInfo->infoTxt));
|
|
break;
|
|
case Inf_INFO_SRC_URL: // Link to a web page
|
|
getCourseInfo->infoTxt = (char *) soap_malloc (Gbl.soap,Cns_MAX_BYTES_URL+1);
|
|
Inf_WriteURLIntoTxtBuffer (InfoType,getCourseInfo->infoTxt);
|
|
break;
|
|
}
|
|
|
|
/***** Return empty text if pointer is null *****/
|
|
if (getCourseInfo->infoTxt == NULL)
|
|
{
|
|
getCourseInfo->infoTxt = (char *) soap_malloc (Gbl.soap,1);
|
|
getCourseInfo->infoTxt[0] = '\0';
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************** Return students in a course **************************/
|
|
/*****************************************************************************/
|
|
// If groupCode <= 0 ==> get users from the whole course
|
|
|
|
int swad__getUsers (struct soap *soap,
|
|
char *wsKey,int courseCode,int groupCode,int userRole, // input
|
|
struct swad__getUsersOutput *getUsersOut) // output
|
|
{
|
|
int ReturnCode;
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow,NumRows;
|
|
bool UsrIDIsVisible;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getUsers;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
Gbl.CurrentCrs.Grps.GrpCod = (long) groupCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Check course and group codes *****/
|
|
if ((ReturnCode = Svc_CheckCourseAndGroupCodes (Gbl.CurrentCrs.Crs.CrsCod,Gbl.CurrentCrs.Grps.GrpCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if I am a student or teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
|
|
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Get degree of current course *****/
|
|
if ((ReturnCode = Svc_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Check requested users' type *****/
|
|
if (userRole != 2 && // student
|
|
userRole != 3) // teacher
|
|
{
|
|
sprintf (Gbl.Message,"Only students (user's type = %u) or teachers (user's type = %u) are allowed",
|
|
(unsigned) 2, // student
|
|
(unsigned) 3); // teacher
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad requested users' type",
|
|
Gbl.Message);
|
|
}
|
|
|
|
/***** Query users beloging to course or group from database *****/
|
|
if (groupCode <= 0) // Users belonging to the whole course
|
|
sprintf (Query,"SELECT usr_data.UsrCod"
|
|
" FROM crs_usr,usr_data"
|
|
" WHERE crs_usr.CrsCod='%ld' AND crs_usr.UsrCod=usr_data.UsrCod AND crs_usr.Role='%d'"
|
|
" ORDER BY usr_data.Surname1,usr_data.Surname2,usr_data.FirstName,usr_data.UsrCod",
|
|
(long) courseCode,
|
|
userRole == 2 ? (unsigned) Rol_STUDENT :
|
|
(unsigned) Rol_TEACHER);
|
|
else // Users belonging to the group
|
|
sprintf (Query,"SELECT usr_data.UsrCod"
|
|
" FROM crs_grp_usr,crs_usr,usr_data"
|
|
" WHERE crs_grp_usr.GrpCod='%ld' AND crs_grp_usr.UsrCod=crs_usr.UsrCod AND crs_grp_usr.UsrCod=usr_data.UsrCod AND crs_usr.Role='%d'"
|
|
" ORDER BY usr_data.Surname1,usr_data.Surname2,usr_data.FirstName,usr_data.UsrCod",
|
|
(long) groupCode,
|
|
userRole == 2 ? (unsigned) Rol_STUDENT :
|
|
(unsigned) Rol_TEACHER);
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get users");
|
|
|
|
getUsersOut->numUsers = (int) NumRows;
|
|
getUsersOut->usersArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getUsersOut->usersArray.__ptr = NULL;
|
|
else // Users found
|
|
{
|
|
getUsersOut->usersArray.__ptr = soap_malloc (Gbl.soap,(getUsersOut->usersArray.__size) * sizeof (*(getUsersOut->usersArray.__ptr)));
|
|
|
|
/***** Users' IDs are visible? *****/
|
|
UsrIDIsVisible = (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB == Rol_STUDENT &&
|
|
userRole == 2); // get students in the course
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next user */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get user's code (row[0]) */
|
|
if ((Gbl.Usrs.Other.UsrDat.UsrCod = (long) Str_ConvertStrCodToLongCod (row[0])) > 0)
|
|
/* Get user's data */
|
|
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat))
|
|
/* Copy user's data into output structure */
|
|
Svc_CopyUsrData (&(getUsersOut->usersArray.__ptr[NumRow]),&Gbl.Usrs.Other.UsrDat,UsrIDIsVisible);
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************** Return group types in a course ***********************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getGroupTypes (struct soap *soap,
|
|
char *wsKey,int courseCode, // input
|
|
struct swad__getGroupTypesOutput *getGroupTypesOut) // output
|
|
{
|
|
int ReturnCode;
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow,NumRows;
|
|
long OpenTime;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getGroupTypes;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
|
|
/***** Open groups of this course that must be opened
|
|
if open time is in the past *****/
|
|
Grp_OpenGroupsAutomatically ();
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (Gbl.CurrentCrs.Crs.CrsCod <= 0)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if I am a student or teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
|
|
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Query group types in a course from database *****/
|
|
sprintf (Query,"SELECT GrpTypCod,GrpTypName,Mandatory,Multiple,UNIX_TIMESTAMP(OpenTime)"
|
|
" FROM crs_grp_types"
|
|
" WHERE CrsCod='%d'"
|
|
" ORDER BY GrpTypName",
|
|
courseCode);
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get group types");
|
|
|
|
getGroupTypesOut->numGroupTypes = (int) NumRows;
|
|
getGroupTypesOut->groupTypesArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getGroupTypesOut->groupTypesArray.__ptr = NULL;
|
|
else // Groups found
|
|
{
|
|
getGroupTypesOut->groupTypesArray.__ptr = soap_malloc (Gbl.soap,(getGroupTypesOut->groupTypesArray.__size) * sizeof (*(getGroupTypesOut->groupTypesArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next group */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get group type code (row[0]) */
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumRow].groupTypeCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get group type name (row[1]) */
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumRow].groupTypeName = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getGroupTypesOut->groupTypesArray.__ptr[NumRow].groupTypeName,row[1],255);
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumRow].groupTypeName[255] = '\0';
|
|
|
|
/* Get whether enrollment is mandatory ('Y') or voluntary ('N') (row[2]) */
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumRow].mandatory = (row[2][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get whether user can enroll in multiple groups ('Y') or only in one group ('N') (row[3]) */
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumRow].multiple = (row[3][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get time of opening (row[4]) */
|
|
OpenTime = 0L;
|
|
if (row[4])
|
|
sscanf (row[4],"%ld",&OpenTime);
|
|
getGroupTypesOut->groupTypesArray.__ptr[NumRow].openTime = OpenTime;
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************** Return groups in a course ************************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getGroups (struct soap *soap,
|
|
char *wsKey,int courseCode, // input
|
|
struct swad__getGroupsOutput *getGroupsOut) // output
|
|
{
|
|
int ReturnCode;
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow,NumRows;
|
|
long GrpCod;
|
|
unsigned MaxStudents;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getGroups;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
|
|
/***** Open groups of this course that must be opened
|
|
if open time is in the past *****/
|
|
Grp_OpenGroupsAutomatically ();
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (Gbl.CurrentCrs.Crs.CrsCod <= 0)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if I am a student or teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
|
|
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Query groups in a course from database *****/
|
|
sprintf (Query,"SELECT crs_grp_types.GrpTypCod,crs_grp_types.GrpTypName,"
|
|
"crs_grp.GrpCod,crs_grp.GrpName,"
|
|
"crs_grp.MaxStudents,crs_grp.Open,crs_grp.FileZones"
|
|
" FROM crs_grp_types,crs_grp"
|
|
" WHERE crs_grp_types.CrsCod='%d'"
|
|
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod"
|
|
" ORDER BY crs_grp_types.GrpTypName,crs_grp.GrpName",
|
|
courseCode);
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get user's groups");
|
|
|
|
getGroupsOut->numGroups = (int) NumRows;
|
|
getGroupsOut->groupsArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getGroupsOut->groupsArray.__ptr = NULL;
|
|
else // Groups found
|
|
{
|
|
getGroupsOut->groupsArray.__ptr = soap_malloc (Gbl.soap,(getGroupsOut->groupsArray.__size) * sizeof (*(getGroupsOut->groupsArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next group */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get group type code (row[0]) */
|
|
getGroupsOut->groupsArray.__ptr[NumRow].groupTypeCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get group type name (row[1]) */
|
|
getGroupsOut->groupsArray.__ptr[NumRow].groupTypeName = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getGroupsOut->groupsArray.__ptr[NumRow].groupTypeName,row[1],255);
|
|
getGroupsOut->groupsArray.__ptr[NumRow].groupTypeName[255] = '\0';
|
|
|
|
/* Get group code (row[2]) */
|
|
GrpCod = Str_ConvertStrCodToLongCod (row[2]);
|
|
getGroupsOut->groupsArray.__ptr[NumRow].groupCode = (int) GrpCod;
|
|
|
|
/* Get group name (row[3]) */
|
|
getGroupsOut->groupsArray.__ptr[NumRow].groupName = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getGroupsOut->groupsArray.__ptr[NumRow].groupName,row[3],255);
|
|
getGroupsOut->groupsArray.__ptr[NumRow].groupName[255] = '\0';
|
|
|
|
/* Get max number of students of group (row[4]) and number of current students */
|
|
MaxStudents = Grp_ConvertToNumMaxStdsGrp (row[4]);
|
|
getGroupsOut->groupsArray.__ptr[NumRow].maxStudents = (MaxStudents > Grp_MAX_STUDENTS_IN_A_GROUP) ? -1 :
|
|
(int) MaxStudents;
|
|
|
|
/* Get number of current students */
|
|
getGroupsOut->groupsArray.__ptr[NumRow].numStudents = (int) Grp_CountNumStdsInGrp (GrpCod);
|
|
|
|
/* Get whether group is open ('Y') or closed ('N') (row[5]) */
|
|
getGroupsOut->groupsArray.__ptr[NumRow].open = (row[5][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get whether group have file zones ('Y') or not ('N') (row[6]) */
|
|
getGroupsOut->groupsArray.__ptr[NumRow].fileZones = (row[6][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get whether I belong to this group or not */
|
|
getGroupsOut->groupsArray.__ptr[NumRow].member = Grp_GetIfIBelongToGrp (GrpCod) ? 1 :
|
|
0;
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************* Send my groups in a course ************************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__sendMyGroups (struct soap *soap,
|
|
char *wsKey,int courseCode,char *myGroups, // input
|
|
struct swad__sendMyGroupsOutput *SendMyGroupsOut) // output
|
|
{
|
|
int ReturnCode;
|
|
struct ListCodGrps LstGrpsIWant;
|
|
const char *Ptr;
|
|
char LongStr[1+10+1];
|
|
unsigned NumGrp;
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow,NumRows;
|
|
long GrpCod;
|
|
unsigned MaxStudents;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_sendMyGroups;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (Gbl.CurrentCrs.Crs.CrsCod <= 0)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if I am a student or teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
|
|
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Get the group codes which I want to join to *****/
|
|
LstGrpsIWant.NumGrps = 0;
|
|
LstGrpsIWant.GrpCod = NULL;
|
|
|
|
if (myGroups[0])
|
|
{
|
|
/***** Count number of desired groups *****/
|
|
for (NumGrp = 0, Ptr = myGroups;
|
|
*Ptr;
|
|
NumGrp++)
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,1+10);
|
|
LstGrpsIWant.NumGrps = NumGrp;
|
|
|
|
if (LstGrpsIWant.NumGrps) // If I have selected groups...
|
|
{
|
|
/***** Create a list of groups selected from myGroups *****/
|
|
if ((LstGrpsIWant.GrpCod = (long *) calloc (LstGrpsIWant.NumGrps,sizeof (long))) == NULL)
|
|
Lay_ShowErrorAndExit ("Not enough memory to store the codes of the selected groups.");
|
|
for (NumGrp = 0, Ptr = myGroups;
|
|
*Ptr;
|
|
NumGrp++)
|
|
{
|
|
/* Find next string in text until comma (leading and trailing spaces are removed) */
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,1+10);
|
|
LstGrpsIWant.GrpCod[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 *****/
|
|
sprintf (Query,"SELECT crs_grp_types.GrpTypCod,crs_grp_types.GrpTypName,"
|
|
"crs_grp.GrpCod,crs_grp.GrpName,"
|
|
"crs_grp.MaxStudents,crs_grp.Open,crs_grp.FileZones"
|
|
" FROM crs_grp_types,crs_grp"
|
|
" WHERE crs_grp_types.CrsCod='%d'"
|
|
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod"
|
|
" ORDER BY crs_grp_types.GrpTypName,crs_grp.GrpName",
|
|
courseCode);
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get user's groups");
|
|
|
|
SendMyGroupsOut->numGroups = (int) NumRows;
|
|
SendMyGroupsOut->groupsArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
SendMyGroupsOut->groupsArray.__ptr = NULL;
|
|
else // Groups found
|
|
{
|
|
SendMyGroupsOut->groupsArray.__ptr = soap_malloc (Gbl.soap,(SendMyGroupsOut->groupsArray.__size) * sizeof (*(SendMyGroupsOut->groupsArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next group */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get group type code (row[0]) */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].groupTypeCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get group type name (row[1]) */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].groupTypeName = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (SendMyGroupsOut->groupsArray.__ptr[NumRow].groupTypeName,row[1],255);
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].groupTypeName[255] = '\0';
|
|
|
|
/* Get group code (row[2]) */
|
|
GrpCod = Str_ConvertStrCodToLongCod (row[2]);
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].groupCode = (int) GrpCod;
|
|
|
|
/* Get group name (row[3]) */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].groupName = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (SendMyGroupsOut->groupsArray.__ptr[NumRow].groupName,row[3],255);
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].groupName[255] = '\0';
|
|
|
|
/* Get max number of students of group (row[4]) and number of current students */
|
|
MaxStudents = Grp_ConvertToNumMaxStdsGrp (row[4]);
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].maxStudents = (MaxStudents > Grp_MAX_STUDENTS_IN_A_GROUP) ? -1 :
|
|
(int) MaxStudents;
|
|
|
|
/* Get number of current students */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].numStudents = (int) Grp_CountNumStdsInGrp (GrpCod);
|
|
|
|
/* Get whether group is open ('Y') or closed ('N') (row[5]) */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].open = (row[5][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get whether group have file zones ('Y') or not ('N') (row[6]) */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].fileZones = (row[6][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get whether I belong to this group or not */
|
|
SendMyGroupsOut->groupsArray.__ptr[NumRow].member = Grp_GetIfIBelongToGrp (GrpCod) ? 1 :
|
|
0;
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********** Copy data of a user from database to soap structure *************/
|
|
/*****************************************************************************/
|
|
|
|
static void Svc_CopyUsrData (struct swad__user *Usr,struct UsrData *UsrDat,bool UsrIDIsVisible)
|
|
{
|
|
char PhotoURL[PATH_MAX+1];
|
|
|
|
/* Copy user's code */
|
|
Usr->userCode = UsrDat->UsrCod;
|
|
|
|
/* Copy user's nickname */
|
|
Usr->userNickname = (char *) soap_malloc (Gbl.soap,Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA+1);
|
|
strncpy (Usr->userNickname,UsrDat->Nickname,Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA);
|
|
Usr->userNickname[Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA] = '\0';
|
|
|
|
/* Copy user's ID */
|
|
Usr->userID = (char *) soap_malloc (Gbl.soap,ID_MAX_LENGTH_USR_ID+1);
|
|
if (UsrIDIsVisible && UsrDat->IDs.List)
|
|
{
|
|
strncpy (Usr->userID,UsrDat->IDs.List[0].ID,ID_MAX_LENGTH_USR_ID);
|
|
Usr->userID[ID_MAX_LENGTH_USR_ID] = '\0';
|
|
}
|
|
else // Hide user's ID
|
|
strcpy (Usr->userID,"********");
|
|
|
|
/* Copy user's surname1 */
|
|
Usr->userSurname1 = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (Usr->userSurname1,UsrDat->Surname1,255);
|
|
Usr->userSurname1[255] = '\0';
|
|
|
|
/* Copy user's surname2 */
|
|
Usr->userSurname2 = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (Usr->userSurname2,UsrDat->Surname2,255);
|
|
Usr->userSurname2[255] = '\0';
|
|
|
|
/* Copy user's first name */
|
|
Usr->userFirstname = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (Usr->userFirstname,UsrDat->FirstName,255);
|
|
Usr->userFirstname[255] = '\0';
|
|
|
|
/* User's photo URL */
|
|
Pho_BuildLinkToPhoto (UsrDat,PhotoURL,false);
|
|
Usr->userPhoto = (char *) soap_malloc (Gbl.soap,PATH_MAX+1);
|
|
strncpy (Usr->userPhoto,PhotoURL,PATH_MAX);
|
|
Usr->userPhoto[PATH_MAX] = '\0';
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************** 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;
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
int NumAttEvent;
|
|
long AttCod;
|
|
char PhotoURL[PATH_MAX+1];
|
|
long StartTime;
|
|
long EndTime;
|
|
size_t Length;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getAttendanceEvents;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (Gbl.CurrentCrs.Crs.CrsCod <= 0)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if I am a teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
/***** Query list of attendance events *****/
|
|
sprintf (Query,"SELECT AttCod,UsrCod,"
|
|
"UNIX_TIMESTAMP(StartTime) AS ST,UNIX_TIMESTAMP(EndTime) AS ET,"
|
|
"CommentTchVisible,Title,Txt"
|
|
" FROM att_events"
|
|
" WHERE CrsCod='%d' AND Hidden='N'"
|
|
" ORDER BY ST DESC,ET DESC,Title DESC",
|
|
courseCode);
|
|
getAttendanceEventsOut->eventsArray.__size =
|
|
getAttendanceEventsOut->numEvents = (int) DB_QuerySELECT (Query,&mysql_res,"can not get attendance events");
|
|
|
|
if (getAttendanceEventsOut->numEvents == 0)
|
|
getAttendanceEventsOut->eventsArray.__ptr = NULL;
|
|
else // Events found
|
|
{
|
|
getAttendanceEventsOut->eventsArray.__ptr = soap_malloc (Gbl.soap,(getAttendanceEventsOut->eventsArray.__size) * sizeof (*(getAttendanceEventsOut->eventsArray.__ptr)));
|
|
|
|
for (NumAttEvent = 0;
|
|
NumAttEvent < getAttendanceEventsOut->numEvents;
|
|
NumAttEvent++)
|
|
{
|
|
/* Get next group */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get attendance event code (row[0]) */
|
|
AttCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].attendanceEventCode = (int) AttCod;
|
|
|
|
/* Get user's code of the user who created the event (row[1]) */
|
|
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[1]);
|
|
if (Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Gbl.CurrentCrs.Crs.CrsCod) == SOAP_OK) // Get some user's data from database
|
|
{
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname1 = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname1,
|
|
Gbl.Usrs.Other.UsrDat.Surname1);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname2 = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userSurname2,
|
|
Gbl.Usrs.Other.UsrDat.Surname2);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.FirstName);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userFirstname = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userFirstname,
|
|
Gbl.Usrs.Other.UsrDat.FirstName);
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL,false);
|
|
Length = strlen (PhotoURL);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userPhoto = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].userPhoto,
|
|
PhotoURL);
|
|
}
|
|
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[2]) */
|
|
StartTime = 0L;
|
|
if (row[2])
|
|
sscanf (row[2],"%ld",&StartTime);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].startTime = StartTime;
|
|
|
|
/* Get event end time (row[3]) */
|
|
EndTime = 0L;
|
|
if (row[3])
|
|
sscanf (row[3],"%ld",&EndTime);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].endTime = EndTime;
|
|
|
|
/* Get whether teachers comments are visible ('Y') or hidden ('N') (row[4]) */
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].commentsTeachersVisible = (row[4][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get title of the event (row[5]) */
|
|
Length = strlen (row[5]);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].title = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].title,
|
|
row[5]);
|
|
|
|
/* Get Txt (row[6]) */
|
|
Length = strlen (row[6]);
|
|
getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].text = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceEventsOut->eventsArray.__ptr[NumAttEvent].text,
|
|
row[6]);
|
|
|
|
/* Get list of groups for this attendance event */
|
|
Svc_GetListGrpsInAttendanceEvent (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 Svc_GetListGrpsInAttendanceEvent (long AttCod,char **ListGroups)
|
|
{
|
|
char Query[128];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
long NumGrps;
|
|
long NumGrp;
|
|
long GrpCod;
|
|
char GrpCodStr[10+1];
|
|
|
|
/***** Get list of groups *****/
|
|
sprintf (Query,"SELECT GrpCod FROM att_grp WHERE AttCod='%ld'",
|
|
AttCod);
|
|
if ((NumGrps = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get groups of an attendance event")) == 0)
|
|
*ListGroups = NULL;
|
|
else // Events found
|
|
{
|
|
*ListGroups = soap_malloc (Gbl.soap,NumGrps * 10);
|
|
|
|
for (NumGrp = 0;
|
|
NumGrp < NumGrps;
|
|
NumGrp++)
|
|
{
|
|
/* Get next group */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get group code (row[0]) */
|
|
GrpCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
sprintf (GrpCodStr,
|
|
NumGrp ? ",%ld" :
|
|
"%ld",
|
|
GrpCod);
|
|
strcat (*ListGroups,GrpCodStr);
|
|
}
|
|
}
|
|
|
|
/***** 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 AttendanceEvent Att;
|
|
bool ItsANewAttEvent;
|
|
const char *Ptr;
|
|
char LongStr[1+10+1];
|
|
unsigned NumGrp;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_sendAttendanceEvent;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (Gbl.CurrentCrs.Crs.CrsCod <= 0)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if I am a teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
/**** Get data of attendance event *****/
|
|
/* Event code */
|
|
Att.AttCod = (long) attendanceEventCode;
|
|
|
|
/* Course code */
|
|
if (Att.AttCod > 0) // The event already exists
|
|
{
|
|
Att_GetDataOfAttEventByCod (&Att);
|
|
if (Att.CrsCod != (long) courseCode)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Attendance event does not belong to course");
|
|
ItsANewAttEvent = false;
|
|
}
|
|
else
|
|
{
|
|
ItsANewAttEvent = true;
|
|
Att.CrsCod = (long) courseCode;
|
|
}
|
|
|
|
/* Is event hidden? */
|
|
Att.Hidden = (hidden ? true :
|
|
false);
|
|
|
|
/* User's code (really not used) */
|
|
Att.UsrCod = Gbl.Usrs.Me.UsrDat.UsrCod;
|
|
|
|
/* startTime */
|
|
Att.TimeUTC[Att_START_TIME] = (time_t) startTime;
|
|
|
|
/* endTime */
|
|
Att.TimeUTC[Att_END_TIME ] = (time_t) endTime;
|
|
|
|
/* Are teacher's comments visible? */
|
|
Att.CommentTchVisible = (commentsTeachersVisible ? true :
|
|
false);
|
|
|
|
/* Title */
|
|
strncpy (Att.Title,title,Att_MAX_LENGTH_ATTENDANCE_EVENT_TITLE);
|
|
Att.Title[Att_MAX_LENGTH_ATTENDANCE_EVENT_TITLE] = '\0';
|
|
|
|
/***** Count number of groups *****/
|
|
for (Ptr = groups, NumGrp = 0;
|
|
*Ptr;
|
|
NumGrp++)
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,1+10);
|
|
Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps = NumGrp;
|
|
|
|
/***** Create a list of groups selected *****/
|
|
if (Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps)
|
|
{
|
|
// Here NestedCalls is always 0
|
|
Gbl.CurrentCrs.Grps.LstGrpsSel.NestedCalls++;
|
|
// Here NestedCalls is always 1
|
|
if ((Gbl.CurrentCrs.Grps.LstGrpsSel.GrpCod = (long *) calloc (Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps,sizeof (long))) == NULL)
|
|
Lay_ShowErrorAndExit ("Not enough memory to store the codes of the selected groups.");
|
|
|
|
for (Ptr = groups, NumGrp = 0;
|
|
*Ptr;
|
|
)
|
|
{
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,1+10);
|
|
Gbl.CurrentCrs.Grps.LstGrpsSel.GrpCod[NumGrp] = Str_ConvertStrCodToLongCod (LongStr);
|
|
if (Grp_CheckIfGroupBelongsToCourse (Gbl.CurrentCrs.Grps.LstGrpsSel.GrpCod[NumGrp],Gbl.CurrentCrs.Crs.CrsCod))
|
|
NumGrp++;
|
|
}
|
|
Gbl.CurrentCrs.Grps.LstGrpsSel.NumGrps = NumGrp; // Update number of groups
|
|
}
|
|
|
|
/***** Create or update attendance event *****/
|
|
if (ItsANewAttEvent)
|
|
Att_CreateAttEvent (&Att,text); // Add new attendance event to database
|
|
else
|
|
Att_UpdateAttEvent (&Att,text); // Modify existing attendance event
|
|
|
|
/***** Free memory for list of selected groups *****/
|
|
Grp_FreeListCodSelectedGrps ();
|
|
|
|
sendAttendanceEventOut->attendanceEventCode = Att.AttCod;
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********** 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 AttendanceEvent Att;
|
|
char SubQuery[512];
|
|
char Query[1024];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow,NumRows;
|
|
char PhotoURL[PATH_MAX+1];
|
|
size_t Length;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getAttendanceUsers;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get course of this attendance event *****/
|
|
Att.AttCod = (long) attendanceEventCode;
|
|
Att_GetDataOfAttEventByCod (&Att);
|
|
Gbl.CurrentCrs.Crs.CrsCod = Att.CrsCod;
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if I am a teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
/***** Query list of attendance users *****/
|
|
if (Att_CheckIfAttEventIsAssociatedToGrps (Att.AttCod))
|
|
// Event for one or more groups
|
|
// Subquery: list of users in groups of this attendance event...
|
|
// ...who have no entry in attendance list of users
|
|
sprintf (SubQuery,"SELECT DISTINCT crs_grp_usr.UsrCod AS UsrCod,'N' AS Present"
|
|
" FROM att_grp,crs_grp,crs_grp_types,crs_usr,crs_grp_usr"
|
|
" WHERE att_grp.AttCod='%ld'"
|
|
" AND att_grp.GrpCod=crs_grp.GrpCod"
|
|
" AND crs_grp.GrpTypCod=crs_grp_types.GrpTypCod"
|
|
" AND crs_grp_types.CrsCod=crs_usr.CrsCod"
|
|
" AND crs_usr.Role='%u'"
|
|
" AND crs_usr.UsrCod=crs_grp_usr.UsrCod"
|
|
" AND crs_grp_usr.GrpCod=att_grp.GrpCod"
|
|
" AND crs_grp_usr.UsrCod NOT IN"
|
|
" (SELECT UsrCod FROM att_usr WHERE AttCod='%ld')",
|
|
Att.AttCod,
|
|
(unsigned) Rol_STUDENT,
|
|
Att.AttCod);
|
|
else
|
|
// Event for the whole course
|
|
// Subquery: list of users in the course of this attendance event...
|
|
// ...who have no entry in attendance list of users
|
|
sprintf (SubQuery,"SELECT crs_usr.UsrCod AS UsrCod,'N' AS Present"
|
|
" FROM att_events,crs_usr"
|
|
" WHERE att_events.AttCod='%ld'"
|
|
" AND att_events.CrsCod=crs_usr.CrsCod"
|
|
" AND crs_usr.Role='%u'"
|
|
" AND crs_usr.UsrCod NOT IN"
|
|
" (SELECT UsrCod FROM att_usr WHERE AttCod='%ld')",
|
|
Att.AttCod,
|
|
(unsigned) Rol_STUDENT,
|
|
Att.AttCod);
|
|
// Query: list of users in attendance list + rest of users (subquery)
|
|
sprintf (Query,"SELECT u.UsrCod,u.Present FROM "
|
|
"(SELECT UsrCod,Present"
|
|
" FROM att_usr WHERE AttCod='%ld'"
|
|
" UNION %s) AS u,usr_data"
|
|
" WHERE u.UsrCod=usr_data.UsrCod"
|
|
" ORDER BY usr_data.Surname1,usr_data.Surname2,usr_data.FirstName",
|
|
(long) attendanceEventCode,SubQuery);
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get users in an attendance event");
|
|
|
|
getAttendanceUsersOut->numUsers = (int) NumRows;
|
|
getAttendanceUsersOut->usersArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getAttendanceUsersOut->usersArray.__ptr = NULL;
|
|
else // Events found
|
|
{
|
|
getAttendanceUsersOut->usersArray.__ptr = soap_malloc (Gbl.soap,(getAttendanceUsersOut->usersArray.__size) * sizeof (*(getAttendanceUsersOut->usersArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next user */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get user's code (row[0]) */
|
|
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userCode = (int) Gbl.Usrs.Other.UsrDat.UsrCod;
|
|
|
|
/* Get user's data */
|
|
if (Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,-1L) == SOAP_OK) // Get some user's data from database
|
|
{
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Nickname);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userNickname = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userNickname,Gbl.Usrs.Other.UsrDat.Nickname);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.IDs.List[0].ID); // TODO: What user's ID?
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userID = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userID,Gbl.Usrs.Other.UsrDat.IDs.List[0].ID);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname1);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname1 = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname1,Gbl.Usrs.Other.UsrDat.Surname1);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.Surname2);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname2 = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname2,Gbl.Usrs.Other.UsrDat.Surname2);
|
|
|
|
Length = strlen (Gbl.Usrs.Other.UsrDat.FirstName);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userFirstname = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userFirstname,Gbl.Usrs.Other.UsrDat.FirstName);
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL,false);
|
|
Length = strlen (PhotoURL);
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userPhoto = (char *) soap_malloc (Gbl.soap,Length + 1);
|
|
strcpy (getAttendanceUsersOut->usersArray.__ptr[NumRow].userPhoto,PhotoURL);
|
|
}
|
|
else
|
|
{
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userNickname = NULL;
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userID = NULL;
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname1 = NULL;
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userSurname2 = NULL;
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userFirstname = NULL;
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].userPhoto = NULL;
|
|
}
|
|
|
|
/* Get if user is present or not (row[1]) */
|
|
getAttendanceUsersOut->usersArray.__ptr[NumRow].present = (row[1][0] == 'Y') ? 1 :
|
|
0;
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************ Send a list with the users in an attendance event **************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__sendAttendanceUsers (struct soap *soap,
|
|
char *wsKey,int attendanceEventCode,
|
|
char *users,int setOthersAsAbsent, // input
|
|
struct swad__sendAttendanceUsersOutput *sendAttendanceUsersOut) // output
|
|
{
|
|
int ReturnCode;
|
|
struct AttendanceEvent Att;
|
|
const char *Ptr;
|
|
char LongStr[1+10+1];
|
|
long UsrCod;
|
|
unsigned NumCodsInList;
|
|
char SubQuery[256];
|
|
char *Query = NULL; // Initialized to avoid warning
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_sendAttendanceUsers;
|
|
|
|
/***** Initialize output *****/
|
|
sendAttendanceUsersOut->success = 0;
|
|
sendAttendanceUsersOut->numUsers = 0;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get course of this attendance event *****/
|
|
Att.AttCod = (long) attendanceEventCode;
|
|
if (!Att_GetDataOfAttEventByCod (&Att))
|
|
return SOAP_OK; // return with success = 0
|
|
Gbl.CurrentCrs.Crs.CrsCod = Att.CrsCod;
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if I am a teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
if (setOthersAsAbsent)
|
|
{
|
|
/* Count number of codes in list */
|
|
for (Ptr = users, NumCodsInList = 0;
|
|
*Ptr;
|
|
NumCodsInList++)
|
|
/* Find next string in text until comma (leading and trailing spaces are removed) */
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,1+10);
|
|
|
|
/* Start query used to mark not present users as absent */
|
|
if ((Query = (char *) malloc (256 + NumCodsInList * (1+1+10+1))) == NULL)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Not enough memory",
|
|
"Not enough memory to store list of users");
|
|
sprintf (Query,"UPDATE att_usr SET Present='N'"
|
|
" WHERE AttCod='%ld'",
|
|
Att.AttCod);
|
|
}
|
|
|
|
for (Ptr = users;
|
|
*Ptr;
|
|
)
|
|
{
|
|
/* Find next string in text until comma (leading and trailing spaces are removed) */
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,1+10);
|
|
if ((UsrCod = Str_ConvertStrCodToLongCod (LongStr)) > 0)
|
|
if (Usr_ChkIfUsrCodExists (UsrCod))
|
|
// The user must belong to course,
|
|
// but it's not necessary he/she belongs to groups associated to the event
|
|
if (Usr_CheckIfUsrBelongsToCrs (UsrCod,
|
|
Gbl.CurrentCrs.Crs.CrsCod,
|
|
false))
|
|
{
|
|
/* Mark user as present */
|
|
Att_RegUsrInAttEventNotChangingComments (Att.AttCod,UsrCod);
|
|
|
|
/* Add this user to query used to mark not present users as absent */
|
|
if (setOthersAsAbsent)
|
|
{
|
|
sprintf (SubQuery,sendAttendanceUsersOut->numUsers ? ",'%ld'" :
|
|
" AND UsrCod NOT IN ('%ld'",
|
|
UsrCod);
|
|
strcat (Query,SubQuery);
|
|
}
|
|
|
|
sendAttendanceUsersOut->numUsers++;
|
|
}
|
|
}
|
|
|
|
if (setOthersAsAbsent)
|
|
{
|
|
/* Mark not present users as absent in table of users */
|
|
if (sendAttendanceUsersOut->numUsers)
|
|
strcat (Query,")");
|
|
|
|
DB_QueryUPDATE (Query,"can not set other users as absent");
|
|
free ((void *) Query);
|
|
|
|
/* Clean table att_usr */
|
|
Att_RemoveUsrsAbsentWithoutCommentsFromAttEvent (Att.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_Centre;
|
|
extern const char *Txt_Institution;
|
|
int ReturnCode;
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRows;
|
|
unsigned NumRow;
|
|
long NtfCod;
|
|
Ntf_NotifyEvent_t NotifyEvent;
|
|
long EventTime;
|
|
char PhotoURL[PATH_MAX+1];
|
|
struct Institution Ins;
|
|
struct Centre Ctr;
|
|
struct Degree Deg;
|
|
struct Course Crs;
|
|
long Cod;
|
|
char ForumName[512];
|
|
char *SummaryStr;
|
|
char *ContentStr;
|
|
Ntf_Status_t Status;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getNotifications;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Get my language from database *****/
|
|
if ((ReturnCode = Svc_GetMyLanguage ()) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
if ((SummaryStr = malloc (Cns_MAX_BYTES_TEXT+1)) == NULL)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Not enough memory",
|
|
"Not enough memory to store the summary of the notification");
|
|
|
|
/***** Get my notifications from database *****/
|
|
sprintf (Query,"SELECT NtfCod,NotifyEvent,UNIX_TIMESTAMP(TimeNotif),"
|
|
"FromUsrCod,InsCod,CtrCod,DegCod,CrsCod,Cod,Status"
|
|
" FROM notif"
|
|
" WHERE ToUsrCod='%ld' AND TimeNotif>=FROM_UNIXTIME('%ld')"
|
|
" ORDER BY TimeNotif DESC",
|
|
Gbl.Usrs.Me.UsrDat.UsrCod,beginTime);
|
|
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get user's notifications");
|
|
|
|
getNotificationsOut->numNotifications = (int) NumRows;
|
|
getNotificationsOut->notificationsArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getNotificationsOut->notificationsArray.__ptr = NULL;
|
|
else // Notifications found
|
|
{
|
|
getNotificationsOut->notificationsArray.__ptr = soap_malloc (Gbl.soap,(getNotificationsOut->notificationsArray.__size) * sizeof (*(getNotificationsOut->notificationsArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next notification */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get unique notification code (row[0]) */
|
|
NtfCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].notifCode = (int) NtfCod;
|
|
|
|
/* Get notification event type (row[1]) */
|
|
NotifyEvent = Ntf_GetNotifyEventFromDB ((const char *) row[1]);
|
|
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].eventType = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getNotificationsOut->notificationsArray.__ptr[NumRow].eventType,Ntf_WSNotifyEvents[NotifyEvent],255);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].eventType[255] = '\0';
|
|
|
|
/* Get time of the event (row[2]) */
|
|
EventTime = 0L;
|
|
if (row[2])
|
|
sscanf (row[2],"%ld",&EventTime);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].eventTime = EventTime;
|
|
|
|
/* Get course (row[7]) */
|
|
Crs.CrsCod = Str_ConvertStrCodToLongCod (row[7]);
|
|
Crs_GetDataOfCourseByCod (&Crs);
|
|
|
|
/* Get user's code of the user who caused the event (row[3]) */
|
|
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[3]);
|
|
if (Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,Crs.CrsCod) == SOAP_OK) // Get some user's data from database
|
|
{
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userNickname = (char *) soap_malloc (Gbl.soap,Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA+1);
|
|
strncpy (getNotificationsOut->notificationsArray.__ptr[NumRow].userNickname,Gbl.Usrs.Other.UsrDat.Nickname,Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userNickname[Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA] = '\0';
|
|
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userSurname1 = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getNotificationsOut->notificationsArray.__ptr[NumRow].userSurname1,Gbl.Usrs.Other.UsrDat.Surname1,255);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userSurname1[255] = '\0';
|
|
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userSurname2 = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getNotificationsOut->notificationsArray.__ptr[NumRow].userSurname2,Gbl.Usrs.Other.UsrDat.Surname2,255);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userSurname2[255] = '\0';
|
|
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userFirstname = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getNotificationsOut->notificationsArray.__ptr[NumRow].userFirstname,Gbl.Usrs.Other.UsrDat.FirstName,255);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userFirstname[255] = '\0';
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL,false);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userPhoto = (char *) soap_malloc (Gbl.soap,PATH_MAX+1);
|
|
strncpy (getNotificationsOut->notificationsArray.__ptr[NumRow].userPhoto,PhotoURL,PATH_MAX);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userPhoto[PATH_MAX] = '\0';
|
|
}
|
|
else
|
|
{
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userNickname = NULL;
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userSurname1 = NULL;
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userSurname2 = NULL;
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userFirstname = NULL;
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].userPhoto = NULL;
|
|
}
|
|
|
|
/* Get institution (row[4]) */
|
|
Ins.InsCod = Str_ConvertStrCodToLongCod (row[4]);
|
|
Ins_GetDataOfInstitutionByCod (&Ins,Ins_GET_BASIC_DATA);
|
|
|
|
/* Get centre (row[5]) */
|
|
Ctr.CtrCod = Str_ConvertStrCodToLongCod (row[5]);
|
|
Ctr_GetDataOfCentreByCod (&Ctr);
|
|
|
|
/* Get degree (row[6]) */
|
|
Deg.DegCod = Str_ConvertStrCodToLongCod (row[6]);
|
|
Deg_GetDataOfDegreeByCod (&Deg);
|
|
|
|
/* Get message/post/... code (row[8]) */
|
|
Cod = Str_ConvertStrCodToLongCod (row[8]);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].eventCode = (int) Cod;
|
|
|
|
/* Set location */
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].location = (char *) soap_malloc (Gbl.soap,1024);
|
|
|
|
if (NotifyEvent == Ntf_EVENT_FORUM_POST_COURSE ||
|
|
NotifyEvent == Ntf_EVENT_FORUM_REPLY)
|
|
{
|
|
For_SetForumName (For_GetForumTypeOfAPost (Cod),
|
|
&Ins,
|
|
&Ctr,
|
|
&Deg,
|
|
&Crs,
|
|
ForumName,Gbl.Prefs.Language,false); // Set forum name in recipient's language
|
|
sprintf (getNotificationsOut->notificationsArray.__ptr[NumRow].location,"%s: %s",
|
|
Txt_Forum,ForumName);
|
|
}
|
|
else if (Crs.CrsCod > 0)
|
|
sprintf (getNotificationsOut->notificationsArray.__ptr[NumRow].location,"%s: %s",
|
|
Txt_Course,Crs.ShortName);
|
|
else if (Deg.DegCod > 0)
|
|
sprintf (getNotificationsOut->notificationsArray.__ptr[NumRow].location,"%s: %s",
|
|
Txt_Degree,Deg.ShortName);
|
|
else if (Ctr.CtrCod > 0)
|
|
sprintf (getNotificationsOut->notificationsArray.__ptr[NumRow].location,"%s: %s",
|
|
Txt_Centre,Ctr.ShortName);
|
|
else if (Ins.InsCod > 0)
|
|
sprintf (getNotificationsOut->notificationsArray.__ptr[NumRow].location,"%s: %s",
|
|
Txt_Institution,Ins.ShortName);
|
|
else
|
|
strcpy (getNotificationsOut->notificationsArray.__ptr[NumRow].location,"-");
|
|
|
|
/* Get status (row[9]) */
|
|
if (sscanf (row[9],"%u",&Status) != 1)
|
|
Status = (Ntf_Status_t) 0;
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].status = (int) Status;
|
|
|
|
/* Get summary and content */
|
|
ContentStr = NULL;
|
|
Ntf_GetNotifSummaryAndContent (SummaryStr,&ContentStr,NotifyEvent,
|
|
Cod,Crs.CrsCod,Gbl.Usrs.Me.UsrDat.UsrCod,Cfg_MAX_CHARS_NOTIF_SUMMARY_WEB_SERVICE,true);
|
|
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].summary = (char *) soap_malloc (Gbl.soap,strlen (SummaryStr)+1);
|
|
strcpy (getNotificationsOut->notificationsArray.__ptr[NumRow].summary,SummaryStr);
|
|
|
|
if (ContentStr != NULL)
|
|
{
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].content = (char *) soap_malloc (Gbl.soap,strlen (ContentStr)+1);
|
|
|
|
strcpy (getNotificationsOut->notificationsArray.__ptr[NumRow].content,ContentStr);
|
|
|
|
free ((void *) ContentStr);
|
|
ContentStr = NULL;
|
|
}
|
|
else
|
|
{
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].content = (char *) soap_malloc (Gbl.soap,1);
|
|
getNotificationsOut->notificationsArray.__ptr[NumRow].content[0] = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
/***** Free summary *****/
|
|
free ((void *) SummaryStr);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********************* Get my language from database *************************/
|
|
/*****************************************************************************/
|
|
|
|
static int Svc_GetMyLanguage (void)
|
|
{
|
|
extern const char *Txt_STR_LANG_ID[1+Txt_NUM_LANGUAGES];
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
Txt_Language_t Lan;
|
|
|
|
/***** Get user's language *****/
|
|
sprintf (Query,"SELECT Language FROM usr_data"
|
|
" WHERE UsrCod='%ld'",
|
|
Gbl.Usrs.Me.UsrDat.UsrCod);
|
|
if (DB_QuerySELECT (Query,&mysql_res,"can not get user's language") != 1)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Can not get user's language from database",
|
|
"User doen't exist in database");
|
|
|
|
/***** Get language from database *****/
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get language (row[0]) */
|
|
Gbl.Prefs.Language = Txt_LANGUAGE_UNKNOWN; // Language unknown
|
|
for (Lan = (Txt_Language_t) 1;
|
|
Lan <= Txt_NUM_LANGUAGES;
|
|
Lan++)
|
|
if (!strcasecmp (row[0],Txt_STR_LANG_ID[Lan]))
|
|
{
|
|
Gbl.Prefs.Language = Lan;
|
|
break;
|
|
}
|
|
if (Gbl.Prefs.Language == Txt_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);
|
|
|
|
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[1+10+1];
|
|
unsigned NumNtf;
|
|
unsigned NumNtfsMarkedAsRead = 0;
|
|
long NtfCod;
|
|
char Query[512];
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_markNotificationsAsRead;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
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,1+10);
|
|
if ((NtfCod = Str_ConvertStrCodToLongCod (LongStr)) > 0)
|
|
{
|
|
/***** Mark notification as read in the database *****/
|
|
sprintf (Query,"UPDATE notif SET Status=(Status | %u)"
|
|
" WHERE NtfCod='%ld' AND ToUsrCod='%ld'",
|
|
(unsigned) Ntf_STATUS_BIT_READ,
|
|
(long) NtfCod,Gbl.Usrs.Me.UsrDat.UsrCod);
|
|
DB_QueryUPDATE (Query,"can not mark notification as read");
|
|
|
|
NumNtfsMarkedAsRead++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***** Return notification code *****/
|
|
markNotificationsAsReadOut->numNotifications = (int) NumNtfsMarkedAsRead;
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************** Send a message to one or more users **********************/
|
|
/*****************************************************************************/
|
|
|
|
#define Svc_MAX_LENGHT_QUERY_RECIPIENTS (10*1024)
|
|
|
|
int swad__sendMessage (struct soap *soap,
|
|
char *wsKey,int messageCode,char *to,char *subject,char *body, // input
|
|
struct swad__sendMessageOutput *sendMessageOut) // output
|
|
{
|
|
int ReturnCode;
|
|
long ReplyUsrCod = -1L;
|
|
char Nickname[Nck_MAX_BYTES_NICKNAME_WITH_ARROBA+1];
|
|
char Query[Svc_MAX_LENGHT_QUERY_RECIPIENTS+1];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow,NumRows;
|
|
bool FirstNickname = true;
|
|
bool ThereAreNicknames = false;
|
|
const char *Ptr;
|
|
bool NotifyByEmail;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_sendMessage;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,-1L)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if the message is a reply to a previous message *****/
|
|
if (messageCode)
|
|
{
|
|
/***** Check if the original message was really received by me *****/
|
|
sprintf (Query,"SELECT SUM(N) FROM"
|
|
" (SELECT COUNT(*) AS N FROM msg_rcv"
|
|
" WHERE UsrCod='%ld' AND MsgCod='%ld'"
|
|
" UNION"
|
|
" SELECT COUNT(*) AS N FROM msg_rcv_deleted"
|
|
" WHERE UsrCod='%ld' AND MsgCod='%ld') AS T",
|
|
Gbl.Usrs.Me.UsrDat.UsrCod,(long) messageCode,
|
|
Gbl.Usrs.Me.UsrDat.UsrCod,(long) messageCode);
|
|
if (!DB_QuerySELECT (Query,&mysql_res,"can not check original message"))
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Can not check original message",
|
|
"Error reading from database");
|
|
|
|
/***** Get number of rows *****/
|
|
row = mysql_fetch_row (mysql_res);
|
|
if (sscanf (row[0],"%u",&NumRows) != 1)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Can not check original message",
|
|
"Error reading from database");
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
if (!NumRows)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Can not send reply message",
|
|
"Original message does not exist");
|
|
|
|
/***** Get the recipient of the message *****/
|
|
sprintf (Query,"SELECT UsrCod FROM msg_snt"
|
|
" WHERE MsgCod='%ld'"
|
|
" UNION "
|
|
"SELECT UsrCod FROM msg_snt_deleted"
|
|
" WHERE MsgCod='%ld'",
|
|
(long) messageCode,(long) messageCode);
|
|
if ((NumRows = DB_QuerySELECT (Query,&mysql_res,"can not check original message"))) // Message found in any of the two tables of sent messages
|
|
{
|
|
row = mysql_fetch_row (mysql_res);
|
|
ReplyUsrCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
if (!NumRows)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Can not send reply message",
|
|
"Original message does not exist");
|
|
}
|
|
|
|
|
|
/***** Build query for recipients from database *****/
|
|
if (ReplyUsrCod > 0)
|
|
sprintf (Query,"SELECT UsrCod FROM usr_data"
|
|
" WHERE UsrCod='%ld'",
|
|
ReplyUsrCod);
|
|
else
|
|
Query[0] = '\0';
|
|
|
|
/***** Loop over recipients' nicknames building query *****/
|
|
Ptr = to;
|
|
while (*Ptr)
|
|
{
|
|
/* Find next string in text until comma (leading and trailing spaces are removed) */
|
|
Str_GetNextStringUntilComma (&Ptr,Nickname,Nck_MAX_BYTES_NICKNAME_WITH_ARROBA);
|
|
|
|
/* Check if string is a valid nickname */
|
|
if (Nck_CheckIfNickWithArrobaIsValid (Nickname)) // String is a nickname?
|
|
{
|
|
Str_RemoveLeadingArrobas (Nickname);
|
|
|
|
/* Check for overflow in query */
|
|
if (strlen (Query)+Nck_MAX_LENGTH_NICKNAME_WITHOUT_ARROBA+32 > Svc_MAX_LENGHT_QUERY_RECIPIENTS)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Can not send message",
|
|
"Too many recipients");
|
|
|
|
/* Add this nickname to query */
|
|
if (FirstNickname)
|
|
{
|
|
if (ReplyUsrCod > 0)
|
|
strcat (Query," UNION ");
|
|
strcat (Query,"SELECT UsrCod FROM usr_nicknames"
|
|
" WHERE Nickname IN ('");
|
|
FirstNickname = false;
|
|
ThereAreNicknames = true;
|
|
}
|
|
else
|
|
strcat (Query,",'");
|
|
strcat (Query,Nickname);
|
|
strcat (Query,"'");
|
|
}
|
|
}
|
|
if (ThereAreNicknames)
|
|
strcat (Query,")");
|
|
|
|
/***** Initialize output structure *****/
|
|
sendMessageOut->numUsers = 0;
|
|
sendMessageOut->usersArray.__size = 0;
|
|
sendMessageOut->usersArray.__ptr = NULL;
|
|
|
|
if (ReplyUsrCod > 0 || ThereAreNicknames) // There are a recipient to reply or nicknames in "to"
|
|
{
|
|
/***** Get users *****/
|
|
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get users");
|
|
|
|
sendMessageOut->numUsers = (int) NumRows;
|
|
sendMessageOut->usersArray.__size = (int) NumRows;
|
|
|
|
if (NumRows) // Users found
|
|
{
|
|
sendMessageOut->usersArray.__ptr = soap_malloc (Gbl.soap,(sendMessageOut->usersArray.__size) * sizeof (*(sendMessageOut->usersArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next user */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get user's code (row[0]) */
|
|
if ((Gbl.Usrs.Other.UsrDat.UsrCod = (long) Str_ConvertStrCodToLongCod (row[0])) > 0)
|
|
/* Get recipient data */
|
|
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat))
|
|
{
|
|
/* This received message must be notified by e-mail? */
|
|
NotifyByEmail = ((Gbl.Usrs.Other.UsrDat.UsrCod != Gbl.Usrs.Me.UsrDat.UsrCod) &&
|
|
(Gbl.Usrs.Other.UsrDat.Prefs.EmailNtfEvents & (1 << Ntf_EVENT_MESSAGE)));
|
|
|
|
/* Send message to this user */
|
|
if ((ReturnCode = Svc_sendMessageToUsr ((long) messageCode,Gbl.Usrs.Me.UsrDat.UsrCod,ReplyUsrCod,Gbl.Usrs.Other.UsrDat.UsrCod,NotifyByEmail,subject,body)) != SOAP_OK)
|
|
{
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
return ReturnCode;
|
|
}
|
|
|
|
/* Copy user's data into output structure */
|
|
Svc_CopyUsrData (&(sendMessageOut->usersArray.__ptr[NumRow]),&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 Svc_sendMessageToUsr (long OriginalMsgCod,long SenderUsrCod,long ReplyUsrCod,long RecipientUsrCod,bool NotifyByEmail,const char *Subject,const char *Content)
|
|
{
|
|
static bool MsgAlreadyInserted = false;
|
|
static long NewMsgCod;
|
|
char Query[512+Cns_MAX_BYTES_SUBJECT+Cns_MAX_BYTES_LONG_TEXT];
|
|
|
|
/***** Create message *****/
|
|
if (!MsgAlreadyInserted) // The message is inserted only once in the table of messages sent
|
|
{
|
|
/***** Insert message subject and body in the database *****/
|
|
/* Build query */
|
|
sprintf (Query,"INSERT INTO msg_content (Subject,Content)"
|
|
" VALUES ('%s','%s')",Subject,Content);
|
|
|
|
/* Get the code of the inserted item */
|
|
NewMsgCod = DB_QueryINSERTandReturnCode (Query,"can not create message");
|
|
|
|
/***** Insert message in sent messages *****/
|
|
sprintf (Query,"INSERT INTO msg_snt (MsgCod,CrsCod,UsrCod,Expanded,CreatTime)"
|
|
" VALUES ('%ld','-1','%ld','N',NOW())",
|
|
NewMsgCod,SenderUsrCod);
|
|
DB_QueryINSERT (Query,"can not create message");
|
|
|
|
MsgAlreadyInserted = true;
|
|
}
|
|
|
|
/***** Insert message received in the database *****/
|
|
sprintf (Query,"INSERT INTO msg_rcv (MsgCod,UsrCod,Notified,Open,Replied,Expanded)"
|
|
" VALUES ('%ld','%ld','%c','N','N','N')",
|
|
NewMsgCod,RecipientUsrCod,
|
|
NotifyByEmail ? 'Y' :
|
|
'N');
|
|
DB_QueryINSERT (Query,"can not create received message");
|
|
|
|
/***** Create notification for this recipient.
|
|
If this recipient wants to receive notifications by e-mail, activate the sending of a notification *****/
|
|
sprintf (Query,"INSERT INTO notif (NotifyEvent,ToUsrCod,FromUsrCod,InsCod,DegCod,CrsCod,Cod,TimeNotif,Status)"
|
|
" VALUES ('%u','%ld','%ld','-1','-1','-1','%ld',NOW(),'%u')",
|
|
(unsigned) Ntf_EVENT_MESSAGE,
|
|
RecipientUsrCod,
|
|
SenderUsrCod,
|
|
NewMsgCod,
|
|
(unsigned) (NotifyByEmail ? Ntf_STATUS_BIT_EMAIL :
|
|
0));
|
|
DB_QueryINSERT (Query,"can not create new notification event");
|
|
|
|
/***** If this recipient is the original sender of a message been replied... *****/
|
|
if (RecipientUsrCod == ReplyUsrCod)
|
|
{
|
|
/***** ...then update received message setting Replied field to true *****/
|
|
sprintf (Query,"UPDATE msg_rcv SET Replied='Y' WHERE MsgCod='%ld' AND UsrCod='%ld'",
|
|
OriginalMsgCod,SenderUsrCod);
|
|
DB_QueryUPDATE (Query,"can not update a received message");
|
|
}
|
|
|
|
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;
|
|
char Query[512+Cns_MAX_BYTES_TEXT];
|
|
long NotCod;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_sendNotice;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check course and group codes *****/
|
|
if ((ReturnCode = Svc_CheckCourseAndGroupCodes (Gbl.CurrentCrs.Crs.CrsCod,-1L)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get degree of current course *****/
|
|
if ((ReturnCode = Svc_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Check if I am a teacher *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must be a teacher");
|
|
|
|
/***** Insert notice in the database *****/
|
|
/* Build query */
|
|
sprintf (Query,"INSERT INTO notices (CrsCod,UsrCod,CreatTime,Content,Status)"
|
|
" VALUES ('%ld','%ld',NOW(),'%s','%u')",
|
|
Gbl.CurrentCrs.Crs.CrsCod,Gbl.Usrs.Me.UsrDat.UsrCod,
|
|
body,(unsigned) Not_ACTIVE_NOTICE);
|
|
|
|
/* Get the code of the inserted item */
|
|
NotCod = DB_QueryINSERTandReturnCode (Query,"can not create message");
|
|
|
|
/***** Create notifications *****/
|
|
// TODO: create notifications
|
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
/***** Return notification code *****/
|
|
sendNoticeOut->noticeCode = (int) NotCod;
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****************** Return test configuration in a course ********************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getTestConfig (struct soap *soap,
|
|
char *wsKey,int courseCode, // input
|
|
struct swad__getTestConfigOutput *getTestConfigOut) // output
|
|
{
|
|
extern const char *Tst_FeedbackXML[Tst_NUM_TYPES_FEEDBACK];
|
|
int ReturnCode;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getTestConfig;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (Gbl.CurrentCrs.Crs.CrsCod <= 0)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** Check if I am a student or teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
|
|
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Get degree of current course *****/
|
|
if ((ReturnCode = Svc_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Set default result to empty *****/
|
|
getTestConfigOut->numQuestions = getTestConfigOut->minQuestions = getTestConfigOut->defQuestions = getTestConfigOut->maxQuestions = 0;
|
|
getTestConfigOut->feedback = (char *) soap_malloc (Gbl.soap,256);
|
|
getTestConfigOut->feedback[0] = '\0';
|
|
|
|
/***** Get test configuration *****/
|
|
if ((ReturnCode = Svc_GetTstConfig ((long) courseCode)) != SOAP_OK)
|
|
return ReturnCode;
|
|
getTestConfigOut->pluggable = (Gbl.Test.Config.Pluggable == Tst_PLUGGABLE_YES) ? 1 :
|
|
0;
|
|
getTestConfigOut->minQuestions = (int) Gbl.Test.Config.Min;
|
|
getTestConfigOut->defQuestions = (int) Gbl.Test.Config.Def;
|
|
getTestConfigOut->maxQuestions = (int) Gbl.Test.Config.Max;
|
|
// if (Gbl.Test.Config.FeedbackType == Tst_FEEDBACK_FULL_FEEDBACK)
|
|
// Gbl.Test.Config.FeedbackType = Tst_FEEDBACK_EACH_GOOD_BAD; // TODO: remove this when SWADroid uses it
|
|
strncpy (getTestConfigOut->feedback,Tst_FeedbackXML[Gbl.Test.Config.FeedbackType],255);
|
|
getTestConfigOut->feedback[255] = '\0';
|
|
|
|
/***** Get number of tests *****/
|
|
if (Gbl.Test.Config.Pluggable == Tst_PLUGGABLE_YES &&
|
|
Gbl.Test.Config.Max > 0)
|
|
getTestConfigOut->numQuestions = Svc_GetNumTestQuestionsInCrs ((long) courseCode);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/****** Get configuration of tests from database giving a course code ********/
|
|
/*****************************************************************************/
|
|
|
|
static int Svc_GetTstConfig (long CrsCod)
|
|
{
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
|
|
/***** Query database *****/
|
|
sprintf (Query,"SELECT Pluggable,Min,Def,Max,MinTimeNxtTstPerQst,Feedback"
|
|
" FROM tst_config WHERE CrsCod='%ld'",
|
|
CrsCod);
|
|
if (DB_QuerySELECT (Query,&mysql_res,"can not get test configuration"))
|
|
{
|
|
/***** Get minimun, default and maximum *****/
|
|
row = mysql_fetch_row (mysql_res);
|
|
Tst_GetConfigFromRow (row);
|
|
}
|
|
else // NumRows == 0
|
|
{
|
|
Gbl.Test.Config.Pluggable = Tst_PLUGGABLE_UNKNOWN;
|
|
Gbl.Test.Config.Min = Gbl.Test.Config.Def = Gbl.Test.Config.Max = 0;
|
|
Gbl.Test.Config.FeedbackType = Tst_FEEDBACK_DEFAULT;
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/** Get number of visible test questions from database giving a course code **/
|
|
/*****************************************************************************/
|
|
|
|
static int Svc_GetNumTestQuestionsInCrs (long CrsCod)
|
|
{
|
|
char Query[512];
|
|
|
|
/***** Get number of questions *****/
|
|
// Reject questions with any tag hidden
|
|
// Select only questions with tags
|
|
sprintf (Query,"SELECT COUNT(*)"
|
|
" FROM tst_questions,tst_question_tags,tst_tags"
|
|
" WHERE tst_questions.CrsCod='%ld'"
|
|
" AND tst_questions.QstCod NOT IN"
|
|
" (SELECT tst_question_tags.QstCod FROM tst_tags,tst_question_tags"
|
|
" WHERE tst_tags.CrsCod='%ld' AND tst_tags.TagHidden='Y'"
|
|
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
|
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
|
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
|
" AND tst_tags.CrsCod='%ld'",
|
|
CrsCod,CrsCod,CrsCod);
|
|
return (int) DB_QueryCOUNT (Query,"can not get number of test questions");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************* 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;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getTests;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if course code is correct *****/
|
|
if (Gbl.CurrentCrs.Crs.CrsCod <= 0)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/***** Check if I am a student or teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
|
|
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Get degree of current course *****/
|
|
if ((ReturnCode = Svc_GetCurrentDegCodFromCurrentCrsCod ()) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Set default result to empty *****/
|
|
getTestsOut->tagsArray.__size = 0;
|
|
getTestsOut->tagsArray.__ptr = NULL;
|
|
getTestsOut->questionsArray.__size = 0;
|
|
getTestsOut->questionsArray.__ptr = NULL;
|
|
getTestsOut->answersArray.__size = 0;
|
|
getTestsOut->answersArray.__ptr = NULL;
|
|
getTestsOut->questionTagsArray.__size = 0;
|
|
getTestsOut->questionTagsArray.__ptr = NULL;
|
|
|
|
/***** Get test configuration *****/
|
|
if ((ReturnCode = Svc_GetTstConfig ((long) courseCode)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
if (Gbl.Test.Config.Pluggable == Tst_PLUGGABLE_YES)
|
|
{
|
|
/***** Get tags *****/
|
|
if ((ReturnCode = Svc_GetTstTags ((long) courseCode,getTestsOut)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get questions *****/
|
|
if ((ReturnCode = Svc_GetTstQuestions ((long) courseCode,beginTime,getTestsOut)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get answers *****/
|
|
if ((ReturnCode = Svc_GetTstAnswers ((long) courseCode,beginTime,getTestsOut)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get tags for each question *****/
|
|
if ((ReturnCode = Svc_GetTstQuestionTags ((long) courseCode,beginTime,getTestsOut)) != SOAP_OK)
|
|
return ReturnCode;
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**** Get test tags (only not hidden) from database giving a course code *****/
|
|
/*****************************************************************************/
|
|
|
|
static int Svc_GetTstTags (long CrsCod,struct swad__getTestsOutput *getTestsOut)
|
|
{
|
|
extern const char *Txt_STR_LANG_ID[1+Txt_NUM_LANGUAGES];
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow,NumRows;
|
|
|
|
/***** Get available tags from database *****/
|
|
sprintf (Query,"SELECT TagCod,TagTxt"
|
|
" FROM tst_tags"
|
|
" WHERE CrsCod='%ld' AND TagHidden='N'"
|
|
" ORDER BY TagTxt",
|
|
CrsCod);
|
|
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get test tags");
|
|
|
|
getTestsOut->tagsArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getTestsOut->tagsArray.__ptr = NULL;
|
|
else // Tags found
|
|
{
|
|
getTestsOut->tagsArray.__ptr = soap_malloc (Gbl.soap,(getTestsOut->tagsArray.__size) * sizeof (*(getTestsOut->tagsArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next tag */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get tag code (row[0]) */
|
|
getTestsOut->tagsArray.__ptr[NumRow].tagCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get tag text (row[1]) */
|
|
getTestsOut->tagsArray.__ptr[NumRow].tagText = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getTestsOut->tagsArray.__ptr[NumRow].tagText,row[1],255);
|
|
getTestsOut->tagsArray.__ptr[NumRow].tagText[255] = '\0';
|
|
}
|
|
}
|
|
|
|
/***** 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 Svc_GetTstQuestions (long CrsCod,long BeginTime,struct swad__getTestsOutput *getTestsOut)
|
|
{
|
|
extern const char *Tst_StrAnswerTypesXML[Tst_NUM_ANS_TYPES];
|
|
char Query[1024];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow;
|
|
unsigned NumRows;
|
|
Tst_AnswerType_t AnswerType;
|
|
|
|
/***** Get recent test questions from database *****/
|
|
// DISTINCTROW is necessary to not repeat questions
|
|
sprintf (Query,"SELECT DISTINCTROW tst_questions.QstCod,"
|
|
"tst_questions.AnsType,tst_questions.Shuffle,"
|
|
"tst_questions.Stem,tst_questions.Feedback"
|
|
" FROM tst_questions,tst_question_tags,tst_tags"
|
|
" WHERE tst_questions.CrsCod='%ld'"
|
|
" AND tst_questions.QstCod NOT IN"
|
|
" (SELECT tst_question_tags.QstCod FROM tst_tags,tst_question_tags"
|
|
" WHERE tst_tags.CrsCod='%ld' AND tst_tags.TagHidden='Y'"
|
|
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
|
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
|
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
|
" AND tst_tags.CrsCod='%ld'"
|
|
" AND "
|
|
"("
|
|
"tst_questions.EditTime>=FROM_UNIXTIME('%ld')"
|
|
" OR "
|
|
"tst_tags.ChangeTime>=FROM_UNIXTIME('%ld')"
|
|
")"
|
|
" ORDER BY QstCod",
|
|
CrsCod,CrsCod,CrsCod,
|
|
BeginTime,
|
|
BeginTime);
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test questions");
|
|
|
|
getTestsOut->questionsArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getTestsOut->questionsArray.__ptr = NULL;
|
|
else // Questions found
|
|
{
|
|
getTestsOut->questionsArray.__ptr = soap_malloc (Gbl.soap,(getTestsOut->questionsArray.__size) * sizeof (*(getTestsOut->questionsArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next question */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get question code (row[0]) */
|
|
getTestsOut->questionsArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get answer type (row[1]) */
|
|
AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
|
|
getTestsOut->questionsArray.__ptr[NumRow].answerType = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getTestsOut->questionsArray.__ptr[NumRow].answerType,Tst_StrAnswerTypesXML[AnswerType],255);
|
|
getTestsOut->questionsArray.__ptr[NumRow].answerType[255] = '\0';
|
|
|
|
/* Get shuffle (row[2]) */
|
|
getTestsOut->questionsArray.__ptr[NumRow].shuffle = (row[2][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get question stem (row[3]) */
|
|
getTestsOut->questionsArray.__ptr[NumRow].stem = (char *) soap_malloc (Gbl.soap,Cns_MAX_BYTES_TEXT+1);
|
|
strncpy (getTestsOut->questionsArray.__ptr[NumRow].stem,row[3],Cns_MAX_BYTES_TEXT);
|
|
getTestsOut->questionsArray.__ptr[NumRow].stem[Cns_MAX_BYTES_TEXT] = '\0';
|
|
|
|
/* Get question feedback (row[4]) */
|
|
getTestsOut->questionsArray.__ptr[NumRow].feedback = (char *) soap_malloc (Gbl.soap,Cns_MAX_BYTES_TEXT+1);
|
|
strncpy (getTestsOut->questionsArray.__ptr[NumRow].feedback,row[4],Cns_MAX_BYTES_TEXT);
|
|
getTestsOut->questionsArray.__ptr[NumRow].feedback[Cns_MAX_BYTES_TEXT] = '\0';
|
|
}
|
|
}
|
|
|
|
/***** 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 Svc_GetTstAnswers (long CrsCod,long BeginTime,struct swad__getTestsOutput *getTestsOut)
|
|
{
|
|
extern const char *Tst_StrAnswerTypesXML[Tst_NUM_ANS_TYPES];
|
|
char Query[1024];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow,NumRows;
|
|
unsigned Index;
|
|
|
|
/***** Get recent test questions from database *****/
|
|
sprintf (Query,"SELECT QstCod,AnsInd,Correct,Answer,Feedback"
|
|
" FROM tst_answers WHERE QstCod IN "
|
|
"(SELECT tst_questions.QstCod"
|
|
" FROM tst_questions,tst_question_tags,tst_tags"
|
|
" WHERE tst_questions.CrsCod='%ld'"
|
|
" AND tst_questions.QstCod NOT IN"
|
|
" (SELECT tst_question_tags.QstCod FROM tst_tags,tst_question_tags"
|
|
" WHERE tst_tags.CrsCod='%ld' AND tst_tags.TagHidden='Y'"
|
|
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
|
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
|
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
|
" AND tst_tags.CrsCod='%ld'"
|
|
" AND "
|
|
"("
|
|
"tst_questions.EditTime>=FROM_UNIXTIME('%ld')"
|
|
" OR "
|
|
"tst_tags.ChangeTime>=FROM_UNIXTIME('%ld')"
|
|
")"
|
|
")"
|
|
" ORDER BY QstCod,AnsInd",
|
|
CrsCod,CrsCod,CrsCod,
|
|
BeginTime,
|
|
BeginTime);
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test answers");
|
|
|
|
getTestsOut->answersArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getTestsOut->answersArray.__ptr = NULL;
|
|
else // Answers found
|
|
{
|
|
getTestsOut->answersArray.__ptr = soap_malloc (Gbl.soap,(getTestsOut->answersArray.__size) * sizeof (*(getTestsOut->answersArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next question */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get question code (row[0]) */
|
|
getTestsOut->answersArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get answer index (row[1]) */
|
|
if (sscanf (row[1],"%u",&Index) == 1)
|
|
getTestsOut->answersArray.__ptr[NumRow].answerIndex = (int) Index;
|
|
else
|
|
getTestsOut->answersArray.__ptr[NumRow].answerIndex = 0; // error
|
|
|
|
/* Get correct (row[2]) */
|
|
getTestsOut->answersArray.__ptr[NumRow].correct = (row[2][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get answer (row[3]) */
|
|
getTestsOut->answersArray.__ptr[NumRow].answerText = (char *) soap_malloc (Gbl.soap,Cns_MAX_BYTES_TEXT+1);
|
|
strncpy (getTestsOut->answersArray.__ptr[NumRow].answerText,row[3],Cns_MAX_BYTES_TEXT);
|
|
getTestsOut->answersArray.__ptr[NumRow].answerText[Cns_MAX_BYTES_TEXT] = '\0';
|
|
|
|
/* Get feedback (row[4]) */
|
|
getTestsOut->answersArray.__ptr[NumRow].answerFeedback = (char *) soap_malloc (Gbl.soap,Cns_MAX_BYTES_TEXT+1);
|
|
strncpy (getTestsOut->answersArray.__ptr[NumRow].answerFeedback,row[4],Cns_MAX_BYTES_TEXT);
|
|
getTestsOut->answersArray.__ptr[NumRow].answerFeedback[Cns_MAX_BYTES_TEXT] = '\0';
|
|
}
|
|
}
|
|
|
|
/***** 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 Svc_GetTstQuestionTags (long CrsCod,long BeginTime,struct swad__getTestsOutput *getTestsOut)
|
|
{
|
|
extern const char *Tst_StrAnswerTypesXML[Tst_NUM_ANS_TYPES];
|
|
char Query[1024];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow,NumRows;
|
|
unsigned Index;
|
|
|
|
/***** Get recent test questions from database *****/
|
|
sprintf (Query,"SELECT QstCod,TagCod,TagInd"
|
|
" FROM tst_question_tags WHERE QstCod IN "
|
|
"(SELECT tst_questions.QstCod"
|
|
" FROM tst_questions,tst_question_tags,tst_tags"
|
|
" WHERE tst_questions.CrsCod='%ld'"
|
|
" AND tst_questions.QstCod NOT IN"
|
|
" (SELECT tst_question_tags.QstCod FROM tst_tags,tst_question_tags"
|
|
" WHERE tst_tags.CrsCod='%ld' AND tst_tags.TagHidden='Y'"
|
|
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
|
" AND tst_questions.QstCod=tst_question_tags.QstCod"
|
|
" AND tst_question_tags.TagCod=tst_tags.TagCod"
|
|
" AND tst_tags.CrsCod='%ld'"
|
|
" AND "
|
|
"("
|
|
"tst_questions.EditTime>=FROM_UNIXTIME('%ld')"
|
|
" OR "
|
|
"tst_tags.ChangeTime>=FROM_UNIXTIME('%ld')"
|
|
")"
|
|
")"
|
|
" ORDER BY QstCod,TagInd",
|
|
CrsCod,CrsCod,CrsCod,
|
|
BeginTime,
|
|
BeginTime);
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test question tags");
|
|
|
|
getTestsOut->questionTagsArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getTestsOut->questionTagsArray.__ptr = NULL;
|
|
else // Answers found
|
|
{
|
|
getTestsOut->questionTagsArray.__ptr = soap_malloc (Gbl.soap,(getTestsOut->questionTagsArray.__size) * sizeof (*(getTestsOut->questionTagsArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next question */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get question code (row[0]) */
|
|
getTestsOut->questionTagsArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get tag code (row[1]) */
|
|
getTestsOut->questionTagsArray.__ptr[NumRow].tagCode = (int) Str_ConvertStrCodToLongCod (row[1]);
|
|
|
|
/* Get tag index (row[2]) */
|
|
if (sscanf (row[2],"%u",&Index) == 1)
|
|
getTestsOut->questionTagsArray.__ptr[NumRow].tagIndex = (int) Index;
|
|
else
|
|
getTestsOut->questionTagsArray.__ptr[NumRow].tagIndex = 0; // error
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
/***************** 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 *Tst_StrAnswerTypesXML[Tst_NUM_ANS_TYPES];
|
|
int ReturnCode;
|
|
const char *Ptr;
|
|
char LongStr[1+10+1];
|
|
char DegreesStr[1024];
|
|
char DegStr[ 1+1+1+ 10 +1+ 1];
|
|
// DegStr=", ' - number ' \0"
|
|
long DegCod;
|
|
bool FirstDegree = true;
|
|
char Query[4096];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumRow;
|
|
unsigned NumRows;
|
|
long QstCod = -1L;
|
|
Tst_AnswerType_t AnswerType;
|
|
unsigned Index;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getTrivialQuestion;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Loop over recipients' nicknames building query *****/
|
|
DegreesStr[0] = '\0';
|
|
Ptr = degrees;
|
|
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod == 19543)
|
|
{
|
|
char QueryDebug[512*1024];
|
|
|
|
sprintf (QueryDebug,"INSERT INTO debug (DebugTime,Txt) VALUES (NOW(),'degrees = %s')",degrees);
|
|
DB_QueryINSERT (QueryDebug,"Error inserting in debug table");
|
|
}
|
|
|
|
while (*Ptr)
|
|
{
|
|
/* Find next string in text until comma (leading and trailing spaces are removed) */
|
|
Str_GetNextStringUntilComma (&Ptr,LongStr,1+10);
|
|
|
|
/* 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)
|
|
{
|
|
sprintf (DegreesStr,"'%ld'",DegCod);
|
|
FirstDegree = false;
|
|
}
|
|
else
|
|
{
|
|
sprintf (DegStr,",'%ld'",DegCod);
|
|
strcat (DegreesStr,DegStr);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!DegreesStr[0]) // Degrees not found
|
|
return soap_sender_fault (Gbl.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 (Gbl.soap,
|
|
"Bad score interval",
|
|
"lowerScore or upperScore values not valid");
|
|
|
|
/***** Start query *****/
|
|
setlocale (LC_NUMERIC,"en_US.utf8"); // To print the floating point as a dot
|
|
sprintf (Query,"SELECT DISTINCTROW tst_questions.QstCod,"
|
|
"tst_questions.AnsType,tst_questions.Shuffle,"
|
|
"tst_questions.Stem,tst_questions.Feedback,"
|
|
"tst_questions.Score/tst_questions.NumHits AS S"
|
|
" FROM courses,tst_questions"
|
|
" WHERE courses.DegCod IN (%s)"
|
|
" AND courses.CrsCod=tst_questions.CrsCod"
|
|
" AND tst_questions.AnsType='unique_choice'"
|
|
" AND tst_questions.NumHits>'0'"
|
|
" AND tst_questions.QstCod NOT IN"
|
|
" (SELECT tst_question_tags.QstCod"
|
|
" FROM courses,tst_tags,tst_question_tags"
|
|
" WHERE courses.DegCod IN (%s)"
|
|
" AND courses.CrsCod=tst_tags.CrsCod"
|
|
" AND tst_tags.TagHidden='Y'"
|
|
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
|
|
" HAVING S>='%f' AND S<='%f'"
|
|
" ORDER BY RAND(NOW()) LIMIT 1",
|
|
DegreesStr,DegreesStr,
|
|
lowerScore,upperScore);
|
|
setlocale (LC_NUMERIC,"es_ES.utf8"); // Return to spanish system (TODO: this should be internationalized!!!!!!!)
|
|
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test questions");
|
|
|
|
if (NumRows == 1) // Question found
|
|
{
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod == 19543)
|
|
{
|
|
char QueryDebug[512*1024];
|
|
|
|
sprintf (QueryDebug,"INSERT INTO debug (DebugTime,Txt) VALUES (NOW(),'Una pregunta devuelta')");
|
|
DB_QueryINSERT (QueryDebug,"Error inserting in debug table");
|
|
}
|
|
|
|
/* Get next question */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get question code (row[0]) */
|
|
QstCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
getTrivialQuestionOut->question.questionCode = (int) QstCod;
|
|
|
|
/* Get answer type (row[1]) */
|
|
AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
|
|
getTrivialQuestionOut->question.answerType = (char *) soap_malloc (Gbl.soap,256);
|
|
strncpy (getTrivialQuestionOut->question.answerType,Tst_StrAnswerTypesXML[AnswerType],255);
|
|
getTrivialQuestionOut->question.answerType[255] = '\0';
|
|
|
|
/* Get shuffle (row[2]) */
|
|
getTrivialQuestionOut->question.shuffle = (row[2][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get question stem (row[3]) */
|
|
getTrivialQuestionOut->question.stem = (char *) soap_malloc (Gbl.soap,Cns_MAX_BYTES_TEXT+1);
|
|
strncpy (getTrivialQuestionOut->question.stem,row[3],Cns_MAX_BYTES_TEXT);
|
|
getTrivialQuestionOut->question.stem[Cns_MAX_BYTES_TEXT] = '\0';
|
|
|
|
/* Get question feedback (row[4]) */
|
|
getTrivialQuestionOut->question.feedback = (char *) soap_malloc (Gbl.soap,Cns_MAX_BYTES_TEXT+1);
|
|
strncpy (getTrivialQuestionOut->question.feedback,row[4],Cns_MAX_BYTES_TEXT);
|
|
getTrivialQuestionOut->question.feedback[Cns_MAX_BYTES_TEXT] = '\0';
|
|
}
|
|
else // Empty question
|
|
{
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod == 19543)
|
|
{
|
|
char QueryDebug[512*1024];
|
|
|
|
sprintf (QueryDebug,"INSERT INTO debug (DebugTime,Txt) VALUES (NOW(),'Ninguna pregunta devuelta')");
|
|
DB_QueryINSERT (QueryDebug,"Error inserting in debug table");
|
|
}
|
|
|
|
/* Question code (row[0]) */
|
|
QstCod = -1L;
|
|
getTrivialQuestionOut->question.questionCode = -1;
|
|
|
|
/* Answer type (row[1]) */
|
|
getTrivialQuestionOut->question.answerType = (char *) soap_malloc (Gbl.soap,1);
|
|
getTrivialQuestionOut->question.answerType[0] = '\0';
|
|
|
|
/* Shuffle (row[2]) */
|
|
getTrivialQuestionOut->question.shuffle = 0;
|
|
|
|
/* Question stem (row[3]) */
|
|
getTrivialQuestionOut->question.stem = (char *) soap_malloc (Gbl.soap,1);
|
|
getTrivialQuestionOut->question.stem[0] = '\0';
|
|
|
|
/* Get question feedback (row[4]) */
|
|
getTrivialQuestionOut->question.feedback = (char *) soap_malloc (Gbl.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 *****/
|
|
sprintf (Query,"SELECT QstCod,AnsInd,Correct,Answer,Feedback"
|
|
" FROM tst_answers WHERE QstCod='%ld'"
|
|
" ORDER BY AnsInd",
|
|
QstCod);
|
|
NumRows = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get test answers");
|
|
|
|
getTrivialQuestionOut->answersArray.__size = (int) NumRows;
|
|
|
|
if (NumRows == 0)
|
|
getTrivialQuestionOut->answersArray.__ptr = NULL;
|
|
else // Answers found
|
|
{
|
|
getTrivialQuestionOut->answersArray.__ptr = soap_malloc (Gbl.soap,(getTrivialQuestionOut->answersArray.__size) * sizeof (*(getTrivialQuestionOut->answersArray.__ptr)));
|
|
|
|
for (NumRow = 0;
|
|
NumRow < NumRows;
|
|
NumRow++)
|
|
{
|
|
/* Get next question */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get question code (row[0]) */
|
|
getTrivialQuestionOut->answersArray.__ptr[NumRow].questionCode = (int) Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
/* Get answer index (row[1]) */
|
|
if (sscanf (row[1],"%u",&Index) == 1)
|
|
getTrivialQuestionOut->answersArray.__ptr[NumRow].answerIndex = (int) Index;
|
|
else
|
|
getTrivialQuestionOut->answersArray.__ptr[NumRow].answerIndex = 0; // error
|
|
|
|
/* Get correct (row[2]) */
|
|
getTrivialQuestionOut->answersArray.__ptr[NumRow].correct = (row[2][0] == 'Y') ? 1 :
|
|
0;
|
|
|
|
/* Get answer (row[3]) */
|
|
getTrivialQuestionOut->answersArray.__ptr[NumRow].answerText = (char *) soap_malloc (Gbl.soap,Cns_MAX_BYTES_TEXT+1);
|
|
strncpy (getTrivialQuestionOut->answersArray.__ptr[NumRow].answerText,row[3],Cns_MAX_BYTES_TEXT);
|
|
getTrivialQuestionOut->answersArray.__ptr[NumRow].answerText[Cns_MAX_BYTES_TEXT] = '\0';
|
|
|
|
/* Get feedback (row[4]) */
|
|
getTrivialQuestionOut->answersArray.__ptr[NumRow].answerFeedback = (char *) soap_malloc (Gbl.soap,Cns_MAX_BYTES_TEXT+1);
|
|
strncpy (getTrivialQuestionOut->answersArray.__ptr[NumRow].answerFeedback,row[4],Cns_MAX_BYTES_TEXT);
|
|
getTrivialQuestionOut->answersArray.__ptr[NumRow].answerFeedback[Cns_MAX_BYTES_TEXT] = '\0';
|
|
}
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*************** 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 PathXMLPriv[PATH_MAX+1];
|
|
char XMLFileName[PATH_MAX+1];
|
|
unsigned long FileSize;
|
|
unsigned long NumBytesRead;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getDirectoryTree;
|
|
Gbl.CurrentCrs.Crs.CrsCod = (long) courseCode;
|
|
Gbl.CurrentCrs.Grps.GrpCod = (long) groupCode;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check course and group codes *****/
|
|
if ((ReturnCode = Svc_CheckCourseAndGroupCodes (Gbl.CurrentCrs.Crs.CrsCod,Gbl.CurrentCrs.Grps.GrpCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Check if I am a student or teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
|
|
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Check if I belong to course/group *****/
|
|
if (Gbl.CurrentCrs.Grps.GrpCod > 0)
|
|
if (!Grp_GetIfIBelongToGrp (Gbl.CurrentCrs.Grps.GrpCod))
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to group");
|
|
|
|
/***** Check if tree code is correct *****/
|
|
if (treeCode <= 0 || treeCode > 3)
|
|
return soap_sender_fault (Gbl.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_DOCUM_GRP;
|
|
break;
|
|
case 2: // Shared files
|
|
Gbl.FileBrowser.Type = Brw_ADMI_SHARE_GRP;
|
|
break;
|
|
case 3: // Marks
|
|
Gbl.FileBrowser.Type = Brw_SHOW_MARKS_GRP;
|
|
break;
|
|
}
|
|
else // groupCode <= 0
|
|
switch (treeCode)
|
|
{
|
|
case 1: // Documents
|
|
Gbl.FileBrowser.Type = Brw_SHOW_DOCUM_CRS;
|
|
break;
|
|
case 2: // Shared files
|
|
Gbl.FileBrowser.Type = Brw_ADMI_SHARE_CRS;
|
|
break;
|
|
case 3: // Marks
|
|
Gbl.FileBrowser.Type = Brw_SHOW_MARKS_CRS;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad course code",
|
|
"Course code must be a integer greater than 0");
|
|
|
|
/* Initialize path to private directory */
|
|
Gbl.CurrentCrs.Crs.CrsCod = (courseCode > 0) ? (long) courseCode :
|
|
-1L;
|
|
Gbl.CurrentCrs.Grps.GrpCod = (groupCode > 0) ? (long) groupCode :
|
|
-1L;
|
|
|
|
sprintf (Gbl.CurrentCrs.PathPriv,"%s/%s/%ld",
|
|
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_CRS,Gbl.CurrentCrs.Crs.CrsCod);
|
|
Brw_InitializeFileBrowser ();
|
|
Brw_SetFullPathInTree (Brw_RootFolderInternalNames[Gbl.FileBrowser.Type],".");
|
|
|
|
/* Check if exists the directory for HTML output. If not exists, create it */
|
|
sprintf (PathXMLPriv,"%s/%s",Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_OUT);
|
|
Fil_CreateDirIfNotExists (PathXMLPriv);
|
|
|
|
/* Create a unique name for the file */
|
|
sprintf (XMLFileName,"%s/%s.xml",
|
|
PathXMLPriv,Gbl.UniqueNameEncrypted);
|
|
|
|
/* Open file for writing and reading */
|
|
if ((Gbl.F.XML = fopen (XMLFileName,"w+t")) == NULL)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Can not get tree",
|
|
"Can not create temporary XML file");
|
|
|
|
/* Get directory tree into XML file */
|
|
XML_WriteStartFile (Gbl.F.XML,"tree",false);
|
|
if (!Brw_CheckIfFileOrFolderIsSetAsHiddenInDB (Brw_IS_FOLDER,
|
|
Gbl.FileBrowser.Priv.FullPathInTree)) // If root folder is visible
|
|
Svc_ListDir (1,Gbl.FileBrowser.Priv.PathRootFolder,Brw_RootFolderInternalNames[Gbl.FileBrowser.Type]);
|
|
XML_WriteEndFile (Gbl.F.XML,"tree");
|
|
|
|
/* Compute file size */
|
|
// fseek (Gbl.F.XML,0L,SEEK_END);
|
|
FileSize = (unsigned long) ftell (Gbl.F.XML);
|
|
fseek (Gbl.F.XML,0L,SEEK_SET);
|
|
|
|
/* Copy XML content from file to memory */
|
|
getDirectoryTreeOut->tree = (char *) soap_malloc (Gbl.soap,FileSize + 1);
|
|
NumBytesRead = fread (getDirectoryTreeOut->tree,1,FileSize,Gbl.F.XML);
|
|
getDirectoryTreeOut->tree[NumBytesRead] = '\0';
|
|
|
|
/* Close and remove XML file */
|
|
Fil_CloseXMLFile ();
|
|
unlink (XMLFileName);
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************************ List a directory recursively ***********************/
|
|
/*****************************************************************************/
|
|
|
|
static void Svc_ListDir (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];
|
|
char PathFileInExplTree[PATH_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 ".."
|
|
{
|
|
sprintf (PathFileRel ,"%s/%s",Path ,FileList[NumFile]->d_name);
|
|
sprintf (PathFileInExplTree,"%s/%s",PathInTree,FileList[NumFile]->d_name);
|
|
|
|
lstat (PathFileRel,&FileStatus);
|
|
|
|
/***** Construct the full path of the file or folder *****/
|
|
Brw_SetFullPathInTree (PathInTree,FileList[NumFile]->d_name);
|
|
|
|
if (S_ISDIR (FileStatus.st_mode)) // It's a directory
|
|
{
|
|
/***** Write a row for the subdirectory *****/
|
|
if (Svc_WriteRowFileBrowser (Level,Brw_IS_FOLDER,FileList[NumFile]->d_name))
|
|
{
|
|
/* List subtree starting at this this directory */
|
|
Svc_ListDir (Level + 1,PathFileRel,PathFileInExplTree);
|
|
|
|
/* Indent and end dir */
|
|
Svc_IndentXMLLine (Level);
|
|
fprintf (Gbl.F.XML,"</dir>%s",Txt_NEW_LINE);
|
|
}
|
|
}
|
|
else if (S_ISREG (FileStatus.st_mode)) // It's a regular file
|
|
Svc_WriteRowFileBrowser (Level,
|
|
Str_FileIs (FileList[NumFile]->d_name,"url") ? Brw_IS_LINK :
|
|
Brw_IS_FILE,
|
|
FileList[NumFile]->d_name);
|
|
}
|
|
|
|
free ((void *) FileList[NumFile]);
|
|
}
|
|
free ((void *) 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 Svc_WriteRowFileBrowser (unsigned Level,Brw_FileType_t FileType,const char *FileName)
|
|
{
|
|
extern const char *Txt_NEW_LINE;
|
|
extern const char *Txt_LICENSES[Brw_NUM_LICENSES];
|
|
struct FileMetadata FileMetadata;
|
|
char PhotoURL[PATH_MAX+1];
|
|
|
|
/***** Is this row hidden or visible? *****/
|
|
if (Gbl.FileBrowser.Type == Brw_SHOW_DOCUM_CRS ||
|
|
Gbl.FileBrowser.Type == Brw_SHOW_DOCUM_GRP)
|
|
if (Brw_CheckIfFileOrFolderIsSetAsHiddenInDB (FileType,
|
|
Gbl.FileBrowser.Priv.FullPathInTree))
|
|
return false;
|
|
|
|
/***** XML row *****/
|
|
/* Indent */
|
|
Svc_IndentXMLLine (Level);
|
|
|
|
/* Write file or folder data */
|
|
if (FileType == Brw_IS_FOLDER)
|
|
fprintf (Gbl.F.XML,"<dir name=\"%s\">%s",
|
|
FileName,Txt_NEW_LINE);
|
|
else // File or link
|
|
{
|
|
/* Get file metadata */
|
|
Brw_GetFileMetadataByPath (&FileMetadata);
|
|
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_AddPathToDB (-1L,FileMetadata.FileType,
|
|
Gbl.FileBrowser.Priv.FullPathInTree,false,Brw_LICENSE_DEFAULT);
|
|
|
|
Gbl.Usrs.Other.UsrDat.UsrCod = FileMetadata.PublisherUsrCod;
|
|
Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat);
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Me.UsrDat,PhotoURL,false);
|
|
|
|
fprintf (Gbl.F.XML,"<file name=\"%s\">"
|
|
"<code>%ld</code>"
|
|
"<size>%lu</size>"
|
|
"<time>%lu</time>"
|
|
"<license>%s</license>"
|
|
"<publisher>%s</publisher>"
|
|
"<photo>%s</photo>"
|
|
"</file>%s",
|
|
FileName,
|
|
FileMetadata.FilCod,
|
|
(unsigned long) FileMetadata.Size,
|
|
(unsigned long) FileMetadata.Time,
|
|
Txt_LICENSES[FileMetadata.License],
|
|
Gbl.Usrs.Other.UsrDat.FullName,
|
|
PhotoURL,
|
|
Txt_NEW_LINE);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************************* Indent XML line *****************************/
|
|
/*****************************************************************************/
|
|
|
|
static void Svc_IndentXMLLine (unsigned Level)
|
|
{
|
|
for ( ;
|
|
Level;
|
|
Level--)
|
|
fprintf (Gbl.F.XML,"\t");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**************************** Get info of a file *****************************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getFile (struct soap *soap,
|
|
char *wsKey,int fileCode, // input
|
|
struct swad__getFileOutput *getFileOut) // output
|
|
{
|
|
extern const char *Txt_LICENSES[Brw_NUM_LICENSES];
|
|
int ReturnCode;
|
|
struct FileMetadata FileMetadata;
|
|
char PathUntilFileName[PATH_MAX+1];
|
|
char FileName[NAME_MAX+1];
|
|
char URL[PATH_MAX+1];
|
|
char PhotoURL[PATH_MAX+1];
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getFile;
|
|
|
|
/***** Allocate space for strings *****/
|
|
getFileOut->fileName = (char *) soap_malloc (Gbl.soap,NAME_MAX+1);
|
|
getFileOut->URL = (char *) soap_malloc (Gbl.soap,PATH_MAX+1);
|
|
getFileOut->license = (char *) soap_malloc (Gbl.soap,256);
|
|
getFileOut->publisherName = (char *) soap_malloc (Gbl.soap,255+1+255+1+255+1);
|
|
getFileOut->publisherPhoto = (char *) soap_malloc (Gbl.soap,PATH_MAX+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 = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get file metadata *****/
|
|
FileMetadata.FilCod = (long) fileCode;
|
|
if (FileMetadata.FilCod <= 0)
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Bad file code",
|
|
"File code must be a integer greater than 0");
|
|
|
|
Brw_GetFileMetadataByCod (&FileMetadata);
|
|
if (FileMetadata.FilCod <= 0)
|
|
return soap_sender_fault (Gbl.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.CurrentCrs.Crs.CrsCod,
|
|
&Gbl.CurrentCrs.Grps.GrpCod);
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check course and group codes *****/
|
|
if ((ReturnCode = Svc_CheckCourseAndGroupCodes (Gbl.CurrentCrs.Crs.CrsCod,Gbl.CurrentCrs.Grps.GrpCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Check if I am a student or teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
|
|
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Check if I belong to group *****/
|
|
if (Gbl.CurrentCrs.Grps.GrpCod > 0)
|
|
if (!Grp_GetIfIBelongToGrp (Gbl.CurrentCrs.Grps.GrpCod))
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to group");
|
|
|
|
/***** Check if file is in a valid zone *****/
|
|
switch ((Gbl.FileBrowser.Type = FileMetadata.FileBrowser))
|
|
{
|
|
// case Brw_SHOW_DOCUM_CRS: // This type of file browser is not in database
|
|
// case Brw_SHOW_DOCUM_GRP: // This type of file browser is not in database
|
|
case Brw_ADMI_DOCUM_CRS:
|
|
case Brw_ADMI_DOCUM_GRP:
|
|
case Brw_ADMI_SHARE_CRS:
|
|
case Brw_ADMI_SHARE_GRP:
|
|
break;
|
|
case Brw_ADMI_MARKS_CRS:
|
|
case Brw_ADMI_MARKS_GRP:
|
|
// Downloading a file of marks is only allowed for teachers
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Wrong tree",
|
|
"Wrong file zone");
|
|
break;
|
|
default:
|
|
return soap_sender_fault (Gbl.soap,
|
|
"Wrong tree",
|
|
"Wrong file zone");
|
|
}
|
|
|
|
/***** Set paths *****/
|
|
Deg_InitCurrentCourse ();
|
|
Str_SplitFullPathIntoPathAndFileName (FileMetadata.Path,PathUntilFileName,FileName);
|
|
Brw_SetFullPathInTree (PathUntilFileName,FileName);
|
|
Brw_InitializeFileBrowser ();
|
|
|
|
/***** 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 (PathUntilFileName,
|
|
FileName,
|
|
URL);
|
|
|
|
/***** Copy data into output structure *****/
|
|
strncpy (getFileOut->fileName,FileName,NAME_MAX);
|
|
getFileOut->fileName[NAME_MAX] = '\0';
|
|
|
|
strncpy (getFileOut->URL,URL,PATH_MAX);
|
|
getFileOut->URL[PATH_MAX] = '\0';
|
|
|
|
getFileOut->size = (int) FileMetadata.Size;
|
|
|
|
getFileOut->time = (int) FileMetadata.Time;
|
|
|
|
strncpy (getFileOut->license,Txt_LICENSES[FileMetadata.License],255);
|
|
getFileOut->license[255] = '\0';
|
|
|
|
if ((Gbl.Usrs.Other.UsrDat.UsrCod = FileMetadata.PublisherUsrCod) > 0)
|
|
/* Get publisher's data */
|
|
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat))
|
|
/* Copy publisher's data into output structure */
|
|
{
|
|
strncpy (getFileOut->publisherName,Gbl.Usrs.Other.UsrDat.FullName,255+1+255+1+255);
|
|
getFileOut->publisherName[255+1+255+1+255] = '\0';
|
|
|
|
Pho_BuildLinkToPhoto (&Gbl.Usrs.Other.UsrDat,PhotoURL,false);
|
|
strncpy (getFileOut->publisherPhoto,PhotoURL,PATH_MAX);
|
|
getFileOut->publisherPhoto[PATH_MAX] = '\0';
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**************************** Get info of my marks ***************************/
|
|
/*****************************************************************************/
|
|
|
|
int swad__getMarks (struct soap *soap,
|
|
char *wsKey,int fileCode, // input
|
|
struct swad__getMarksOutput *getMarksOut) // output
|
|
{
|
|
int ReturnCode;
|
|
struct FileMetadata FileMetadata;
|
|
char SummaryStr[NAME_MAX+1]; // Really not used
|
|
char *ContentStr;
|
|
|
|
Gbl.soap = soap;
|
|
Gbl.WebService.Function = Svc_getMarks;
|
|
getMarksOut->content = NULL;
|
|
|
|
/***** Check web service key *****/
|
|
if ((ReturnCode = Svc_CheckWSKey (wsKey)) != SOAP_OK)
|
|
return ReturnCode;
|
|
if (Gbl.Usrs.Me.UsrDat.UsrCod < 0) // Web service key does not exist in database
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad web service key",
|
|
"Web service key does not exist in database");
|
|
|
|
/***** Get file metadata *****/
|
|
FileMetadata.FilCod = (long) fileCode;
|
|
Brw_GetFileMetadataByCod (&FileMetadata);
|
|
|
|
if (FileMetadata.FileType != Brw_IS_FILE ||
|
|
FileMetadata.IsHidden ||
|
|
(FileMetadata.FileBrowser != Brw_ADMI_MARKS_CRS &&
|
|
FileMetadata.FileBrowser != Brw_ADMI_MARKS_GRP))
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Bad file code",
|
|
"You can not get marks from this file");
|
|
|
|
/***** Set course and group codes *****/
|
|
Brw_GetCrsGrpFromFileMetadata (FileMetadata.FileBrowser,FileMetadata.Cod,
|
|
&Gbl.CurrentCrs.Crs.CrsCod,
|
|
&Gbl.CurrentCrs.Grps.GrpCod);
|
|
|
|
/***** Check course and group codes *****/
|
|
if ((ReturnCode = Svc_CheckCourseAndGroupCodes (Gbl.CurrentCrs.Crs.CrsCod,Gbl.CurrentCrs.Grps.GrpCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
|
|
/***** Get some of my data *****/
|
|
if ((ReturnCode = Svc_GetSomeUsrDataFromUsrCod (&Gbl.Usrs.Me.UsrDat,Gbl.CurrentCrs.Crs.CrsCod)) != SOAP_OK)
|
|
return ReturnCode;
|
|
Gbl.Usrs.Me.Logged = true;
|
|
Gbl.Usrs.Me.LoggedRole = Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB;
|
|
|
|
/***** Check if I am a student or teacher in the course *****/
|
|
if (Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_STUDENT &&
|
|
Gbl.Usrs.Me.UsrDat.RoleInCurrentCrsDB != Rol_TEACHER)
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to course");
|
|
|
|
/***** Check if I belong to group *****/
|
|
if (Gbl.CurrentCrs.Grps.GrpCod > 0)
|
|
if (!Grp_GetIfIBelongToGrp (Gbl.CurrentCrs.Grps.GrpCod))
|
|
return soap_receiver_fault (Gbl.soap,
|
|
"Request forbidden",
|
|
"Requester must belong to group");
|
|
|
|
/***** Get content *****/
|
|
ContentStr = NULL;
|
|
Mrk_GetNotifMyMarks (SummaryStr,&ContentStr,
|
|
FileMetadata.FilCod,Gbl.Usrs.Me.UsrDat.UsrCod,
|
|
0,true);
|
|
if (ContentStr != NULL)
|
|
{
|
|
getMarksOut->content = (char *) soap_malloc (Gbl.soap,strlen (ContentStr)+1);
|
|
|
|
strcpy (getMarksOut->content,ContentStr);
|
|
|
|
free ((void *) ContentStr);
|
|
ContentStr = NULL;
|
|
}
|
|
else
|
|
{
|
|
getMarksOut->content = (char *) soap_malloc (Gbl.soap,1);
|
|
getMarksOut->content[0] = '\0';
|
|
}
|
|
|
|
return SOAP_OK;
|
|
}
|