mirror of
https://github.com/acanas/swad-core.git
synced 2024-09-22 00:00:40 +02:00
592 lines
24 KiB
C
592 lines
24 KiB
C
// swad_import.c: import courses and students from another web application using web services
|
|
|
|
/*
|
|
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-2014 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/>.
|
|
*/
|
|
/*****************************************************************************/
|
|
/********************************* Headers ***********************************/
|
|
/*****************************************************************************/
|
|
|
|
#include <linux/limits.h> // For PATH_MAX
|
|
#include <linux/stddef.h> // For NULL
|
|
#include <stdlib.h> // For exit, system, malloc, free, rand, etc.
|
|
#include <string.h> // For string functions
|
|
#include <sys/wait.h> // For the macro WEXITSTATUS
|
|
#include <unistd.h> // For unlink
|
|
|
|
#include "swad_config.h"
|
|
#include "swad_database.h"
|
|
#include "swad_global.h"
|
|
#include "swad_ID.h"
|
|
#include "swad_import.h"
|
|
#include "swad_parameter.h"
|
|
#include "swad_user.h"
|
|
|
|
/*****************************************************************************/
|
|
/************** External global variables from others modules ****************/
|
|
/*****************************************************************************/
|
|
|
|
extern struct Globals Gbl;
|
|
extern const char *Usr_StringsSexDB[Usr_NUM_SEXS];
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private constants *****************************/
|
|
/*****************************************************************************/
|
|
|
|
#define Imp_OK 0
|
|
#define Imp_ERROR_BAD_SESSION 1
|
|
#define Imp_ERROR_NOT_ENOUGH_MEMORY 2
|
|
#define Imp_ERROR_SOAP 3
|
|
|
|
#define Imp_MAX_BYTES_USR_ID 16
|
|
#define Imp_MAX_BYTES_NAME 32
|
|
#define Imp_MAX_BYTES_EMAIL 127
|
|
|
|
/*****************************************************************************/
|
|
/******************************* Private types *******************************/
|
|
/*****************************************************************************/
|
|
|
|
struct ImportedStudent
|
|
{
|
|
char ExternalUsrID[Imp_MAX_BYTES_USR_ID+1];
|
|
char FirstName[Imp_MAX_BYTES_NAME+1];
|
|
char Surname1[Imp_MAX_BYTES_NAME+1];
|
|
char Surname2[Imp_MAX_BYTES_NAME+1];
|
|
char Email[Imp_MAX_BYTES_EMAIL+1];
|
|
Usr_Sex_t Sex;
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/***************************** Private prototypes ****************************/
|
|
/*****************************************************************************/
|
|
|
|
static void Imp_ListMyImpGrpsAndStds (bool ItsAFormToRegRemStds);
|
|
static void Imp_RemoveOldImpSessions (void);
|
|
static void Imp_RemoveOldImpStdsAndGrps (void);
|
|
static unsigned Imp_GetAndListImpGrpsAndStdsFromDB (bool ItsAFormToRegRemStds);
|
|
|
|
/*****************************************************************************/
|
|
/************** Get parameters with imported user and session ****************/
|
|
/*****************************************************************************/
|
|
|
|
void Imp_GetImpUsrAndSession (void)
|
|
{
|
|
Gbl.Imported.ExternalUsrId[0] = '\0';
|
|
if (Cfg_NAME_PARAM_IMPORTED_USR_ID[0])
|
|
Par_GetParToText (Cfg_NAME_PARAM_IMPORTED_USR_ID,Gbl.Imported.ExternalUsrId,Cfg_MAX_LENGTH_IMPORTED_USR_ID);
|
|
|
|
Gbl.Imported.ExternalSesId[0] = '\0';
|
|
if (Cfg_NAME_PARAM_IMPORTED_SESSION_ID[0])
|
|
Par_GetParToText (Cfg_NAME_PARAM_IMPORTED_SESSION_ID,Gbl.Imported.ExternalSesId,Cfg_MAX_LENGTH_IMPORTED_SESSION_ID);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/********** Import the students of an official group from database ***********/
|
|
/*****************************************************************************/
|
|
|
|
void Imp_ImportStdsFromAnImpGrp (long ImpGrpCod,struct ListCodGrps *LstGrps,unsigned *NumUsrsRegistered)
|
|
{
|
|
char Query[1024];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned NumStds;
|
|
unsigned NumStd;
|
|
struct ImportedStudent ImpStd;
|
|
Usr_Sex_t Sex;
|
|
struct UsrData UsrDat;
|
|
struct ListUsrCods ListUsrCodsForThisID;
|
|
unsigned NumUsrFoundForThisID;
|
|
|
|
/***** Get official data of the imported students belonging to this group from database *****/
|
|
sprintf (Query,"SELECT UsrID,Surname1,Surname2,FirstName,Sex,E_mail"
|
|
" FROM imported_students WHERE GrpCod='%ld'"
|
|
" ORDER BY Surname1,Surname2,FirstName,UsrID",
|
|
ImpGrpCod);
|
|
NumStds = (unsigned) DB_QuerySELECT (Query,&mysql_res,"can not get imported students");
|
|
|
|
if (NumStds)
|
|
{
|
|
/***** Initialize structure with user's data *****/
|
|
Usr_UsrDataConstructor (&UsrDat);
|
|
|
|
/***** Import the students from this official group *****/
|
|
for (NumStd = 0;
|
|
NumStd < NumStds;
|
|
NumStd++) // For each student inside the official group...
|
|
{
|
|
/* Get official data of the student */
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/* Get user's ID (row[0]) */
|
|
strncpy (ImpStd.ExternalUsrID,row[0],Imp_MAX_BYTES_USR_ID);
|
|
ImpStd.ExternalUsrID[Imp_MAX_BYTES_USR_ID] = '\0';
|
|
// Users' IDs are always stored internally in capitals and without leading zeros
|
|
Str_RemoveLeadingZeros (ImpStd.ExternalUsrID);
|
|
Str_ConvertToUpperText (ImpStd.ExternalUsrID);
|
|
|
|
if (ID_CheckIfUsrIDIsValid (ImpStd.ExternalUsrID)) // If it's not a valid user's ID, skip it
|
|
{
|
|
/* Get Surname1 (row[1]) */
|
|
strncpy (ImpStd.Surname1,row[1],Imp_MAX_BYTES_NAME);
|
|
ImpStd.Surname1[Imp_MAX_BYTES_NAME] = '\0';
|
|
|
|
/* Get Surname2 (row[2]) */
|
|
strncpy (ImpStd.Surname2,row[2],Imp_MAX_BYTES_NAME);
|
|
ImpStd.Surname2[Imp_MAX_BYTES_NAME] = '\0';
|
|
|
|
/* Get FirstName (row[3]) */
|
|
strncpy (ImpStd.FirstName,row[3],Imp_MAX_BYTES_NAME);
|
|
ImpStd.FirstName[Imp_MAX_BYTES_NAME] = '\0';
|
|
|
|
/* Get Sex (row[4]) */
|
|
ImpStd.Sex = Usr_SEX_UNKNOWN;
|
|
for (Sex = (Usr_Sex_t) 0;
|
|
Sex < Usr_NUM_SEXS;
|
|
Sex++)
|
|
if (!strcasecmp (row[4],Usr_StringsSexDB[Sex]))
|
|
{
|
|
ImpStd.Sex = Sex;
|
|
break;
|
|
}
|
|
|
|
/* Get e-mail (row[5]) */
|
|
strncpy (ImpStd.Email,row[5],Imp_MAX_BYTES_EMAIL);
|
|
ImpStd.Email[Imp_MAX_BYTES_EMAIL] = '\0';
|
|
|
|
/* Set ID of the student */
|
|
ID_ReallocateListIDs (&UsrDat,1);
|
|
strncpy (UsrDat.IDs.List[0].ID,ImpStd.ExternalUsrID,ID_MAX_LENGTH_USR_ID);
|
|
UsrDat.IDs.List[0].ID[ID_MAX_LENGTH_USR_ID] = '\0';
|
|
|
|
if (ID_GetListUsrCodsFromUsrID (&UsrDat,NULL,&ListUsrCodsForThisID,false))
|
|
{// User(s) found
|
|
for (NumUsrFoundForThisID = 0;
|
|
NumUsrFoundForThisID < ListUsrCodsForThisID.NumUsrs;
|
|
NumUsrFoundForThisID++)
|
|
{
|
|
/* Get user's data */
|
|
UsrDat.UsrCod = ListUsrCodsForThisID.Lst[NumUsrFoundForThisID];
|
|
Usr_GetUsrDataFromUsrCod (&UsrDat); // Get data of the first user in list
|
|
|
|
if (UsrDat.RoleInCurrentCrsDB <= Rol_ROLE_STUDENT)
|
|
{
|
|
/* Update user's data if only one user with this ID */
|
|
if (ListUsrCodsForThisID.NumUsrs == 1) // Only one user with this ID
|
|
{
|
|
/* Fill empty data */
|
|
if (!UsrDat.Surname1[0])
|
|
strcpy (UsrDat.Surname1,ImpStd.Surname1);
|
|
if (!UsrDat.Surname2[0])
|
|
strcpy (UsrDat.Surname2,ImpStd.Surname2);
|
|
if (!UsrDat.FirstName[0])
|
|
strcpy (UsrDat.FirstName,ImpStd.FirstName);
|
|
if (UsrDat.Sex == Usr_SEX_UNKNOWN)
|
|
UsrDat.Sex = ImpStd.Sex;
|
|
|
|
/* Update user's data */
|
|
Usr_UpdateUsrData (&UsrDat);
|
|
|
|
/* Update e-mail */
|
|
if (!UsrDat.Email[0])
|
|
{
|
|
strcpy (UsrDat.Email,ImpStd.Email);
|
|
if (!Mai_UpdateEmailInDB (&UsrDat,UsrDat.Email)) // Email was already registered and confirmed by another user
|
|
UsrDat.Email[0] = '\0';
|
|
}
|
|
}
|
|
|
|
if (UsrDat.RoleInCurrentCrsDB == Rol_ROLE_STUDENT) // He/she was already a student in current course
|
|
Usr_AcceptUsrInCrs (UsrDat.UsrCod);
|
|
else // He/she not belonged to the current course
|
|
/* Register user as student in the current course */
|
|
Usr_RegisterUsrInCurrentCrs (&UsrDat,Rol_ROLE_STUDENT,
|
|
Cns_QUIET,Usr_SET_ACCEPTED_TO_TRUE);
|
|
|
|
/* Register user in the selected groups */
|
|
if (Gbl.CurrentCrs.Grps.NumGrps) // If there are groups in current course
|
|
Grp_RegisterUsrIntoGroups (&UsrDat,LstGrps); // Register student in the selected groups
|
|
|
|
/* Confirm user's ID */
|
|
ID_ConfirmUsrID (UsrDat.UsrCod,ImpStd.ExternalUsrID);
|
|
|
|
(*NumUsrsRegistered)++;
|
|
}
|
|
}
|
|
|
|
/* Free memory used for list of users' codes found for this ID */
|
|
Usr_FreeListUsrCods (&ListUsrCodsForThisID);
|
|
}
|
|
else // No users found with this ID
|
|
{// The user does not exist in the platform. Register him/her in the current course as student
|
|
Usr_ResetUsrDataExceptUsrCodAndIDs (&UsrDat);
|
|
strcpy (UsrDat.Surname1,ImpStd.Surname1);
|
|
strcpy (UsrDat.Surname2,ImpStd.Surname2);
|
|
strcpy (UsrDat.FirstName,ImpStd.FirstName);
|
|
UsrDat.Sex = ImpStd.Sex;
|
|
strcpy (UsrDat.Email,ImpStd.Email);
|
|
|
|
/* Create user */
|
|
UsrDat.IDs.List[0].Confirmed = true; // If he/she is a new user ==> his/her ID will be stored as confirmed in database
|
|
Usr_CreateNewUsr (&UsrDat);
|
|
|
|
/* Update e-mail */
|
|
if (!Mai_UpdateEmailInDB (&UsrDat,UsrDat.Email)) // Email was already registered and confirmed by another user
|
|
UsrDat.Email[0] = '\0';
|
|
|
|
/* Register user as student in the current course */
|
|
Usr_RegisterUsrInCurrentCrs (&UsrDat,Rol_ROLE_STUDENT,
|
|
Cns_QUIET,Usr_SET_ACCEPTED_TO_TRUE);
|
|
|
|
/* Register user in the selected groups */
|
|
if (Gbl.CurrentCrs.Grps.NumGrps) // If there are groups in current course
|
|
Grp_RegisterUsrIntoGroups (&UsrDat,LstGrps); // Register student in the selected groups
|
|
|
|
(*NumUsrsRegistered)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***** Free memory used for user's data *****/
|
|
Usr_UsrDataDestructor (&UsrDat);
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*************** Insert new imported session in the database *****************/
|
|
/*****************************************************************************/
|
|
|
|
void Imp_InsertImpSessionInDB (void)
|
|
{
|
|
char Query[1024];
|
|
|
|
/***** Remove old imported sessions *****/
|
|
Imp_RemoveOldImpSessions ();
|
|
|
|
/***** Insert session in the database *****/
|
|
sprintf (Query,"INSERT INTO imported_sessions"
|
|
" (SessionId,UsrCod,ImportedUsrId,ImportedSessionId,ImportedRole)"
|
|
" VALUES ('%s','%ld','%s','%s','%u')",
|
|
Gbl.Session.Id,
|
|
Gbl.Usrs.Me.UsrDat.UsrCod,
|
|
Gbl.Imported.ExternalUsrId,
|
|
Gbl.Imported.ExternalSesId,
|
|
(unsigned) Gbl.Imported.ExternalRole);
|
|
DB_QueryINSERT (Query,"can not create imported session");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******************** Get the data of a imported session *********************/
|
|
/*****************************************************************************/
|
|
|
|
bool Imp_GetImpSessionData (void)
|
|
{
|
|
char Query[512];
|
|
MYSQL_RES *mysql_res;
|
|
MYSQL_ROW row;
|
|
unsigned long NumRows;
|
|
bool Result = false;
|
|
|
|
/***** Get data of the imported session from database *****/
|
|
sprintf (Query,"SELECT ImportedUsrId,ImportedSessionId,ImportedRole"
|
|
" FROM imported_sessions"
|
|
" WHERE SessionId='%s'",
|
|
Gbl.Session.Id);
|
|
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get imported session data");
|
|
|
|
/***** Check if the session existed in the database *****/
|
|
if (NumRows)
|
|
{
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
/***** Get imported user identifier (row[0]) *****/
|
|
strcpy (Gbl.Imported.ExternalUsrId,row[0]);
|
|
|
|
/***** Get imported session identifier (row[1]) *****/
|
|
strcpy (Gbl.Imported.ExternalSesId,row[1]);
|
|
|
|
/***** Get imported user's (external) role (row[2]) *****/
|
|
if (sscanf (row[2],"%u",&Gbl.Imported.ExternalRole) != 1)
|
|
Gbl.Imported.ExternalRole = Rol_ROLE_UNKNOWN;
|
|
|
|
Result = true;
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
return Result;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************* Get lists of my imported groups and students ******************/
|
|
/*****************************************************************************/
|
|
|
|
void Imp_ListMyImpGrpsAndStdsNoForm (void)
|
|
{
|
|
Imp_ListMyImpGrpsAndStds (false);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************* Get lists of my imported groups and students ******************/
|
|
/*****************************************************************************/
|
|
|
|
void Imp_ListMyImpGrpsAndStdsForm (void)
|
|
{
|
|
Imp_ListMyImpGrpsAndStds (true);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/************* Get lists of my imported groups and students ******************/
|
|
/*****************************************************************************/
|
|
|
|
static void Imp_ListMyImpGrpsAndStds (bool ItsAFormToRegRemStds)
|
|
{
|
|
extern const char *Txt_There_is_no_external_service_for_authentication_and_official_lists;
|
|
extern const char *Txt_Could_not_get_the_official_list_of_your_groups_and_students_;
|
|
extern const char *Txt_To_get_the_official_list_of_your_groups_and_students_;
|
|
char PathRelParamsToCommandsPriv[PATH_MAX+1];
|
|
char FileNameParams[PATH_MAX+1];
|
|
FILE *FileParams;
|
|
char Command[2048];
|
|
int ReturnCode;
|
|
|
|
if (Cfg_EXTERNAL_LOGIN_CLIENT_COMMAND[0] == '\0')
|
|
Lay_ShowAlert (Lay_WARNING,Txt_There_is_no_external_service_for_authentication_and_official_lists);
|
|
/***** Try to get lists from database *****/
|
|
else if (!Imp_GetAndListImpGrpsAndStdsFromDB (ItsAFormToRegRemStds))
|
|
{
|
|
/***** Remove old imported students and groups *****/
|
|
Imp_RemoveOldImpStdsAndGrps ();
|
|
|
|
if (Gbl.Imported.ExternalUsrId[0] &&
|
|
Gbl.Imported.ExternalSesId[0] &&
|
|
Gbl.Imported.ExternalRole == Rol_ROLE_TEACHER)
|
|
{
|
|
/***** Parameters to command used to import data are passed through a temporary file *****/
|
|
/* If the private directory does not exist, create it */
|
|
sprintf (PathRelParamsToCommandsPriv,"%s/%s",
|
|
Cfg_PATH_SWAD_PRIVATE,Cfg_FOLDER_PARAM);
|
|
Fil_CreateDirIfNotExists (PathRelParamsToCommandsPriv);
|
|
|
|
/* First of all, we remove the oldest temporary files.
|
|
Such temporary files have been created by me or by other users.
|
|
This is a bit sloppy, but they must be removed by someone.
|
|
Here "oldest" means more than x time from their creation */
|
|
Fil_RemoveOldTmpFiles (PathRelParamsToCommandsPriv,Cfg_TIME_TO_DELETE_PARAMS_TO_COMMANDS,false);
|
|
|
|
/****** Create a new temporary file *****/
|
|
sprintf (FileNameParams,"%s/%s",PathRelParamsToCommandsPriv,Gbl.UniqueNameEncrypted);
|
|
if ((FileParams = fopen (FileNameParams,"wb")) == NULL)
|
|
Lay_ShowErrorAndExit ("Can not open file to send parameters to command.");
|
|
fprintf (FileParams,"2\n%s\n%s\n%s\n",
|
|
Gbl.Session.Id,Gbl.Imported.ExternalUsrId,Gbl.Imported.ExternalSesId);
|
|
fclose (FileParams);
|
|
|
|
/***** Get new imported lists and store them in database *****/
|
|
sprintf (Command,"%s %s",Cfg_EXTERNAL_LOGIN_CLIENT_COMMAND,FileNameParams);
|
|
ReturnCode = system (Command);
|
|
// unlink (FileNameParams); // File with parameters is no longer necessary
|
|
if (ReturnCode == -1)
|
|
Lay_ShowErrorAndExit ("Error when running command to import lists of groups and students.");
|
|
|
|
/***** Write message depending on return code *****/
|
|
ReturnCode = WEXITSTATUS(ReturnCode);
|
|
|
|
switch (ReturnCode)
|
|
{
|
|
case 0: // Success
|
|
/***** Try again to get lists from database *****/
|
|
if (!Imp_GetAndListImpGrpsAndStdsFromDB (ItsAFormToRegRemStds))
|
|
{
|
|
sprintf (Gbl.Message,Txt_Could_not_get_the_official_list_of_your_groups_and_students_,
|
|
Cfg_PLATFORM_SHORT_NAME,
|
|
Cfg_EXTERNAL_LOGIN_URL,
|
|
Cfg_EXTERNAL_LOGIN_SERVICE_FULL_NAME);
|
|
Lay_ShowAlert (Lay_ERROR,Gbl.Message);
|
|
}
|
|
break;
|
|
default: // Error
|
|
sprintf (Gbl.Message,"Error %d while importing lists of groups and students.",ReturnCode);
|
|
Lay_ShowAlert (Lay_ERROR,Gbl.Message);
|
|
break;
|
|
}
|
|
}
|
|
else // I am not entered from external program as teacher
|
|
{
|
|
sprintf (Gbl.Message,Txt_To_get_the_official_list_of_your_groups_and_students_,
|
|
Cfg_PLATFORM_SHORT_NAME,
|
|
Cfg_EXTERNAL_LOGIN_URL,
|
|
Cfg_EXTERNAL_LOGIN_SERVICE_FULL_NAME);
|
|
Lay_ShowAlert (Lay_WARNING,Gbl.Message);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/*********************** Remove old imported sessions ************************/
|
|
/*****************************************************************************/
|
|
|
|
static void Imp_RemoveOldImpSessions (void)
|
|
{
|
|
char Query[1024];
|
|
|
|
/***** Remove old imported sessions *****/
|
|
sprintf (Query,"DELETE FROM imported_sessions"
|
|
" WHERE SessionId NOT IN (SELECT SessionId FROM sessions)");
|
|
DB_QueryDELETE (Query,"can not remove old imported sessions");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/***************** Remove old imported students and groups *******************/
|
|
/*****************************************************************************/
|
|
|
|
static void Imp_RemoveOldImpStdsAndGrps (void)
|
|
{
|
|
char Query[1024];
|
|
|
|
/***** Remove old imported students *****/
|
|
sprintf (Query,"DELETE FROM imported_students"
|
|
" USING imported_groups,imported_students"
|
|
" WHERE imported_groups.SessionId NOT IN"
|
|
" (SELECT SessionId FROM sessions)"
|
|
" AND imported_groups.GrpCod=imported_students.GrpCod");
|
|
DB_QueryDELETE (Query,"can not remove old imported students");
|
|
|
|
/***** Remove old imported groups *****/
|
|
sprintf (Query,"DELETE FROM imported_groups"
|
|
" WHERE SessionId NOT IN"
|
|
" (SELECT SessionId FROM sessions)");
|
|
DB_QueryDELETE (Query,"can not remove old imported groups");
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/******** Get from database and list imported groups and students ************/
|
|
/*****************************************************************************/
|
|
|
|
static unsigned Imp_GetAndListImpGrpsAndStdsFromDB (bool ItsAFormToRegRemStds)
|
|
{
|
|
extern const char *Txt_Official_students;
|
|
extern const char *Txt_Group;
|
|
extern const char *Txt_ROLES_PLURAL_abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
|
|
char Query[1024];
|
|
MYSQL_RES *mysql_res_grp;
|
|
MYSQL_RES *mysql_res_std;
|
|
MYSQL_ROW row;
|
|
char ExternalCrsCod[Crs_LENGTH_INSTITUTIONAL_CRS_COD+1];
|
|
unsigned NumGrps,NumGrp;
|
|
long GrpCod;
|
|
unsigned NumStds,NumStd;
|
|
|
|
/***** Get data of imported groups from database *****/
|
|
sprintf (Query,"SELECT GrpCod,ExternalCrsCod,DegName,CrsName,GrpName,GrpType FROM imported_groups"
|
|
" WHERE SessionId='%s' ORDER BY DegName,CrsName,GrpName,GrpType",
|
|
Gbl.Session.Id);
|
|
NumGrps = (unsigned) DB_QuerySELECT (Query,&mysql_res_grp,"can not get imported groups");
|
|
|
|
if (NumGrps)
|
|
{
|
|
/***** Start table with groups *****/
|
|
Lay_StartRoundFrameTable10 (NULL,2,NULL);
|
|
fprintf (Gbl.F.Out,"<tr>"
|
|
"<th colspan=\"%u\" align=\"center\" valign=\"top\" class=\"TIT_TBL\">",
|
|
ItsAFormToRegRemStds ? 3 :
|
|
2);
|
|
Lay_WriteTitle (Txt_Official_students);
|
|
fprintf (Gbl.F.Out,"</th>"
|
|
"</tr>");
|
|
|
|
/***** Get groups and write them *****/
|
|
for (NumGrp = 0;
|
|
NumGrp < NumGrps;
|
|
NumGrp++) // For each course
|
|
{
|
|
row = mysql_fetch_row (mysql_res_grp);
|
|
|
|
GrpCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
strncpy (ExternalCrsCod,row[1],Crs_LENGTH_INSTITUTIONAL_CRS_COD);
|
|
ExternalCrsCod[Crs_LENGTH_INSTITUTIONAL_CRS_COD] = '\0';
|
|
|
|
/***** Get data of the imported students belonging to this group from database *****/
|
|
sprintf (Query,"SELECT UsrID,Surname1,Surname2,FirstName"
|
|
" FROM imported_students"
|
|
" WHERE GrpCod='%ld' ORDER BY Surname1,Surname2,FirstName,UsrID",
|
|
GrpCod);
|
|
NumStds = (unsigned) DB_QuerySELECT (Query,&mysql_res_std,"can not get imported students");
|
|
|
|
fprintf (Gbl.F.Out,"<tr>");
|
|
if (ItsAFormToRegRemStds)
|
|
/* Put checkbox to select the group */
|
|
fprintf (Gbl.F.Out,"<td rowspan=\"2\" align=\"left\" valign=\"top\">"
|
|
"<input type=\"checkbox\" name=\"ImpGrpCod\" value=\"%ld_%s\" />"
|
|
"</td>",
|
|
GrpCod,ExternalCrsCod);
|
|
|
|
/* Write degree, course and group */
|
|
fprintf (Gbl.F.Out,"<td colspan=\"2\" align=\"left\" valign=\"top\" class=\"TIT_TBL\">%s<br />%s %s<br />%s %s (%s)</td>" \
|
|
"</tr>",
|
|
row[2],
|
|
ExternalCrsCod,row[3],
|
|
Txt_Group,row[4],row[5]);
|
|
|
|
/* Write students */
|
|
fprintf (Gbl.F.Out,"<tr>" \
|
|
"<td align=\"left\" valign=\"top\" class=\"DAT\">%u %s%s</td>" \
|
|
"<td align=\"left\" valign=\"top\" class=\"DAT\">",
|
|
NumStds,Txt_ROLES_PLURAL_abc[Rol_ROLE_STUDENT][Usr_SEX_UNKNOWN],
|
|
NumStds ? ":" :
|
|
"");
|
|
if (NumStds)
|
|
{
|
|
fprintf (Gbl.F.Out,"<textarea cols=\"60\" rows=\"%u\" readonly>",
|
|
NumStds > 50 ? NumStds / 10 :
|
|
5);
|
|
for (NumStd = 0;
|
|
NumStd < NumStds;
|
|
NumStd++) // For each student inside the group
|
|
{
|
|
row = mysql_fetch_row (mysql_res_std);
|
|
fprintf (Gbl.F.Out,"%s %s",row[0],row[1]); // User's ID and Surname 1
|
|
if (row[2][0])
|
|
fprintf (Gbl.F.Out," %s",row[2]); // Surname 2
|
|
fprintf (Gbl.F.Out,", %s\n",row[3]); // First name
|
|
}
|
|
fprintf (Gbl.F.Out,"</textarea>");
|
|
}
|
|
fprintf (Gbl.F.Out,"</td>" \
|
|
"</tr>");
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res_std);
|
|
}
|
|
|
|
/***** End of table with courses *****/
|
|
Lay_EndRoundFrameTable10 ();
|
|
}
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
DB_FreeMySQLResult (&mysql_res_grp);
|
|
|
|
return NumGrps;
|
|
}
|