swad-core/swad_group.c

5106 lines
190 KiB
C
Raw Normal View History

2014-12-01 23:55:08 +01:00
// swad_group.c: types of groups and groups
/*
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.
2020-01-01 14:53:57 +01:00
Copyright (C) 1999-2020 Antonio Ca<EFBFBD>as Vargas
2014-12-01 23:55:08 +01:00
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 *********************************/
/*****************************************************************************/
2018-10-22 09:51:37 +02:00
#define _GNU_SOURCE // For asprintf
2019-12-29 12:39:00 +01:00
#include <stddef.h> // For NULL
2018-10-22 09:51:37 +02:00
#include <stdio.h> // For asprintf
2014-12-01 23:55:08 +01:00
#include <stdlib.h> // For exit, system, malloc, free, rand, etc.
#include <string.h> // For string functions
#include "swad_action.h"
2020-04-14 17:15:17 +02:00
#include "swad_attendance.h"
2017-06-10 21:38:10 +02:00
#include "swad_box.h"
2014-12-01 23:55:08 +01:00
#include "swad_database.h"
2020-05-06 01:43:48 +02:00
#include "swad_exam_event.h"
2018-11-09 20:47:39 +01:00
#include "swad_form.h"
2017-09-07 18:38:18 +02:00
#include "swad_game.h"
2014-12-01 23:55:08 +01:00
#include "swad_global.h"
#include "swad_group.h"
2019-10-23 19:05:05 +02:00
#include "swad_HTML.h"
2019-09-28 02:31:42 +02:00
#include "swad_match.h"
2014-12-01 23:55:08 +01:00
#include "swad_notification.h"
#include "swad_parameter.h"
2020-02-26 00:26:07 +01:00
#include "swad_program.h"
2017-09-17 16:58:09 +02:00
#include "swad_project.h"
2019-03-26 11:53:21 +01:00
#include "swad_setting.h"
2020-04-14 17:15:17 +02:00
#include "swad_survey.h"
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2019-11-21 16:47:07 +01:00
/*************************** Private constants *******************************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2017-05-31 09:37:20 +02:00
#define Grp_GROUP_TYPES_SECTION_ID "grp_types"
2017-05-25 13:43:54 +02:00
#define Grp_NEW_GROUP_TYPE_SECTION_ID "new_grp_type"
#define Grp_GROUPS_SECTION_ID "grps"
2017-05-31 09:37:20 +02:00
#define Grp_NEW_GROUP_SECTION_ID "new_grp"
2017-04-29 15:29:58 +02:00
2017-06-04 18:18:54 +02:00
static const bool Grp_ICanChangeGrps[Rol_NUM_ROLES] =
{
2019-11-21 01:27:17 +01:00
[Rol_UNK ] = false,
[Rol_GST ] = false,
[Rol_USR ] = false,
[Rol_STD ] = true,
[Rol_NET ] = false,
[Rol_TCH ] = true,
[Rol_DEG_ADM] = false,
[Rol_CTR_ADM] = false,
[Rol_INS_ADM] = false,
[Rol_SYS_ADM] = true,
2017-06-04 18:18:54 +02:00
};
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2019-11-21 16:47:07 +01:00
/****************************** Private types ********************************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/*****************************************************************************/
/************* External global variables from others modules *****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
2019-11-21 16:47:07 +01:00
/************************** Private global variables *************************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/*****************************************************************************/
2019-11-21 16:47:07 +01:00
/***************************** Private prototypes ****************************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2019-03-09 20:12:44 +01:00
static void Grp_ReqEditGroupsInternal (Ale_AlertType_t AlertTypeGroupTypes,const char *AlertTextGroupTypes,
Ale_AlertType_t AlertTypeGroups,const char *AlertTextGroups);
2017-04-29 02:20:34 +02:00
static void Grp_ReqEditGroupsInternal0 (void);
2019-03-09 20:12:44 +01:00
static void Grp_ReqEditGroupsInternal1 (Ale_AlertType_t AlertTypeGroupTypes,
const char *AlertTextGroupTypes);
static void Grp_ReqEditGroupsInternal2 (Ale_AlertType_t AlertTypeGroups,
const char *AlertTextGroups);
2017-04-28 18:03:30 +02:00
2014-12-01 23:55:08 +01:00
static void Grp_EditGroupTypes (void);
2020-04-14 17:15:17 +02:00
static void Grp_EditGroups (const struct Roo_Rooms *Rooms);
2020-04-08 18:18:46 +02:00
static void Grp_PutIconsEditingGroups (__attribute__((unused)) void *Args);
2017-04-29 20:16:53 +02:00
static void Grp_PutIconToCreateNewGroup (void);
2017-01-19 20:55:31 +01:00
2017-07-02 18:53:35 +02:00
static void Grp_PutCheckboxAllGrps (Grp_WhichGroups_t GroupsSelectableByStdsOrNETs);
2017-05-30 19:42:10 +02:00
2018-10-22 10:12:41 +02:00
static void Grp_LockTables (void);
static void Grp_UnlockTables (void);
2014-12-01 23:55:08 +01:00
static void Grp_ConstructorListGrpAlreadySelec (struct ListGrpsAlreadySelec **AlreadyExistsGroupOfType);
static void Grp_DestructorListGrpAlreadySelec (struct ListGrpsAlreadySelec **AlreadyExistsGroupOfType);
static void Grp_RemoveUsrFromGroup (long UsrCod,long GrpCod);
static void Grp_AddUsrToGroup (struct UsrData *UsrDat,long GrpCod);
2017-04-29 19:32:06 +02:00
2014-12-01 23:55:08 +01:00
static void Grp_ListGroupTypesForEdition (void);
2020-04-08 18:18:46 +02:00
static void Grp_PutIconsEditingGroupTypes (__attribute__((unused)) void *Args);
2017-04-29 19:19:55 +02:00
static void Grp_PutIconToViewGroups (void);
static void Grp_PutIconToCreateNewGroupType (void);
2014-12-01 23:55:08 +01:00
static void Grp_WriteHeadingGroupTypes (void);
2017-04-29 19:32:06 +02:00
2020-04-14 17:15:17 +02:00
static void Grp_ListGroupsForEdition (const struct Roo_Rooms *Rooms);
2014-12-01 23:55:08 +01:00
static void Grp_WriteHeadingGroups (void);
2020-05-06 01:43:48 +02:00
static bool Grp_CheckIfAssociatedToGrp (const char *Table,const char *Field,
long Cod,long GrpCod);
2020-04-08 18:18:46 +02:00
static void Grp_PutIconToEditGroups (__attribute__((unused)) void *Args);
2014-12-01 23:55:08 +01:00
static void Grp_ShowWarningToStdsToChangeGrps (void);
2017-06-04 18:18:54 +02:00
static bool Grp_ListGrpsForChangeMySelection (struct GroupType *GrpTyp,
unsigned *NumGrpsThisTypeIBelong);
2014-12-01 23:55:08 +01:00
static void Grp_ListGrpsToAddOrRemUsrs (struct GroupType *GrpTyp,long UsrCod);
2017-06-23 09:56:01 +02:00
static void Grp_ListGrpsForMultipleSelection (struct GroupType *GrpTyp,
2017-07-02 18:53:35 +02:00
Grp_WhichGroups_t GroupsSelectableByStdsOrNETs);
2014-12-01 23:55:08 +01:00
static void Grp_WriteGrpHead (struct GroupType *GrpTyp);
static void Grp_WriteRowGrp (struct Group *Grp,bool Highlight);
static void Grp_PutFormToCreateGroupType (void);
2020-04-14 17:15:17 +02:00
static void Grp_PutFormToCreateGroup (const struct Roo_Rooms *Rooms);
2014-12-01 23:55:08 +01:00
static unsigned Grp_CountNumGrpsInThisCrsOfType (long GrpTypCod);
static void Grp_GetDataOfGroupTypeByCod (struct GroupType *GrpTyp);
2017-03-30 11:20:06 +02:00
static bool Grp_GetMultipleEnrolmentOfAGroupType (long GrpTypCod);
2014-12-01 23:55:08 +01:00
static long Grp_GetTypeOfGroupOfAGroup (long GrpCod);
2018-10-31 10:19:01 +01:00
static unsigned long Grp_CountNumUsrsInNoGrpsOfType (Rol_Role_t Role,long GrpTypCod);
2019-02-18 14:41:46 +01:00
static bool Grp_CheckIfIBelongToGrpsOfType (long GrpTypCod);
2014-12-01 23:55:08 +01:00
static void Grp_GetLstCodGrpsUsrBelongs (long CrsCod,long GrpTypCod,long UsrCod,
struct ListCodGrps *LstGrps);
static bool Grp_CheckIfGrpIsInList (long GrpCod,struct ListCodGrps *LstGrps);
2015-10-26 20:02:07 +01:00
static bool Grp_CheckIfOpenTimeInTheFuture (time_t OpenTimeUTC);
2014-12-01 23:55:08 +01:00
static bool Grp_CheckIfGroupTypeNameExists (const char *GrpTypName,long GrpTypCod);
static bool Grp_CheckIfGroupNameExists (long GrpTypCod,const char *GrpName,long GrpCod);
static void Grp_CreateGroupType (void);
static void Grp_CreateGroup (void);
2017-04-28 13:10:46 +02:00
2014-12-01 23:55:08 +01:00
static void Grp_AskConfirmRemGrpTypWithGrps (unsigned NumGrps);
2020-04-08 18:18:46 +02:00
static void Grp_PutParamRemGrpTyp (void *GrpTypCod);
2014-12-01 23:55:08 +01:00
static void Grp_AskConfirmRemGrp (void);
2020-04-08 18:18:46 +02:00
static void Grp_PutParamRemGrp (void *GrpCod);
2014-12-01 23:55:08 +01:00
static void Grp_RemoveGroupTypeCompletely (void);
static void Grp_RemoveGroupCompletely (void);
2017-04-28 13:10:46 +02:00
2019-11-08 01:10:32 +01:00
static void Grp_WriteMaxStds (char Str[Cns_MAX_DECIMAL_DIGITS_UINT + 1],unsigned MaxStudents);
2014-12-01 23:55:08 +01:00
static long Grp_GetParamGrpTypCod (void);
static long Grp_GetParamGrpCod (void);
static void Grp_PutParamGrpTypCod (long GrpTypCod);
/*****************************************************************************/
/******************* Write the names of the selected groups ******************/
/*****************************************************************************/
void Grp_WriteNamesOfSelectedGrps (void)
{
extern const char *Txt_Group;
extern const char *Txt_Groups;
2017-05-30 21:43:05 +02:00
extern const char *Txt_users_with_no_group;
2014-12-01 23:55:08 +01:00
extern const char *Txt_and;
long GrpCod;
unsigned NumGrpSel;
struct GroupData GrpDat;
/***** Show the selected groups *****/
2020-01-11 15:22:02 +01:00
HTM_TxtColonNBSP (Gbl.Crs.Grps.LstGrpsSel.NumGrps == 1 ? Txt_Group :
Txt_Groups);
2014-12-01 23:55:08 +01:00
for (NumGrpSel = 0;
2019-04-04 10:45:15 +02:00
NumGrpSel < Gbl.Crs.Grps.LstGrpsSel.NumGrps;
2014-12-01 23:55:08 +01:00
NumGrpSel++)
{
2019-04-04 10:45:15 +02:00
if ((GrpCod = Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrpSel]) >= 0)
2014-12-01 23:55:08 +01:00
{
GrpDat.GrpCod = GrpCod;
Grp_GetDataOfGroupByCod (&GrpDat);
2019-11-11 10:59:24 +01:00
HTM_TxtF ("%s&nbsp;%s",GrpDat.GrpTypName,GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
}
else // GrpCod < 0 ==> students not belonging to any group of type (-GrpCod)
{
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod = -GrpCod;
Grp_GetDataOfGroupTypeByCod (&Gbl.Crs.Grps.GrpTyp);
2019-11-11 10:59:24 +01:00
HTM_TxtF ("%s&nbsp;(%s)",Gbl.Crs.Grps.GrpTyp.GrpTypName,
Txt_users_with_no_group);
2014-12-01 23:55:08 +01:00
}
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps >= 2)
2014-12-01 23:55:08 +01:00
{
2019-04-04 10:45:15 +02:00
if (NumGrpSel == Gbl.Crs.Grps.LstGrpsSel.NumGrps-2)
2019-11-11 00:15:44 +01:00
HTM_TxtF (" %s ",Txt_and);
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps >= 3)
if (NumGrpSel < Gbl.Crs.Grps.LstGrpsSel.NumGrps-2)
2019-11-10 16:41:47 +01:00
HTM_Txt (", ");
2014-12-01 23:55:08 +01:00
}
}
}
/*****************************************************************************/
/************************** Put forms to edit groups *************************/
/*****************************************************************************/
void Grp_ReqEditGroups (void)
2017-04-29 20:42:10 +02:00
{
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
Ale_INFO,NULL);
2017-04-29 20:42:10 +02:00
}
2019-03-09 20:12:44 +01:00
static void Grp_ReqEditGroupsInternal (Ale_AlertType_t AlertTypeGroupTypes,
const char *AlertTextGroupTypes,
Ale_AlertType_t AlertTypeGroups,
const char *AlertTextGroups)
2017-04-28 18:03:30 +02:00
{
2017-04-29 02:20:34 +02:00
Grp_ReqEditGroupsInternal0 ();
2019-03-09 20:12:44 +01:00
Grp_ReqEditGroupsInternal1 (AlertTypeGroupTypes,AlertTextGroupTypes);
Grp_ReqEditGroupsInternal2 (AlertTypeGroups,AlertTextGroups);
2017-04-28 18:03:30 +02:00
}
2017-04-29 02:20:34 +02:00
static void Grp_ReqEditGroupsInternal0 (void)
2017-04-29 00:23:48 +02:00
{
2017-04-29 02:20:34 +02:00
/***** Start groups types section *****/
2019-10-26 01:56:36 +02:00
HTM_SECTION_Begin (Grp_GROUP_TYPES_SECTION_ID);
2017-04-29 00:23:48 +02:00
}
2019-03-09 20:12:44 +01:00
static void Grp_ReqEditGroupsInternal1 (Ale_AlertType_t AlertTypeGroupTypes,
const char *AlertTextGroupTypes)
2014-12-01 23:55:08 +01:00
{
/***** Get list of groups types and groups in this course *****/
Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ALL_GROUP_TYPES);
2017-04-29 02:20:34 +02:00
/***** Show optional alert *****/
2019-03-09 20:12:44 +01:00
if (AlertTextGroupTypes)
if (AlertTextGroupTypes[0])
Ale_ShowAlert (AlertTypeGroupTypes,AlertTextGroupTypes);
2017-04-28 18:03:30 +02:00
2017-04-29 02:20:34 +02:00
/***** Put form to edit group types *****/
2014-12-01 23:55:08 +01:00
Grp_EditGroupTypes ();
2017-04-29 02:20:34 +02:00
/***** End groups types section *****/
2019-10-26 01:56:36 +02:00
HTM_SECTION_End ();
2017-04-28 18:03:30 +02:00
2017-04-29 02:20:34 +02:00
/***** Start groups section *****/
2019-10-26 01:56:36 +02:00
HTM_SECTION_Begin (Grp_GROUPS_SECTION_ID);
2017-04-29 00:23:48 +02:00
}
2017-04-28 18:03:30 +02:00
2019-03-09 20:12:44 +01:00
static void Grp_ReqEditGroupsInternal2 (Ale_AlertType_t AlertTypeGroups,
const char *AlertTextGroups)
2017-04-29 00:23:48 +02:00
{
2020-04-14 17:15:17 +02:00
struct Roo_Rooms Rooms;
2020-04-14 11:08:23 +02:00
2020-04-14 17:15:17 +02:00
/***** Reset rooms context *****/
Roo_ResetRooms (&Rooms);
2020-04-14 11:08:23 +02:00
2017-04-29 02:20:34 +02:00
/***** Show optional alert *****/
2019-03-09 20:12:44 +01:00
if (AlertTextGroups)
if (AlertTextGroups[0])
Ale_ShowAlert (AlertTypeGroups,AlertTextGroups);
2017-04-29 02:20:34 +02:00
2020-04-14 17:15:17 +02:00
/***** Get list of rooms in this centre *****/
Roo_GetListRooms (&Rooms,Roo_ONLY_SHRT_NAME);
2020-04-14 11:08:23 +02:00
2017-04-29 02:20:34 +02:00
/***** Put form to edit groups *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpTypes.Num) // If there are group types...
2020-04-14 17:15:17 +02:00
Grp_EditGroups (&Rooms);
2014-12-01 23:55:08 +01:00
2017-04-29 02:20:34 +02:00
/***** End groups section *****/
2019-10-26 01:56:36 +02:00
HTM_SECTION_End ();
2017-04-29 02:20:34 +02:00
2020-04-14 17:15:17 +02:00
/***** Free list of rooms in this centre *****/
Roo_FreeListRooms (&Rooms);
2019-01-04 12:53:40 +01:00
2017-04-29 02:20:34 +02:00
/***** Free list of groups types and groups in this course *****/
Grp_FreeListGrpTypesAndGrps ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************* Put forms to edit group types *********************/
/*****************************************************************************/
static void Grp_EditGroupTypes (void)
{
2017-04-29 20:16:53 +02:00
extern const char *Hlp_USERS_Groups;
extern const char *Txt_Types_of_group;
2014-12-01 23:55:08 +01:00
extern const char *Txt_There_are_no_types_of_group_in_the_course_X;
2019-10-26 02:19:42 +02:00
/***** Begin box *****/
2020-03-26 02:54:30 +01:00
Box_BoxBegin (NULL,Txt_Types_of_group,
2020-04-08 18:18:46 +02:00
Grp_PutIconsEditingGroupTypes,NULL,
2017-06-12 15:03:29 +02:00
Hlp_USERS_Groups,Box_NOT_CLOSABLE);
2017-04-29 20:16:53 +02:00
2017-05-11 14:47:48 +02:00
/***** Put a form to create a new group type *****/
Grp_PutFormToCreateGroupType ();
2014-12-01 23:55:08 +01:00
/***** Forms to edit current group types *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpTypes.Num) // Group types found...
2014-12-01 23:55:08 +01:00
Grp_ListGroupTypesForEdition ();
else // No group types found in this course
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_INFO,Txt_There_are_no_types_of_group_in_the_course_X,
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.ShrtName);
2014-12-01 23:55:08 +01:00
2017-06-12 14:16:33 +02:00
/***** End box *****/
2019-10-25 22:48:34 +02:00
Box_BoxEnd ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************************** Put forms to edit groups ***********************/
/*****************************************************************************/
2020-04-14 17:15:17 +02:00
static void Grp_EditGroups (const struct Roo_Rooms *Rooms)
2014-12-01 23:55:08 +01:00
{
2017-04-29 20:16:53 +02:00
extern const char *Hlp_USERS_Groups;
extern const char *Txt_Groups;
2014-12-01 23:55:08 +01:00
extern const char *Txt_No_groups_have_been_created_in_the_course_X;
2019-10-26 02:19:42 +02:00
/***** Begin box *****/
2020-03-26 02:54:30 +01:00
Box_BoxBegin (NULL,Txt_Groups,
2020-04-08 18:18:46 +02:00
Grp_PutIconsEditingGroups,NULL,
2017-06-12 15:03:29 +02:00
Hlp_USERS_Groups,Box_NOT_CLOSABLE);
2017-04-29 20:16:53 +02:00
2017-05-11 14:47:48 +02:00
/***** Put a form to create a new group *****/
2020-04-14 17:15:17 +02:00
Grp_PutFormToCreateGroup (Rooms);
2017-05-11 14:47:48 +02:00
2014-12-01 23:55:08 +01:00
/***** Forms to edit current groups *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpTypes.NumGrpsTotal) // If there are groups...
2020-04-14 17:15:17 +02:00
Grp_ListGroupsForEdition (Rooms);
2014-12-01 23:55:08 +01:00
else // There are group types, but there aren't groups
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_INFO,Txt_No_groups_have_been_created_in_the_course_X,
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.ShrtName);
2014-12-01 23:55:08 +01:00
2017-06-12 14:16:33 +02:00
/***** End box *****/
2019-10-25 22:48:34 +02:00
Box_BoxEnd ();
2017-04-29 20:16:53 +02:00
}
/*****************************************************************************/
/**************** Put contextual icons in edition of groups ******************/
/*****************************************************************************/
2020-04-08 18:18:46 +02:00
static void Grp_PutIconsEditingGroups (__attribute__((unused)) void *Args)
2017-04-29 20:16:53 +02:00
{
2020-04-08 18:18:46 +02:00
/***** Put icon to view groups *****/
Grp_PutIconToViewGroups ();
2017-04-29 20:16:53 +02:00
2020-04-08 18:18:46 +02:00
/***** Put icon to create a new group *****/
Grp_PutIconToCreateNewGroup ();
2017-04-29 20:16:53 +02:00
}
static void Grp_PutIconToCreateNewGroup (void)
{
extern const char *Txt_New_group;
/***** Put form to create a new group *****/
2020-03-26 02:54:30 +01:00
Ico_PutContextualIconToAdd (ActReqEdiGrp,Grp_NEW_GROUP_SECTION_ID,
NULL,NULL,
2019-01-10 15:26:33 +01:00
Txt_New_group);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*************** Show form to select one or several groups *******************/
/*****************************************************************************/
2020-03-26 02:54:30 +01:00
void Grp_ShowFormToSelectSeveralGroups (void (*FuncParams) (void *Args),void *Args,
2017-07-02 18:53:35 +02:00
Grp_WhichGroups_t GroupsSelectableByStdsOrNETs)
2014-12-01 23:55:08 +01:00
{
2016-11-13 20:54:06 +01:00
extern const char *Hlp_USERS_Groups;
2019-11-19 00:17:23 +01:00
extern const char *The_ClassFormLinkInBoxBold[The_NUM_THEMES];
2015-04-11 14:27:18 +02:00
extern const char *Txt_Groups;
2017-05-30 18:24:26 +02:00
extern const char *Txt_Update_users;
2014-12-01 23:55:08 +01:00
unsigned NumGrpTyp;
2016-11-25 03:21:02 +01:00
bool ICanEdit;
2014-12-01 23:55:08 +01:00
2019-04-10 17:46:42 +02:00
/***** Trivial check: if no groups ==> nothing to do *****/
if (!Gbl.Crs.Grps.NumGrps)
return;
2016-11-25 03:21:02 +01:00
2019-10-26 02:19:42 +02:00
/***** Begin box *****/
2019-04-10 17:46:42 +02:00
ICanEdit = !Gbl.Form.Inside &&
(Gbl.Usrs.Me.Role.Logged == Rol_TCH ||
Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM);
2020-03-26 02:54:30 +01:00
if (ICanEdit)
Box_BoxBegin (NULL,Txt_Groups,
2020-04-08 18:18:46 +02:00
Grp_PutIconToEditGroups,NULL,
2020-03-26 02:54:30 +01:00
Hlp_USERS_Groups,Box_CLOSABLE);
else
Box_BoxBegin (NULL,Txt_Groups,
NULL,NULL,
Hlp_USERS_Groups,Box_CLOSABLE);
2016-11-25 03:21:02 +01:00
2019-10-20 22:00:28 +02:00
/***** Begin form to update the students listed
2019-04-10 17:46:42 +02:00
depending on the groups selected *****/
2019-04-11 14:45:31 +02:00
Frm_StartFormAnchor (Gbl.Action.Act, // Repeat current action
Usr_USER_LIST_SECTION_ID);
2019-04-10 17:46:42 +02:00
Usr_PutParamsPrefsAboutUsrList ();
2019-04-11 09:55:35 +02:00
if (FuncParams)
2020-03-26 02:54:30 +01:00
FuncParams (Args);
2016-11-25 03:21:02 +01:00
2019-04-10 17:46:42 +02:00
/***** Select all groups *****/
Grp_PutCheckboxAllGrps (GroupsSelectableByStdsOrNETs);
2016-11-25 03:21:02 +01:00
2019-04-10 17:46:42 +02:00
/***** Get list of groups types and groups in this course *****/
Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
2016-11-25 03:21:02 +01:00
2019-04-10 17:46:42 +02:00
/***** List the groups for each group type *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_BeginWidePadding (2);
2019-04-10 17:46:42 +02:00
for (NumGrpTyp = 0;
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
NumGrpTyp++)
if (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps)
Grp_ListGrpsForMultipleSelection (&Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp],
GroupsSelectableByStdsOrNETs);
2019-10-23 19:05:05 +02:00
HTM_TABLE_End ();
2016-11-25 03:21:02 +01:00
2019-04-10 17:46:42 +02:00
/***** Free list of groups types and groups in this course *****/
Grp_FreeListGrpTypesAndGrps ();
2016-11-25 03:21:02 +01:00
2019-04-10 17:46:42 +02:00
/***** Submit button *****/
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("class=\"CM\" style=\"padding-top:12px;\"");
2019-11-19 00:17:23 +01:00
HTM_BUTTON_Animated_Begin (Txt_Update_users,
The_ClassFormLinkInBoxBold[Gbl.Prefs.Theme],
Gbl.Action.Act == ActReqMsgUsr ? "CopyMessageToHiddenFields();" :
NULL);
2019-04-10 17:46:42 +02:00
Ico_PutCalculateIconWithText (Txt_Update_users);
2019-11-19 00:17:23 +01:00
HTM_BUTTON_End ();
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2016-11-25 03:21:02 +01:00
2019-04-10 17:46:42 +02:00
/***** End form *****/
Frm_EndForm ();
2016-11-25 03:21:02 +01:00
2019-04-10 17:46:42 +02:00
/***** End box *****/
2019-10-25 22:48:34 +02:00
Box_BoxEnd ();
2014-12-01 23:55:08 +01:00
}
2017-05-30 19:42:10 +02:00
/*****************************************************************************/
/******************* Put checkbox to select all groups ***********************/
/*****************************************************************************/
2017-07-02 18:53:35 +02:00
static void Grp_PutCheckboxAllGrps (Grp_WhichGroups_t GroupsSelectableByStdsOrNETs)
2017-05-30 19:42:10 +02:00
{
2019-02-22 21:47:50 +01:00
extern const char *The_ClassFormInBox[The_NUM_THEMES];
2017-05-30 19:42:10 +02:00
extern const char *Txt_All_groups;
2017-06-06 20:27:46 +02:00
bool ICanSelUnselGroup;
switch (Gbl.Usrs.Me.Role.Logged)
{
2017-07-02 18:53:35 +02:00
case Rol_STD:
2017-06-06 20:27:46 +02:00
case Rol_NET:
2017-07-02 18:53:35 +02:00
ICanSelUnselGroup = (GroupsSelectableByStdsOrNETs == Grp_ALL_GROUPS);
2017-06-06 20:27:46 +02:00
break;
case Rol_TCH:
case Rol_DEG_ADM:
case Rol_CTR_ADM:
case Rol_INS_ADM:
case Rol_SYS_ADM:
ICanSelUnselGroup = true;
break;
default:
ICanSelUnselGroup = false;
break;
}
2017-05-30 19:42:10 +02:00
2019-10-24 00:04:40 +02:00
HTM_DIV_Begin ("class=\"CONTEXT_OPT\"");
2019-11-04 20:41:35 +01:00
HTM_LABEL_Begin ("class=\"%s\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
2020-03-12 13:53:37 +01:00
HTM_INPUT_CHECKBOX ("AllGroups",HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-04 20:41:35 +01:00
"value=\"Y\"%s",
ICanSelUnselGroup ? (Gbl.Usrs.ClassPhoto.AllGroups ? " checked=\"checked\""
" onclick=\"togglecheckChildren(this,'GrpCods')\"" :
" onclick=\"togglecheckChildren(this,'GrpCods')\"") :
" disabled=\"disabled\"");
2019-11-11 10:59:24 +01:00
HTM_TxtF ("&nbsp;%s",Txt_All_groups);
2019-11-02 12:59:31 +01:00
HTM_LABEL_End ();
2019-10-23 20:07:56 +02:00
HTM_DIV_End ();
2017-05-30 19:42:10 +02:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/************ Put parameters with the groups of students selected ************/
/*****************************************************************************/
void Grp_PutParamsCodGrps (void)
{
2019-11-03 13:19:32 +01:00
extern const char *Par_SEPARATOR_PARAM_MULTIPLE;
2014-12-01 23:55:08 +01:00
unsigned NumGrpSel;
2019-11-03 13:19:32 +01:00
size_t MaxLengthGrpCods;
char *GrpCods;
2019-11-08 01:10:32 +01:00
char GrpCod[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2014-12-01 23:55:08 +01:00
/***** Write the boolean parameter that indicates if all the groups must be listed *****/
Par_PutHiddenParamChar ("AllGroups",
Gbl.Usrs.ClassPhoto.AllGroups ? 'Y' :
'N');
/***** Write the parameter with the list of group codes to show *****/
if (!Gbl.Usrs.ClassPhoto.AllGroups &&
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.LstGrpsSel.NumGrps)
2014-12-01 23:55:08 +01:00
{
2019-11-11 11:20:31 +01:00
MaxLengthGrpCods = Gbl.Crs.Grps.LstGrpsSel.NumGrps * (Cns_MAX_DECIMAL_DIGITS_LONG + 1) - 1;
2019-11-03 13:19:32 +01:00
if ((GrpCods = (char *) malloc (MaxLengthGrpCods + 1)) == NULL)
Lay_NotEnoughMemoryExit ();
2019-11-11 11:20:31 +01:00
GrpCods[0] = '\0';
2019-11-03 13:19:32 +01:00
2014-12-01 23:55:08 +01:00
for (NumGrpSel = 0;
2019-04-04 10:45:15 +02:00
NumGrpSel < Gbl.Crs.Grps.LstGrpsSel.NumGrps;
2014-12-01 23:55:08 +01:00
NumGrpSel++)
{
2019-11-03 13:19:32 +01:00
/* Append group code to list */
2014-12-01 23:55:08 +01:00
if (NumGrpSel)
2019-11-03 13:19:32 +01:00
Str_Concat (GrpCods,Par_SEPARATOR_PARAM_MULTIPLE,MaxLengthGrpCods);
snprintf (GrpCod,sizeof (GrpCod),
"%ld",
Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrpSel]);
Str_Concat (GrpCods,GrpCod,MaxLengthGrpCods);
2014-12-01 23:55:08 +01:00
}
2019-11-03 13:19:32 +01:00
Par_PutHiddenParamString (NULL,"GrpCods",GrpCods);
2019-11-06 19:45:20 +01:00
free (GrpCods);
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/**************** Get parameters related to groups selected ******************/
/*****************************************************************************/
void Grp_GetParCodsSeveralGrpsToShowUsrs (void)
{
struct ListCodGrps LstGrpsIBelong;
unsigned NumGrp;
2019-04-04 10:45:15 +02:00
if (++Gbl.Crs.Grps.LstGrpsSel.NestedCalls > 1) // If list is created yet, there's nothing to do
2014-12-01 23:55:08 +01:00
return;
/***** Get boolean parameter that indicates if all groups must be listed *****/
2017-01-28 20:32:50 +01:00
Gbl.Usrs.ClassPhoto.AllGroups = Par_GetParToBool ("AllGroups");
2014-12-01 23:55:08 +01:00
2017-01-19 20:55:31 +01:00
/***** Get parameter with list of groups selected *****/
Grp_GetParCodsSeveralGrps ();
2014-12-01 23:55:08 +01:00
2019-11-08 01:10:32 +01:00
if (Gbl.Crs.Grps.NumGrps && // This course has groups and...
2019-04-04 10:45:15 +02:00
!Gbl.Crs.Grps.LstGrpsSel.NumGrps) // ...I haven't selected any group
2017-01-19 20:55:31 +01:00
{
/***** I I haven't selected any group, show by default the groups I belong to *****/
/* Get list of groups of all types in current course I belong to */
2019-04-04 10:45:15 +02:00
Grp_GetLstCodGrpsUsrBelongs (Gbl.Hierarchy.Crs.CrsCod,-1L,
2017-01-19 20:55:31 +01:00
Gbl.Usrs.Me.UsrDat.UsrCod,&LstGrpsIBelong);
2014-12-01 23:55:08 +01:00
2017-01-19 20:55:31 +01:00
if (LstGrpsIBelong.NumGrps)
{
/* Allocate space for list of selected groups */
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.LstGrpsSel.GrpCods = (long *) calloc (LstGrpsIBelong.NumGrps,sizeof (long))) == NULL)
2018-10-18 20:06:54 +02:00
Lay_NotEnoughMemoryExit ();
2017-01-19 20:55:31 +01:00
/* Fill list of selected groups with list of groups I belong to */
for (NumGrp = 0;
NumGrp < LstGrpsIBelong.NumGrps;
NumGrp++)
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrp] = LstGrpsIBelong.GrpCods[NumGrp];
Gbl.Crs.Grps.LstGrpsSel.NumGrps = LstGrpsIBelong.NumGrps;
2017-01-19 20:55:31 +01:00
}
2014-12-01 23:55:08 +01:00
2017-01-19 20:55:31 +01:00
/* Free list of groups I belong to */
Grp_FreeListCodGrp (&LstGrpsIBelong);
2014-12-01 23:55:08 +01:00
}
/***** If no groups selected ==> show all groups *****/
2019-04-04 10:45:15 +02:00
if (!Gbl.Crs.Grps.LstGrpsSel.NumGrps)
2014-12-01 23:55:08 +01:00
Gbl.Usrs.ClassPhoto.AllGroups = true;
}
/*****************************************************************************/
2017-01-19 20:55:31 +01:00
/**************** Get parameter with list of groups selected *****************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2017-01-19 20:55:31 +01:00
void Grp_GetParCodsSeveralGrps (void)
2014-12-01 23:55:08 +01:00
{
2017-01-19 20:55:31 +01:00
char *ParamLstCodGrps;
2014-12-01 23:55:08 +01:00
const char *Ptr;
2019-11-08 01:10:32 +01:00
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2014-12-01 23:55:08 +01:00
unsigned NumGrp;
2019-11-08 01:10:32 +01:00
unsigned long MaxSizeLstGrpCods = ((Cns_MAX_DECIMAL_DIGITS_LONG + 1) * Gbl.Crs.Grps.NumGrps) - 1;
2014-12-01 23:55:08 +01:00
2017-01-19 20:55:31 +01:00
/***** Reset number of groups selected *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.LstGrpsSel.NumGrps = 0;
2014-12-01 23:55:08 +01:00
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.NumGrps) // If course has groups
2014-12-01 23:55:08 +01:00
{
2017-01-19 20:55:31 +01:00
/***** Allocate memory for the list of group codes selected *****/
if ((ParamLstCodGrps = (char *) malloc (MaxSizeLstGrpCods + 1)) == NULL)
2018-10-18 20:06:54 +02:00
Lay_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
/***** Get parameter with list of groups to list *****/
2017-01-19 20:55:31 +01:00
Par_GetParMultiToText ("GrpCods",ParamLstCodGrps,MaxSizeLstGrpCods);
2014-12-01 23:55:08 +01:00
2017-01-19 20:55:31 +01:00
if (ParamLstCodGrps[0])
{
/***** Count number of groups selected from LstCodGrps *****/
for (Ptr = ParamLstCodGrps, NumGrp = 0;
*Ptr;
NumGrp++)
2019-11-08 01:10:32 +01:00
Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.LstGrpsSel.NumGrps = NumGrp;
2017-01-19 20:55:31 +01:00
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.LstGrpsSel.NumGrps) // If I have selected groups...
2017-01-19 20:55:31 +01:00
{
/***** Create a list of groups selected from LstCodGrps *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.LstGrpsSel.GrpCods = (long *) calloc (Gbl.Crs.Grps.LstGrpsSel.NumGrps,sizeof (long))) == NULL)
2018-10-18 20:06:54 +02:00
Lay_NotEnoughMemoryExit ();
2017-01-19 20:55:31 +01:00
for (Ptr = ParamLstCodGrps, NumGrp = 0;
*Ptr;
NumGrp++)
{
2019-11-08 01:10:32 +01:00
Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrp] = Str_ConvertStrCodToLongCod (LongStr);
2017-01-19 20:55:31 +01:00
}
}
}
2014-12-01 23:55:08 +01:00
/***** Free memory used for the list of groups to show *****/
2019-11-06 19:45:20 +01:00
free (ParamLstCodGrps);
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/********* Free memory used for the list of group codes selected *************/
/*****************************************************************************/
void Grp_FreeListCodSelectedGrps (void)
{
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.LstGrpsSel.NestedCalls > 0)
if (--Gbl.Crs.Grps.LstGrpsSel.NestedCalls == 0)
if (Gbl.Crs.Grps.LstGrpsSel.GrpCods)
2014-12-01 23:55:08 +01:00
{
2019-11-06 19:45:20 +01:00
free (Gbl.Crs.Grps.LstGrpsSel.GrpCods);
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.LstGrpsSel.GrpCods = NULL;
Gbl.Crs.Grps.LstGrpsSel.NumGrps = 0;
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/******************* Change my groups and show form again ********************/
/*****************************************************************************/
void Grp_ChangeMyGrpsAndShowChanges (void)
{
/***** Change my groups *****/
2017-06-04 18:18:54 +02:00
Grp_ChangeMyGrps (Cns_VERBOSE);
2014-12-01 23:55:08 +01:00
/***** Show again the table of selection of groups with the changes already made *****/
Grp_ReqRegisterInGrps ();
}
/*****************************************************************************/
/****************************** Change my groups *****************************/
/*****************************************************************************/
2017-06-04 18:18:54 +02:00
void Grp_ChangeMyGrps (Cns_QuietOrVerbose_t QuietOrVerbose)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_The_requested_group_changes_were_successful;
extern const char *Txt_There_has_been_no_change_in_groups;
2017-03-30 11:20:06 +02:00
extern const char *Txt_In_a_type_of_group_with_single_enrolment_students_can_not_be_registered_in_more_than_one_group;
2014-12-01 23:55:08 +01:00
struct ListCodGrps LstGrpsIWant;
2017-06-20 01:58:16 +02:00
bool MySelectionIsValid;
2017-06-04 18:18:54 +02:00
bool ChangesMade;
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** Can I change my groups? *****/
if (Grp_ICanChangeGrps[Gbl.Usrs.Me.Role.Logged])
{
/***** Get list of groups types and groups in this course *****/
Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** Get the group codes which I want to join to *****/
LstGrpsIWant.GrpCods = NULL; // Initialized to avoid bug reported by Coverity
2017-06-20 01:58:16 +02:00
LstGrpsIWant.NumGrps = 0; // Initialized to avoid bug reported by Coverity
2017-06-04 18:18:54 +02:00
Grp_GetLstCodsGrpWanted (&LstGrpsIWant);
/***** A student can not be enroled in more than one group
if the type of group is of single enrolment *****/
// As the form to register in groups of single enrolment...
// ...is a radio-based form and not a checkbox-based form...
// ...this check is made only to avoid problems...
// ...if the student manipulates the form
2017-06-20 01:58:16 +02:00
MySelectionIsValid = Grp_CheckIfSelectionGrpsSingleEnrolmentIsValid (Gbl.Usrs.Me.Role.Logged,&LstGrpsIWant);
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** Free list of groups types and groups in this course *****/
// The lists of group types and groups need to be freed here...
// ...in order to get them again when changing my groups atomically
Grp_FreeListGrpTypesAndGrps ();
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** Change my groups *****/
if (MySelectionIsValid)
{
ChangesMade = Grp_ChangeMyGrpsAtomically (&LstGrpsIWant);
if (QuietOrVerbose == Cns_VERBOSE)
{
if (ChangesMade)
2019-03-09 20:12:44 +01:00
Ale_CreateAlert (Ale_SUCCESS,NULL,
Txt_The_requested_group_changes_were_successful);
2017-06-04 18:18:54 +02:00
else
2019-03-09 20:12:44 +01:00
Ale_CreateAlert (Ale_WARNING,NULL,
Txt_There_has_been_no_change_in_groups);
2017-06-04 18:18:54 +02:00
}
}
else if (QuietOrVerbose == Cns_VERBOSE)
2019-03-09 20:12:44 +01:00
Ale_CreateAlert (Ale_WARNING,NULL,
Txt_In_a_type_of_group_with_single_enrolment_students_can_not_be_registered_in_more_than_one_group);
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** Free memory with the list of groups which I want to belong to *****/
Grp_FreeListCodGrp (&LstGrpsIWant);
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************** Change groups of another user ************************/
/*****************************************************************************/
void Grp_ChangeOtherUsrGrps (void)
{
extern const char *Txt_The_requested_group_changes_were_successful;
extern const char *Txt_There_has_been_no_change_in_groups;
2017-03-30 11:20:06 +02:00
extern const char *Txt_In_a_type_of_group_with_single_enrolment_students_can_not_be_registered_in_more_than_one_group;
2014-12-01 23:55:08 +01:00
struct ListCodGrps LstGrpsUsrWants;
2017-06-20 01:58:16 +02:00
bool SelectionIsValid;
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** Can I change another user's groups? *****/
if (Grp_ICanChangeGrps[Gbl.Usrs.Me.Role.Logged])
{
/***** Get list of groups types and groups in current course *****/
Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** Get the list of groups to which register this user *****/
LstGrpsUsrWants.GrpCods = NULL; // Initialized to avoid bug reported by Coverity
LstGrpsUsrWants.NumGrps = 0; // Initialized to avoid bug reported by Coverity
Grp_GetLstCodsGrpWanted (&LstGrpsUsrWants);
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** A student can not be enroled in more than one group
if the type of group is of single enrolment *****/
2017-06-20 01:58:16 +02:00
SelectionIsValid = Grp_CheckIfSelectionGrpsSingleEnrolmentIsValid (Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs.Role,&LstGrpsUsrWants);
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** Free list of groups types and groups in this course *****/
// The lists of group types and groups need to be freed here...
// ...in order to get them again when changing groups atomically
Grp_FreeListGrpTypesAndGrps ();
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** Register user in the selected groups *****/
if (SelectionIsValid)
Grp_ChangeGrpsOtherUsrAtomically (&LstGrpsUsrWants);
2019-03-09 20:12:44 +01:00
else
Ale_CreateAlert (Ale_WARNING,NULL,
Txt_In_a_type_of_group_with_single_enrolment_students_can_not_be_registered_in_more_than_one_group);
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
/***** Free memory with the list of groups to/from which register/remove users *****/
Grp_FreeListCodGrp (&LstGrpsUsrWants);
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************** Change my groups atomically **************************/
/*****************************************************************************/
// Return true if desired changes are made
bool Grp_ChangeMyGrpsAtomically (struct ListCodGrps *LstGrpsIWant)
{
struct ListCodGrps LstGrpsIBelong;
unsigned NumGrpTyp;
unsigned NumGrpIBelong;
unsigned NumGrpIWant;
unsigned NumGrpThisType;
struct GroupType *GrpTyp;
bool ITryToLeaveAClosedGroup = false;
bool ITryToRegisterInAClosedGroup = false;
bool ITryToRegisterInFullGroup = false;
bool RemoveMeFromThisGrp;
bool RegisterMeInThisGrp;
bool ChangesMade = false;
/***** Lock tables to make the inscription atomic *****/
2018-10-22 10:12:41 +02:00
Grp_LockTables ();
2014-12-01 23:55:08 +01:00
/***** Get list of groups types and groups in this course *****/
Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
/***** Query in the database the group codes which I belong to *****/
2019-04-04 10:45:15 +02:00
Grp_GetLstCodGrpsUsrBelongs (Gbl.Hierarchy.Crs.CrsCod,-1L,
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.UsrDat.UsrCod,&LstGrpsIBelong);
2017-06-04 18:18:54 +02:00
if (Gbl.Usrs.Me.Role.Logged == Rol_STD)
2014-12-01 23:55:08 +01:00
{
/***** Go across the list of groups which I belong to and check if I try to leave a closed group *****/
for (NumGrpIBelong = 0;
NumGrpIBelong < LstGrpsIBelong.NumGrps && !ITryToLeaveAClosedGroup;
NumGrpIBelong++)
{
for (NumGrpIWant = 0, RemoveMeFromThisGrp = true;
NumGrpIWant < LstGrpsIWant->NumGrps && RemoveMeFromThisGrp;
NumGrpIWant++)
2017-01-19 20:55:31 +01:00
if (LstGrpsIBelong.GrpCods[NumGrpIBelong] == LstGrpsIWant->GrpCods[NumGrpIWant])
2014-12-01 23:55:08 +01:00
RemoveMeFromThisGrp = false;
if (RemoveMeFromThisGrp)
/* Check if the group is closed */
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num && !ITryToLeaveAClosedGroup;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
{
2019-04-04 10:45:15 +02:00
GrpTyp = &Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp];
2014-12-01 23:55:08 +01:00
for (NumGrpThisType = 0;
NumGrpThisType < GrpTyp->NumGrps && !ITryToLeaveAClosedGroup;
NumGrpThisType++)
2017-01-19 20:55:31 +01:00
if ((GrpTyp->LstGrps[NumGrpThisType]).GrpCod == LstGrpsIBelong.GrpCods[NumGrpIBelong])
2014-12-01 23:55:08 +01:00
if (!((GrpTyp->LstGrps[NumGrpThisType]).Open))
ITryToLeaveAClosedGroup = true;
}
}
if (!ITryToLeaveAClosedGroup)
/***** Go across the list of groups which I want to belong
and check that they are not closed or full *****/
for (NumGrpIWant = 0;
NumGrpIWant < LstGrpsIWant->NumGrps &&
!ITryToRegisterInAClosedGroup &&
!ITryToRegisterInFullGroup;
NumGrpIWant++)
{
for (NumGrpIBelong = 0, RegisterMeInThisGrp = true;
NumGrpIBelong < LstGrpsIBelong.NumGrps && RegisterMeInThisGrp;
NumGrpIBelong++)
2017-01-19 20:55:31 +01:00
if (LstGrpsIWant->GrpCods[NumGrpIWant] == LstGrpsIBelong.GrpCods[NumGrpIBelong])
2014-12-01 23:55:08 +01:00
RegisterMeInThisGrp = false;
if (RegisterMeInThisGrp)
/* Check if the group is closed or full */
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num &&
2014-12-01 23:55:08 +01:00
!ITryToRegisterInAClosedGroup &&
!ITryToRegisterInFullGroup;
NumGrpTyp++)
{
2019-04-04 10:45:15 +02:00
GrpTyp = &Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp];
2014-12-01 23:55:08 +01:00
for (NumGrpThisType = 0;
NumGrpThisType < GrpTyp->NumGrps &&
!ITryToRegisterInAClosedGroup &&
!ITryToRegisterInFullGroup;
NumGrpThisType++)
2017-01-19 20:55:31 +01:00
if ((GrpTyp->LstGrps[NumGrpThisType]).GrpCod == LstGrpsIWant->GrpCods[NumGrpIWant])
2014-12-01 23:55:08 +01:00
{
/* Check if the group is closed */
if (!((GrpTyp->LstGrps[NumGrpThisType]).Open))
ITryToRegisterInAClosedGroup = true;
/* Check if the group is full */
2017-05-30 21:43:05 +02:00
else if ((GrpTyp->LstGrps[NumGrpThisType]).NumUsrs[Rol_STD] >=
2014-12-01 23:55:08 +01:00
(GrpTyp->LstGrps[NumGrpThisType]).MaxStudents)
ITryToRegisterInFullGroup = true;
}
}
}
}
if (!ITryToLeaveAClosedGroup &&
!ITryToRegisterInAClosedGroup &&
!ITryToRegisterInFullGroup)
{
/***** Go across the list of groups I belong to, removing those groups that are not present in the list of groups I want to belong to *****/
for (NumGrpIBelong = 0;
NumGrpIBelong < LstGrpsIBelong.NumGrps;
NumGrpIBelong++)
{
for (NumGrpIWant = 0, RemoveMeFromThisGrp = true;
NumGrpIWant < LstGrpsIWant->NumGrps && RemoveMeFromThisGrp;
NumGrpIWant++)
2017-01-19 20:55:31 +01:00
if (LstGrpsIBelong.GrpCods[NumGrpIBelong] == LstGrpsIWant->GrpCods[NumGrpIWant])
2014-12-01 23:55:08 +01:00
RemoveMeFromThisGrp = false;
if (RemoveMeFromThisGrp)
2017-01-19 20:55:31 +01:00
Grp_RemoveUsrFromGroup (Gbl.Usrs.Me.UsrDat.UsrCod,LstGrpsIBelong.GrpCods[NumGrpIBelong]);
2014-12-01 23:55:08 +01:00
}
/***** Go across the list of groups that I want to register in, adding those groups that are not present in the list of groups I belong to *****/
for (NumGrpIWant = 0;
NumGrpIWant < LstGrpsIWant->NumGrps;
NumGrpIWant++)
{
for (NumGrpIBelong = 0, RegisterMeInThisGrp = true;
NumGrpIBelong < LstGrpsIBelong.NumGrps && RegisterMeInThisGrp;
NumGrpIBelong++)
2017-01-19 20:55:31 +01:00
if (LstGrpsIWant->GrpCods[NumGrpIWant] == LstGrpsIBelong.GrpCods[NumGrpIBelong])
2014-12-01 23:55:08 +01:00
RegisterMeInThisGrp = false;
if (RegisterMeInThisGrp)
2017-01-19 20:55:31 +01:00
Grp_AddUsrToGroup (&Gbl.Usrs.Me.UsrDat,LstGrpsIWant->GrpCods[NumGrpIWant]);
2014-12-01 23:55:08 +01:00
}
ChangesMade = true;
}
/***** Free memory with the list of groups which I belonged to *****/
Grp_FreeListCodGrp (&LstGrpsIBelong);
/***** Unlock tables after changes in my groups *****/
2018-10-22 10:12:41 +02:00
Grp_UnlockTables ();
2014-12-01 23:55:08 +01:00
/***** Free list of groups types and groups in this course *****/
Grp_FreeListGrpTypesAndGrps ();
return ChangesMade;
}
/*****************************************************************************/
/********************** Change my groups atomically **************************/
/*****************************************************************************/
2017-06-04 18:18:54 +02:00
void Grp_ChangeGrpsOtherUsrAtomically (struct ListCodGrps *LstGrpsUsrWants)
2014-12-01 23:55:08 +01:00
{
struct ListCodGrps LstGrpsUsrBelongs;
unsigned NumGrpUsrBelongs;
unsigned NumGrpUsrWants;
bool RemoveUsrFromThisGrp;
bool RegisterUsrInThisGrp;
2018-10-22 10:12:41 +02:00
/***** Lock tables to make the inscription atomic *****/
2017-06-08 15:32:33 +02:00
if (Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs.Role == Rol_STD)
2018-10-22 10:12:41 +02:00
Grp_LockTables ();
2014-12-01 23:55:08 +01:00
/***** Get list of groups types and groups in this course *****/
Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
/***** Query in the database the group codes which user belongs to *****/
2019-04-04 10:45:15 +02:00
Grp_GetLstCodGrpsUsrBelongs (Gbl.Hierarchy.Crs.CrsCod,-1L,
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Other.UsrDat.UsrCod,&LstGrpsUsrBelongs);
/***** Go across the list of groups user belongs to, removing those groups that are not present in the list of groups user wants to belong to *****/
for (NumGrpUsrBelongs = 0;
NumGrpUsrBelongs < LstGrpsUsrBelongs.NumGrps;
NumGrpUsrBelongs++)
{
for (NumGrpUsrWants = 0, RemoveUsrFromThisGrp = true;
NumGrpUsrWants < LstGrpsUsrWants->NumGrps && RemoveUsrFromThisGrp;
NumGrpUsrWants++)
2017-01-19 20:55:31 +01:00
if (LstGrpsUsrBelongs.GrpCods[NumGrpUsrBelongs] == LstGrpsUsrWants->GrpCods[NumGrpUsrWants])
2014-12-01 23:55:08 +01:00
RemoveUsrFromThisGrp = false;
if (RemoveUsrFromThisGrp)
2017-01-19 20:55:31 +01:00
Grp_RemoveUsrFromGroup (Gbl.Usrs.Other.UsrDat.UsrCod,LstGrpsUsrBelongs.GrpCods[NumGrpUsrBelongs]);
2014-12-01 23:55:08 +01:00
}
/***** Go across the list of groups that user wants to register in, adding those groups that are not present in the list of groups user belongs to *****/
for (NumGrpUsrWants = 0;
NumGrpUsrWants < LstGrpsUsrWants->NumGrps;
NumGrpUsrWants++)
{
for (NumGrpUsrBelongs = 0, RegisterUsrInThisGrp = true;
NumGrpUsrBelongs < LstGrpsUsrBelongs.NumGrps && RegisterUsrInThisGrp;
NumGrpUsrBelongs++)
2017-01-19 20:55:31 +01:00
if (LstGrpsUsrWants->GrpCods[NumGrpUsrWants] == LstGrpsUsrBelongs.GrpCods[NumGrpUsrBelongs])
2014-12-01 23:55:08 +01:00
RegisterUsrInThisGrp = false;
if (RegisterUsrInThisGrp)
2017-01-19 20:55:31 +01:00
Grp_AddUsrToGroup (&Gbl.Usrs.Other.UsrDat,LstGrpsUsrWants->GrpCods[NumGrpUsrWants]);
2014-12-01 23:55:08 +01:00
}
2018-10-22 10:12:41 +02:00
/***** Free memory with the list of groups which user belonged to *****/
2014-12-01 23:55:08 +01:00
Grp_FreeListCodGrp (&LstGrpsUsrBelongs);
2018-10-22 10:12:41 +02:00
/***** Unlock tables after changes in groups *****/
2017-06-08 15:32:33 +02:00
if (Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs.Role == Rol_STD)
2018-10-22 10:12:41 +02:00
Grp_UnlockTables ();
2014-12-01 23:55:08 +01:00
/***** Free list of groups types and groups in this course *****/
Grp_FreeListGrpTypesAndGrps ();
}
2018-10-22 10:12:41 +02:00
/*****************************************************************************/
/*********** Lock tables to make the registration in groups atomic ***********/
/*****************************************************************************/
static void Grp_LockTables (void)
{
2018-11-02 22:41:02 +01:00
DB_Query ("can not lock tables to change user's groups",
2019-01-07 17:00:04 +01:00
"LOCK TABLES "
"crs_grp_types WRITE,"
"crs_grp WRITE,"
"crs_grp_usr WRITE,"
"crs_usr READ,"
2020-04-30 01:55:23 +02:00
"crs_usr_last READ,"
2020-04-14 17:15:17 +02:00
"rooms READ");
2018-10-22 10:12:41 +02:00
Gbl.DB.LockedTables = true;
}
/*****************************************************************************/
/*********** Unlock tables after changes in registration in groups ***********/
/*****************************************************************************/
static void Grp_UnlockTables (void)
{
Gbl.DB.LockedTables = false; // Set to false before the following unlock...
// ...to not retry the unlock if error in unlocking
2018-11-02 22:41:02 +01:00
DB_Query ("can not unlock tables after changing user's groups",
"UNLOCK TABLES");
2018-10-22 10:12:41 +02:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2017-06-20 01:58:16 +02:00
/******* Check if not selected more than a group of single enrolment *********/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2017-06-20 01:58:16 +02:00
bool Grp_CheckIfSelectionGrpsSingleEnrolmentIsValid (Rol_Role_t Role,struct ListCodGrps *LstGrps)
2014-12-01 23:55:08 +01:00
{
struct ListGrpsAlreadySelec *AlreadyExistsGroupOfType;
unsigned NumCodGrp;
unsigned NumGrpTyp;
long GrpTypCod;
2017-06-20 01:58:16 +02:00
bool MultipleEnrolment;
bool SelectionValid;
2014-12-01 23:55:08 +01:00
2017-06-20 01:58:16 +02:00
switch (Role)
2014-12-01 23:55:08 +01:00
{
2017-06-20 01:58:16 +02:00
case Rol_STD:
if (LstGrps->NumGrps <= 1)
return true;
/***** Create and initialize list of groups already selected *****/
Grp_ConstructorListGrpAlreadySelec (&AlreadyExistsGroupOfType);
2017-07-02 18:53:35 +02:00
/***** Go across the list of groups selected
checking if a group of the same type is already selected *****/
2017-06-20 01:58:16 +02:00
SelectionValid = true;
for (NumCodGrp = 0;
SelectionValid && NumCodGrp < LstGrps->NumGrps;
NumCodGrp++)
{
GrpTypCod = Grp_GetTypeOfGroupOfAGroup (LstGrps->GrpCods[NumCodGrp]);
MultipleEnrolment = Grp_GetMultipleEnrolmentOfAGroupType (GrpTypCod);
if (!MultipleEnrolment)
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2017-06-20 01:58:16 +02:00
NumGrpTyp++)
if (GrpTypCod == AlreadyExistsGroupOfType[NumGrpTyp].GrpTypCod)
{
if (AlreadyExistsGroupOfType[NumGrpTyp].AlreadySelected)
SelectionValid = false;
else
AlreadyExistsGroupOfType[NumGrpTyp].AlreadySelected = true;
break;
}
}
2014-12-01 23:55:08 +01:00
2017-06-20 01:58:16 +02:00
/***** Free memory of the list of booleanos that indicates
if a group of each type has been selected *****/
Grp_DestructorListGrpAlreadySelec (&AlreadyExistsGroupOfType);
return SelectionValid; // Return true if the selection of groups is correct
case Rol_NET:
case Rol_TCH:
return true;
default:
return false;
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********** Create e inicializar list of groups already selected ************/
/*****************************************************************************/
static void Grp_ConstructorListGrpAlreadySelec (struct ListGrpsAlreadySelec **AlreadyExistsGroupOfType)
{
unsigned NumGrpTyp;
/***** Allocate memory to a list of booleanos that indica if already se ha selected a group of cada type *****/
2019-04-04 10:45:15 +02:00
if ((*AlreadyExistsGroupOfType = (struct ListGrpsAlreadySelec *) calloc (Gbl.Crs.Grps.GrpTypes.Num,sizeof (struct ListGrpsAlreadySelec))) == NULL)
2018-10-18 20:06:54 +02:00
Lay_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
/***** Initialize the list *****/
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
{
2019-04-04 10:45:15 +02:00
(*AlreadyExistsGroupOfType)[NumGrpTyp].GrpTypCod = Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod;
2014-12-01 23:55:08 +01:00
(*AlreadyExistsGroupOfType)[NumGrpTyp].AlreadySelected = false;
}
}
/*****************************************************************************/
/***************** Liberar list of groups already selected *******************/
/*****************************************************************************/
static void Grp_DestructorListGrpAlreadySelec (struct ListGrpsAlreadySelec **AlreadyExistsGroupOfType)
{
2019-11-06 19:45:20 +01:00
free (*AlreadyExistsGroupOfType);
2014-12-01 23:55:08 +01:00
*AlreadyExistsGroupOfType = NULL;
}
/*****************************************************************************/
/******************* Register user in the groups of a list *******************/
/*****************************************************************************/
void Grp_RegisterUsrIntoGroups (struct UsrData *UsrDat,struct ListCodGrps *LstGrps)
{
extern const char *Txt_THE_USER_X_has_been_removed_from_the_group_of_type_Y_to_which_it_belonged;
2017-03-30 11:20:06 +02:00
extern const char *Txt_THE_USER_X_has_been_enroled_in_the_group_of_type_Y_Z;
2014-12-01 23:55:08 +01:00
struct ListCodGrps LstGrpsHeBelongs;
2016-12-29 22:19:46 +01:00
unsigned NumGrpTyp;
unsigned NumGrpSel;
unsigned NumGrpThisType;
unsigned NumGrpHeBelongs;
2017-03-30 11:20:06 +02:00
bool MultipleEnrolment;
2014-12-01 23:55:08 +01:00
bool AlreadyRegisteredInGrp;
/***** For each existing type of group in the course... *****/
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
{
2019-04-04 10:45:15 +02:00
MultipleEnrolment = Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MultipleEnrolment;
2014-12-01 23:55:08 +01:00
/***** Query in the database the group codes of any group of this type the student belongs to *****/
2016-12-29 22:42:57 +01:00
LstGrpsHeBelongs.NumGrps = 0; // Initialized to avoid bug reported by Coverity
2017-01-19 20:55:31 +01:00
LstGrpsHeBelongs.GrpCods = NULL; // Initialized to avoid bug reported by Coverity
2019-04-04 10:45:15 +02:00
Grp_GetLstCodGrpsUsrBelongs (Gbl.Hierarchy.Crs.CrsCod,Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod,
2014-12-01 23:55:08 +01:00
UsrDat->UsrCod,&LstGrpsHeBelongs);
/***** For each group selected by me... *****/
for (NumGrpSel = 0;
NumGrpSel < LstGrps->NumGrps;
NumGrpSel++)
{
/* Check if the selected group is of this type */
for (NumGrpThisType = 0;
2019-04-04 10:45:15 +02:00
NumGrpThisType < Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps;
2014-12-01 23:55:08 +01:00
NumGrpThisType++)
2019-04-04 10:45:15 +02:00
if (LstGrps->GrpCods[NumGrpSel] == Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].LstGrps[NumGrpThisType].GrpCod)
2014-12-01 23:55:08 +01:00
{ // The selected group is of this type
AlreadyRegisteredInGrp = false;
/* For each group of this type to which the user belongs... */
for (NumGrpHeBelongs = 0;
NumGrpHeBelongs < LstGrpsHeBelongs.NumGrps;
NumGrpHeBelongs++)
2017-01-19 20:55:31 +01:00
if (LstGrps->GrpCods[NumGrpSel] == LstGrpsHeBelongs.GrpCods[NumGrpHeBelongs])
2014-12-01 23:55:08 +01:00
AlreadyRegisteredInGrp = true;
2017-03-30 11:20:06 +02:00
else if (!MultipleEnrolment) // If the type of group is of single enrolment
2014-12-01 23:55:08 +01:00
{
2017-03-30 11:20:06 +02:00
/* If the enrolment is single and the group to which the user belongs is different from the selected ==>
2014-12-01 23:55:08 +01:00
remove user from the group to which he belongs */
2017-01-19 20:55:31 +01:00
Grp_RemoveUsrFromGroup (UsrDat->UsrCod,LstGrpsHeBelongs.GrpCods[NumGrpHeBelongs]);
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_THE_USER_X_has_been_removed_from_the_group_of_type_Y_to_which_it_belonged,
2019-04-04 10:45:15 +02:00
UsrDat->FullName,Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypName);
2014-12-01 23:55:08 +01:00
}
if (!AlreadyRegisteredInGrp) // If the user does not belong to the selected group
{
2017-01-19 20:55:31 +01:00
Grp_AddUsrToGroup (UsrDat,LstGrps->GrpCods[NumGrpSel]);
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_THE_USER_X_has_been_enroled_in_the_group_of_type_Y_Z,
2019-04-04 10:45:15 +02:00
UsrDat->FullName,Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypName,
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].LstGrps[NumGrpThisType].GrpName);
2014-12-01 23:55:08 +01:00
}
break; // Once we know the type of a selected group, it's not necessary to check the rest of types
}
}
/***** Free the list of groups of this type to which the user belonged *****/
Grp_FreeListCodGrp (&LstGrpsHeBelongs);
}
}
/*****************************************************************************/
/**************** Remove user of the groups indicados in a list **************/
/*****************************************************************************/
// Returns NumGrpsHeIsRemoved
unsigned Grp_RemoveUsrFromGroups (struct UsrData *UsrDat,struct ListCodGrps *LstGrps)
{
extern const char *Txt_THE_USER_X_has_not_been_removed_from_any_group;
extern const char *Txt_THE_USER_X_has_been_removed_from_one_group;
extern const char *Txt_THE_USER_X_has_been_removed_from_Y_groups;
struct ListCodGrps LstGrpsHeBelongs;
2017-06-20 14:43:26 +02:00
unsigned NumGrpSel;
unsigned NumGrpHeBelongs;
unsigned NumGrpsHeIsRemoved = 0;
2014-12-01 23:55:08 +01:00
/***** Query in the database the group codes of any group the user belongs to *****/
2019-04-04 10:45:15 +02:00
Grp_GetLstCodGrpsUsrBelongs (Gbl.Hierarchy.Crs.CrsCod,-1L,
2014-12-01 23:55:08 +01:00
UsrDat->UsrCod,&LstGrpsHeBelongs);
/***** For each group selected by me... *****/
for (NumGrpSel = 0;
NumGrpSel < LstGrps->NumGrps;
NumGrpSel++)
/* For each group to which the user belongs... */
for (NumGrpHeBelongs = 0;
NumGrpHeBelongs < LstGrpsHeBelongs.NumGrps;
NumGrpHeBelongs++)
/* If the user belongs to a selected group from which he must be removed */
2017-01-19 20:55:31 +01:00
if (LstGrpsHeBelongs.GrpCods[NumGrpHeBelongs] == LstGrps->GrpCods[NumGrpSel])
2014-12-01 23:55:08 +01:00
{
2017-01-19 20:55:31 +01:00
Grp_RemoveUsrFromGroup (UsrDat->UsrCod,LstGrpsHeBelongs.GrpCods[NumGrpHeBelongs]);
2014-12-01 23:55:08 +01:00
NumGrpsHeIsRemoved++;
}
/***** Write message to inform about how many groups the student has been removed from *****/
if (NumGrpsHeIsRemoved == 0)
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_THE_USER_X_has_not_been_removed_from_any_group,
UsrDat->FullName);
2014-12-01 23:55:08 +01:00
else if (NumGrpsHeIsRemoved == 1)
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_THE_USER_X_has_been_removed_from_one_group,
UsrDat->FullName);
2014-12-01 23:55:08 +01:00
else // NumGrpsHeIsRemoved > 1
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_THE_USER_X_has_been_removed_from_Y_groups,
UsrDat->FullName,NumGrpsHeIsRemoved);
2014-12-01 23:55:08 +01:00
/***** Free the list of groups of this type to which the user belonged *****/
Grp_FreeListCodGrp (&LstGrpsHeBelongs);
return NumGrpsHeIsRemoved;
}
/*****************************************************************************/
/*************** Remove a user of all the groups of a course *****************/
/*****************************************************************************/
2017-06-20 14:43:26 +02:00
void Grp_RemUsrFromAllGrpsInCrs (long UsrCod,long CrsCod)
2014-12-01 23:55:08 +01:00
{
2018-10-10 23:56:42 +02:00
bool ItsMe = Usr_ItsMe (UsrCod);
2014-12-01 23:55:08 +01:00
/***** Remove user from all the groups of the course *****/
2018-11-02 22:00:31 +01:00
DB_QueryDELETE ("can not remove a user from all groups of a course",
"DELETE FROM crs_grp_usr"
" WHERE UsrCod=%ld AND GrpCod IN"
" (SELECT crs_grp.GrpCod FROM crs_grp_types,crs_grp"
" WHERE crs_grp_types.CrsCod=%ld"
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod)",
UsrCod,CrsCod);
2017-06-20 14:43:26 +02:00
/***** Flush caches *****/
Grp_FlushCacheUsrSharesAnyOfMyGrpsInCurrentCrs ();
if (ItsMe)
Grp_FlushCacheIBelongToGrp ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******* Remove a user from all the groups of all the user's courses *********/
/*****************************************************************************/
2017-06-20 14:43:26 +02:00
void Grp_RemUsrFromAllGrps (long UsrCod)
2014-12-01 23:55:08 +01:00
{
2018-10-10 23:56:42 +02:00
bool ItsMe = Usr_ItsMe (UsrCod);
2014-12-01 23:55:08 +01:00
/***** Remove user from all groups *****/
2018-11-02 22:00:31 +01:00
DB_QueryDELETE ("can not remove a user from the groups he/she belongs to",
"DELETE FROM crs_grp_usr WHERE UsrCod=%ld",
UsrCod);
2017-06-20 14:43:26 +02:00
/***** Flush caches *****/
Grp_FlushCacheUsrSharesAnyOfMyGrpsInCurrentCrs ();
if (ItsMe)
Grp_FlushCacheIBelongToGrp ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************* Remove a user from a group ************************/
/*****************************************************************************/
static void Grp_RemoveUsrFromGroup (long UsrCod,long GrpCod)
{
2018-10-10 23:56:42 +02:00
bool ItsMe = Usr_ItsMe (UsrCod);
2014-12-01 23:55:08 +01:00
/***** Remove user from group *****/
2018-11-02 22:00:31 +01:00
DB_QueryDELETE ("can not remove a user from a group",
"DELETE FROM crs_grp_usr"
" WHERE GrpCod=%ld AND UsrCod=%ld",
GrpCod,UsrCod);
2017-06-20 14:43:26 +02:00
/***** Flush caches *****/
Grp_FlushCacheUsrSharesAnyOfMyGrpsInCurrentCrs ();
if (ItsMe)
Grp_FlushCacheIBelongToGrp ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********************** Register a user in a group **************************/
/*****************************************************************************/
static void Grp_AddUsrToGroup (struct UsrData *UsrDat,long GrpCod)
{
/***** Register in group *****/
2018-11-02 19:37:11 +01:00
DB_QueryINSERT ("can not add a user to a group",
"INSERT INTO crs_grp_usr"
" (GrpCod,UsrCod)"
" VALUES"
" (%ld,%ld)",
GrpCod,UsrDat->UsrCod);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************** List current group types for edition *******************/
/*****************************************************************************/
static void Grp_ListGroupTypesForEdition (void)
{
2017-04-29 20:16:53 +02:00
2014-12-01 23:55:08 +01:00
extern const char *Txt_It_is_optional_to_choose_a_group;
extern const char *Txt_It_is_mandatory_to_choose_a_group;
extern const char *Txt_A_student_can_belong_to_several_groups;
extern const char *Txt_A_student_can_only_belong_to_one_group;
extern const char *Txt_The_groups_will_automatically_open;
extern const char *Txt_The_groups_will_not_automatically_open;
unsigned NumGrpTyp;
2015-10-26 20:02:07 +01:00
unsigned UniqueId;
char Id[32];
2014-12-01 23:55:08 +01:00
/***** Write heading *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_BeginWidePadding (2);
2014-12-01 23:55:08 +01:00
Grp_WriteHeadingGroupTypes ();
/***** List group types with forms for edition *****/
2015-10-26 20:02:07 +01:00
for (NumGrpTyp = 0, UniqueId=1;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2015-10-26 20:02:07 +01:00
NumGrpTyp++, UniqueId++)
2014-12-01 23:55:08 +01:00
{
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-08 23:28:51 +02:00
/* Put icon to remove group type */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"BM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActReqRemGrpTyp,Grp_GROUP_TYPES_SECTION_ID);
2019-04-04 10:45:15 +02:00
Grp_PutParamGrpTypCod (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod);
2017-06-11 19:13:28 +02:00
Ico_PutIconRemove ();
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/* Name of group type */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActRenGrpTyp,Grp_GROUP_TYPES_SECTION_ID);
2019-04-04 10:45:15 +02:00
Grp_PutParamGrpTypCod (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod);
2019-11-04 12:25:48 +01:00
HTM_INPUT_TEXT ("GrpTypName",Grp_MAX_CHARS_GROUP_TYPE_NAME,
2020-04-27 03:16:55 +02:00
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypName,
HTM_SUBMIT_ON_CHANGE,
2019-11-04 12:25:48 +01:00
"size=\"12\"");
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/* Is it mandatory to register in any group? */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActChgMdtGrpTyp,Grp_GROUP_TYPES_SECTION_ID);
2019-04-04 10:45:15 +02:00
Grp_PutParamGrpTypCod (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod);
2020-04-27 03:16:55 +02:00
HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE,
2019-11-05 15:47:35 +01:00
"name=\"MandatoryEnrolment\""
" style=\"width:150px;\"");
2019-11-07 01:13:21 +01:00
HTM_OPTION (HTM_Type_STRING,"N",
!Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MandatoryEnrolment,false,
"%s",Txt_It_is_optional_to_choose_a_group);
HTM_OPTION (HTM_Type_STRING,"Y",
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MandatoryEnrolment,false,
"%s",Txt_It_is_mandatory_to_choose_a_group);
2019-11-05 08:46:38 +01:00
HTM_SELECT_End ();
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/* Is it possible to register in multiple groups? */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActChgMulGrpTyp,Grp_GROUP_TYPES_SECTION_ID);
2019-04-04 10:45:15 +02:00
Grp_PutParamGrpTypCod (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod);
2020-04-27 03:16:55 +02:00
HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE,
2019-11-05 15:47:35 +01:00
"name=\"MultipleEnrolment\""
" style=\"width:150px;\"");
2019-11-07 01:13:21 +01:00
HTM_OPTION (HTM_Type_STRING,"N",
!Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MultipleEnrolment,false,
"%s",Txt_A_student_can_only_belong_to_one_group);
HTM_OPTION (HTM_Type_STRING,"Y",
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MultipleEnrolment,false,
"%s",Txt_A_student_can_belong_to_several_groups);
2019-11-05 08:46:38 +01:00
HTM_SELECT_End ();
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/* Open time */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActChgTimGrpTyp,Grp_GROUP_TYPES_SECTION_ID);
2019-04-04 10:45:15 +02:00
Grp_PutParamGrpTypCod (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod);
2019-10-23 19:05:05 +02:00
HTM_TABLE_BeginCenterPadding (2);
HTM_TR_Begin (NULL);
2019-10-07 15:15:55 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\" style=\"width:16px;\"");
2019-10-29 21:41:54 +01:00
Ico_PutIcon ("clock.svg",
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MustBeOpened ? Txt_The_groups_will_automatically_open :
Txt_The_groups_will_not_automatically_open,
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MustBeOpened ? "CONTEXT_ICO_16x16" :
"ICO_HIDDEN CONTEXT_ICO_16x16");
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 15:15:55 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
2018-10-18 02:02:32 +02:00
snprintf (Id,sizeof (Id),
"open_time_%u",
UniqueId);
2015-10-26 20:02:07 +01:00
Dat_WriteFormClientLocalDateTimeFromTimeUTC (Id,
"Open",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].OpenTimeUTC,
2015-10-26 20:02:07 +01:00
Gbl.Now.Date.Year,
Gbl.Now.Date.Year + 1,
2016-12-03 20:08:01 +01:00
Dat_FORM_SECONDS_ON,
2017-02-26 20:09:21 +01:00
Dat_HMS_DO_NOT_SET, // Don't set hour, minute and second
true); // Submit on change
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 15:15:55 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
HTM_TABLE_End ();
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/* Number of groups of this type */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM\"");
2019-11-10 13:31:47 +01:00
HTM_Unsigned (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 15:15:55 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
2017-04-29 20:16:53 +02:00
/***** End table *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_End ();
2014-12-01 23:55:08 +01:00
}
2017-04-29 19:19:55 +02:00
/*****************************************************************************/
/************ Put contextual icons in edition of types of group **************/
/*****************************************************************************/
2020-04-08 18:18:46 +02:00
static void Grp_PutIconsEditingGroupTypes (__attribute__((unused)) void *Args)
2017-04-29 19:19:55 +02:00
{
2020-04-08 18:18:46 +02:00
/***** Put icon to view groups *****/
Grp_PutIconToViewGroups ();
2017-04-29 19:19:55 +02:00
2020-04-08 18:18:46 +02:00
/***** Put icon to create a new type of group *****/
Grp_PutIconToCreateNewGroupType ();
2017-04-29 19:19:55 +02:00
}
static void Grp_PutIconToViewGroups (void)
{
2020-03-26 02:54:30 +01:00
Ico_PutContextualIconToView (ActReqSelGrp,
NULL,NULL);
2017-04-29 19:19:55 +02:00
}
static void Grp_PutIconToCreateNewGroupType (void)
{
extern const char *Txt_New_type_of_group;
/***** Put form to create a new type of group *****/
2020-03-26 02:54:30 +01:00
Ico_PutContextualIconToAdd (ActReqEdiGrp,Grp_NEW_GROUP_TYPE_SECTION_ID,
NULL,NULL,
2019-01-10 15:26:33 +01:00
Txt_New_type_of_group);
2017-04-29 19:19:55 +02:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/*********************** Write heading of group types ************************/
/*****************************************************************************/
static void Grp_WriteHeadingGroupTypes (void)
{
extern const char *Txt_Type_of_group;
extern const char *Txt_eg_Lectures_Practicals;
2017-03-30 11:20:06 +02:00
extern const char *Txt_Mandatory_enrolment;
extern const char *Txt_Multiple_enrolment;
2014-12-01 23:55:08 +01:00
extern const char *Txt_Opening_of_groups;
extern const char *Txt_No_of_BR_groups;
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-12 00:07:52 +02:00
2019-10-23 19:05:05 +02:00
HTM_TH (1,1,"BM",NULL);
HTM_TH_Begin (1,1,"CM");
2019-11-10 12:36:37 +01:00
HTM_Txt (Txt_Type_of_group);
2019-11-09 21:08:20 +01:00
HTM_BR ();
2019-11-11 00:15:44 +01:00
HTM_TxtF ("(%s)",Txt_eg_Lectures_Practicals);
2019-10-23 19:05:05 +02:00
HTM_TH_End ();
HTM_TH (1,1,"CM",Txt_Mandatory_enrolment);
HTM_TH (1,1,"CM",Txt_Multiple_enrolment);
HTM_TH (1,1,"CM",Txt_Opening_of_groups);
HTM_TH (1,1,"CM",Txt_No_of_BR_groups);
2019-10-12 00:07:52 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************** List current groups for edition **********************/
/*****************************************************************************/
2020-04-14 17:15:17 +02:00
static void Grp_ListGroupsForEdition (const struct Roo_Rooms *Rooms)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_Group_X_open_click_to_close_it;
extern const char *Txt_Group_X_closed_click_to_open_it;
extern const char *Txt_File_zones_of_the_group_X_enabled_click_to_disable_them;
extern const char *Txt_File_zones_of_the_group_X_disabled_click_to_enable_them;
2020-04-14 17:15:17 +02:00
extern const char *Txt_No_assigned_room;
extern const char *Txt_Another_room;
2014-12-01 23:55:08 +01:00
unsigned NumGrpTyp;
unsigned NumTipGrpAux;
unsigned NumGrpThisType;
2020-04-15 02:17:57 +02:00
unsigned NumRoo;
2014-12-01 23:55:08 +01:00
struct GroupType *GrpTyp;
struct GroupType *GrpTypAux;
struct Group *Grp;
2017-05-30 21:43:05 +02:00
Rol_Role_t Role;
2019-11-08 01:10:32 +01:00
char StrMaxStudents[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
2014-12-01 23:55:08 +01:00
/***** Write heading *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_BeginWidePadding (2);
2014-12-01 23:55:08 +01:00
Grp_WriteHeadingGroups ();
/***** List the groups *****/
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
{
2019-04-04 10:45:15 +02:00
GrpTyp = &Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp];
2014-12-01 23:55:08 +01:00
for (NumGrpThisType = 0;
NumGrpThisType < GrpTyp->NumGrps;
NumGrpThisType++)
{
Grp = &(GrpTyp->LstGrps[NumGrpThisType]);
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-08 23:28:51 +02:00
/***** Icon to remove group *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"BM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActReqRemGrp,Grp_GROUPS_SECTION_ID);
2014-12-01 23:55:08 +01:00
Grp_PutParamGrpCod (Grp->GrpCod);
2017-06-11 19:13:28 +02:00
Ico_PutIconRemove ();
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
2019-01-04 22:46:46 +01:00
/***** Icon to open/close group *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"BM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (Grp->Open ? ActCloGrp :
2017-04-29 01:12:35 +02:00
ActOpeGrp,
2017-05-25 13:43:54 +02:00
Grp_GROUPS_SECTION_ID);
2014-12-01 23:55:08 +01:00
Grp_PutParamGrpCod (Grp->GrpCod);
2019-01-12 19:46:33 +01:00
Ico_PutIconLink (Grp->Open ? "unlock.svg" :
2019-01-12 03:00:59 +01:00
"lock.svg",
2019-12-30 21:47:07 +01:00
Str_BuildStringStr (Grp->Open ? Txt_Group_X_open_click_to_close_it :
Txt_Group_X_closed_click_to_open_it,
Grp->GrpName));
Str_FreeString ();
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
2019-01-04 22:46:46 +01:00
/***** Icon to activate file zones for this group *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"BM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (Grp->FileZones ? ActDisFilZonGrp :
2017-04-29 01:12:35 +02:00
ActEnaFilZonGrp,
2017-05-25 13:43:54 +02:00
Grp_GROUPS_SECTION_ID);
2014-12-01 23:55:08 +01:00
Grp_PutParamGrpCod (Grp->GrpCod);
2019-01-12 03:00:59 +01:00
Ico_PutIconLink (Grp->FileZones ? "folder-open-green.svg" :
"folder-red.svg",
2019-12-30 21:47:07 +01:00
Str_BuildStringStr (Grp->FileZones ? Txt_File_zones_of_the_group_X_enabled_click_to_disable_them :
Txt_File_zones_of_the_group_X_disabled_click_to_enable_them,
Grp->GrpName));
Str_FreeString ();
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
2019-01-04 22:46:46 +01:00
/***** Group type *****/
/* Start selector */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActChgGrpTyp,Grp_GROUPS_SECTION_ID);
2014-12-01 23:55:08 +01:00
Grp_PutParamGrpCod (Grp->GrpCod);
2020-04-27 03:16:55 +02:00
HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE,
2019-11-05 15:47:35 +01:00
"name=\"GrpTypCod\" style=\"width:100px;\"");
2019-01-04 22:46:46 +01:00
/* Options for group types */
2014-12-01 23:55:08 +01:00
for (NumTipGrpAux = 0;
2019-04-04 10:45:15 +02:00
NumTipGrpAux < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumTipGrpAux++)
{
2019-04-04 10:45:15 +02:00
GrpTypAux = &Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumTipGrpAux];
2019-11-07 01:13:21 +01:00
HTM_OPTION (HTM_Type_LONG,&GrpTypAux->GrpTypCod,
GrpTypAux->GrpTypCod == GrpTyp->GrpTypCod,false,
"%s",GrpTypAux->GrpTypName);
2014-12-01 23:55:08 +01:00
}
2019-01-04 22:46:46 +01:00
/* End selector */
2019-11-05 08:46:38 +01:00
HTM_SELECT_End ();
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
2019-01-04 22:46:46 +01:00
/***** Group name *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActRenGrp,Grp_GROUPS_SECTION_ID);
2014-12-01 23:55:08 +01:00
Grp_PutParamGrpCod (Grp->GrpCod);
2020-04-27 03:16:55 +02:00
HTM_INPUT_TEXT ("GrpName",Grp_MAX_CHARS_GROUP_NAME,Grp->GrpName,
HTM_SUBMIT_ON_CHANGE,
2019-11-04 12:25:48 +01:00
"size=\"20\"");
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
2020-04-14 17:15:17 +02:00
/***** Room *****/
2019-01-04 22:46:46 +01:00
/* Start selector */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2020-04-14 17:15:17 +02:00
Frm_StartFormAnchor (ActChgGrpRoo,Grp_GROUPS_SECTION_ID);
2019-01-04 22:46:46 +01:00
Grp_PutParamGrpCod (Grp->GrpCod);
2020-04-27 03:16:55 +02:00
HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE,
2020-04-14 17:15:17 +02:00
"name=\"RooCod\" style=\"width:100px;\"");
2019-01-04 22:46:46 +01:00
2020-04-14 17:15:17 +02:00
/* Option for no assigned room */
2019-11-07 01:13:21 +01:00
HTM_OPTION (HTM_Type_STRING,"-1",
2020-04-14 17:15:17 +02:00
Grp->Room.RooCod < 0,false,
"%s",Txt_No_assigned_room);
2019-01-04 22:46:46 +01:00
2020-04-14 17:15:17 +02:00
/* Option for another room */
2019-11-07 01:13:21 +01:00
HTM_OPTION (HTM_Type_STRING,"0",
2020-04-14 17:15:17 +02:00
Grp->Room.RooCod == 0,false,
"%s",Txt_Another_room);
2019-01-04 22:46:46 +01:00
2020-04-14 17:15:17 +02:00
/* Options for rooms */
2020-04-15 02:17:57 +02:00
for (NumRoo = 0;
NumRoo < Rooms->Num;
NumRoo++)
HTM_OPTION (HTM_Type_LONG,&Rooms->Lst[NumRoo].RooCod,
Rooms->Lst[NumRoo].RooCod == Grp->Room.RooCod,false,
"%s",Rooms->Lst[NumRoo].ShrtName);
2019-01-04 22:46:46 +01:00
/* End selector */
2019-11-05 08:46:38 +01:00
HTM_SELECT_End ();
2019-01-04 22:46:46 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-01-04 22:46:46 +01:00
/***** Current number of users in this group *****/
2017-05-30 21:43:05 +02:00
for (Role = Rol_TCH;
Role >= Rol_STD;
Role--)
2019-10-07 15:15:55 +02:00
{
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM\"");
2019-11-11 10:59:24 +01:00
HTM_Int (Grp->NumUsrs[Role]);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 15:15:55 +02:00
}
2017-05-30 21:43:05 +02:00
2019-01-04 22:46:46 +01:00
/***** Maximum number of students of the group (row[3]) *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActChgMaxStdGrp,Grp_GROUPS_SECTION_ID);
2014-12-01 23:55:08 +01:00
Grp_PutParamGrpCod (Grp->GrpCod);
2019-11-03 23:59:20 +01:00
Grp_WriteMaxStds (StrMaxStudents,Grp->MaxStudents);
2020-04-27 03:16:55 +02:00
HTM_INPUT_TEXT ("MaxStudents",Cns_MAX_DECIMAL_DIGITS_UINT,StrMaxStudents,
HTM_SUBMIT_ON_CHANGE,
2019-11-04 12:25:48 +01:00
"size=\"3\"");
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-08 23:28:51 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
}
2016-11-14 10:05:41 +01:00
/***** End table *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_End ();
2017-04-29 19:32:06 +02:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/************************** Write heading of groups **************************/
/*****************************************************************************/
static void Grp_WriteHeadingGroups (void)
{
extern const char *Txt_Type_BR_of_group;
extern const char *Txt_Group_name;
extern const char *Txt_eg_A_B;
2020-04-14 17:15:17 +02:00
extern const char *Txt_Room;
2017-05-30 21:43:05 +02:00
extern const char *Txt_ROLES_PLURAL_BRIEF_Abc[Rol_NUM_ROLES];
2014-12-01 23:55:08 +01:00
extern const char *Txt_Max_BR_students;
2017-05-30 21:43:05 +02:00
Rol_Role_t Role;
2014-12-01 23:55:08 +01:00
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-12 00:07:52 +02:00
2019-10-23 19:05:05 +02:00
HTM_TH (1,1,"BM",NULL);
HTM_TH (1,1,"BM",NULL);
HTM_TH (1,1,"BM",NULL);
HTM_TH (1,1,"CM",Txt_Type_BR_of_group);
HTM_TH_Begin (1,1,"CM");
2019-11-10 12:36:37 +01:00
HTM_Txt (Txt_Group_name);
2019-11-09 21:08:20 +01:00
HTM_BR ();
2019-11-11 00:15:44 +01:00
HTM_TxtF ("(%s)",Txt_eg_A_B);
2019-10-23 19:05:05 +02:00
HTM_TH_End ();
2020-04-14 17:15:17 +02:00
HTM_TH (1,1,"CM",Txt_Room);
2017-05-30 21:43:05 +02:00
for (Role = Rol_TCH;
Role >= Rol_STD;
Role--)
2019-10-23 19:05:05 +02:00
HTM_TH (1,1,"CM",Txt_ROLES_PLURAL_BRIEF_Abc[Role]);
HTM_TH (1,1,"CM",Txt_Max_BR_students);
2019-10-12 00:07:52 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2020-05-06 01:43:48 +02:00
/****** List groups of a type to edit ******/
/****** assignments, attendance events, surveys, exam events or matches ******/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2020-05-06 01:43:48 +02:00
void Grp_ListGrpsToEditAsgAttSvyEvtMch (struct GroupType *GrpTyp,long Cod,
Grp_WhichIsAssociatedToGrp_t WhichIsAssociatedToGrp)
2014-12-01 23:55:08 +01:00
{
2020-05-06 01:43:48 +02:00
static const struct
{
const char *Table;
const char *Field;
} AssociationsToGrps[Grp_NUM_ASSOCIATIONS_TO_GROUPS] =
{
[Grp_ASSIGNMENT] = {"asg_grp" ,"AsgCod"},
[Grp_ATT_EVENT ] = {"att_grp" ,"AttCod"},
[Grp_SURVEY ] = {"svy_grp" ,"SvyCod"},
[Grp_EXA_EVENT ] = {"exa_groups","EvtCod"},
[Grp_MATCH ] = {"mch_groups","MchCod"},
};
2014-12-01 23:55:08 +01:00
struct ListCodGrps LstGrpsIBelong;
unsigned NumGrpThisType;
bool IBelongToThisGroup;
struct Group *Grp;
2020-05-06 01:43:48 +02:00
bool AssociatedToGrp;
2014-12-01 23:55:08 +01:00
/***** Write heading *****/
Grp_WriteGrpHead (GrpTyp);
/***** Query from the database the groups of this type which I belong to *****/
2019-04-04 10:45:15 +02:00
Grp_GetLstCodGrpsUsrBelongs (Gbl.Hierarchy.Crs.CrsCod,GrpTyp->GrpTypCod,
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.UsrDat.UsrCod,&LstGrpsIBelong);
/***** List the groups *****/
for (NumGrpThisType = 0;
NumGrpThisType < GrpTyp->NumGrps;
NumGrpThisType++)
{
Grp = &(GrpTyp->LstGrps[NumGrpThisType]);
IBelongToThisGroup = Grp_CheckIfGrpIsInList (Grp->GrpCod,&LstGrpsIBelong);
2020-05-06 01:43:48 +02:00
if (Cod > 0) // Cod == -1L means new item, assignment, event, survey, exam event or match
AssociatedToGrp = Grp_CheckIfAssociatedToGrp (AssociationsToGrps[WhichIsAssociatedToGrp].Table,
AssociationsToGrps[WhichIsAssociatedToGrp].Field,
Cod,Grp->GrpCod);
else
AssociatedToGrp = false;
2019-11-04 20:41:35 +01:00
/* Put checkbox to select the group */
HTM_TR_Begin (NULL);
if (IBelongToThisGroup)
HTM_TD_Begin ("class=\"LM LIGHT_BLUE\"");
else
HTM_TD_Begin ("class=\"LM\"");
2020-03-12 13:53:37 +01:00
HTM_INPUT_CHECKBOX ("GrpCods",HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-04 20:41:35 +01:00
"id=\"Grp%ld\" value=\"%ld\"%s%s"
" onclick=\"uncheckParent(this,'WholeCrs')\"",
Grp->GrpCod,Grp->GrpCod,
AssociatedToGrp ? " checked=\"checked\"" : "",
(IBelongToThisGroup ||
Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM) ? "" : " disabled=\"disabled\"");
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
Grp_WriteRowGrp (Grp,IBelongToThisGroup);
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/***** Free memory with the list of groups which I belongs to *****/
Grp_FreeListCodGrp (&LstGrpsIBelong);
}
2020-05-06 01:43:48 +02:00
/*****************************************************************************/
/************ Check if an assignment is associated to a group ****************/
/*****************************************************************************/
static bool Grp_CheckIfAssociatedToGrp (const char *Table,const char *Field,
long Cod,long GrpCod)
{
/***** Get if an assignment, attendance event, survey, exam event or match
is associated to a given group from database *****/
return (DB_QueryCOUNT ("can not check if associated to a group",
"SELECT COUNT(*) FROM %s"
" WHERE %s=%ld AND GrpCod=%ld",
Table,Field,Cod,GrpCod) != 0);
}
/*****************************************************************************/
/*************** Check if a survey is associated to any group ****************/
/*****************************************************************************/
bool Grp_CheckIfAssociatedToGrps (const char *Table,const char *Field,long Cod)
{
/***** Get if an assignment, attendance event, survey, exam event or match
is associated to any group from database *****/
return (DB_QueryCOUNT ("can not check if associated to groups",
"SELECT COUNT(*) FROM %s"
" WHERE %s=%ld",
Table,Field,Cod) != 0);
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/***************** Show list of groups to register/remove me *****************/
/*****************************************************************************/
void Grp_ReqRegisterInGrps (void)
{
2016-03-28 01:02:34 +02:00
/***** Show list of groups to register/remove me *****/
2017-05-22 12:23:08 +02:00
Grp_ShowLstGrpsToChgMyGrps ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************** Show list of groups to register/remove me *****************/
/*****************************************************************************/
2017-05-22 12:23:08 +02:00
void Grp_ShowLstGrpsToChgMyGrps (void)
2014-12-01 23:55:08 +01:00
{
2016-11-13 20:54:06 +01:00
extern const char *Hlp_USERS_Groups;
2014-12-01 23:55:08 +01:00
extern const char *Txt_My_groups;
2016-03-16 15:00:47 +01:00
extern const char *Txt_Change_my_groups;
2017-03-30 11:20:06 +02:00
extern const char *Txt_Enrol_in_groups;
2016-03-28 01:02:34 +02:00
extern const char *Txt_No_groups_have_been_created_in_the_course_X;
2017-03-01 17:06:24 +01:00
extern const char *Txt_Create_group;
2014-12-01 23:55:08 +01:00
unsigned NumGrpTyp;
2017-05-30 11:35:01 +02:00
unsigned NumGrpsThisTypeIBelong;
2014-12-01 23:55:08 +01:00
unsigned NumGrpsIBelong = 0;
2016-03-16 15:00:47 +01:00
bool PutFormToChangeGrps = !Gbl.Form.Inside; // Not inside another form (record card)
bool ICanEdit = !Gbl.Form.Inside &&
2017-06-04 18:18:54 +02:00
(Gbl.Usrs.Me.Role.Logged == Rol_TCH ||
Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM);
bool ICanChangeMyGrps = false;
2014-12-01 23:55:08 +01:00
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.NumGrps) // This course has groups
2016-03-28 01:02:34 +02:00
{
/***** Get list of groups types and groups in this course *****/
Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
2014-12-01 23:55:08 +01:00
2016-03-28 01:02:34 +02:00
/***** Show warnings to students *****/
2017-03-30 11:20:06 +02:00
// Students are required to join groups with mandatory enrolment; teachers don't
2017-06-04 18:18:54 +02:00
if (Gbl.Usrs.Me.Role.Logged == Rol_STD)
2016-03-28 01:02:34 +02:00
Grp_ShowWarningToStdsToChangeGrps ();
}
2014-12-01 23:55:08 +01:00
2019-10-26 02:19:42 +02:00
/***** Begin box *****/
2020-03-26 02:54:30 +01:00
if (ICanEdit)
Box_BoxBegin (NULL,Txt_My_groups,
2020-04-08 18:18:46 +02:00
Grp_PutIconToEditGroups,NULL,
2020-03-26 02:54:30 +01:00
Hlp_USERS_Groups,Box_NOT_CLOSABLE);
else
Box_BoxBegin (NULL,Txt_My_groups,
NULL,NULL,
Hlp_USERS_Groups,Box_NOT_CLOSABLE);
2016-03-16 15:00:47 +01:00
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.NumGrps) // This course has groups
2016-03-16 15:00:47 +01:00
{
2019-10-20 22:00:28 +02:00
/***** Begin form *****/
2016-03-28 01:02:34 +02:00
if (PutFormToChangeGrps)
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActChgGrp);
2016-03-28 01:02:34 +02:00
/***** List the groups the user belongs to for change *****/
2019-10-23 19:05:05 +02:00
HTM_TABLE_BeginWidePadding (2);
2016-03-28 01:02:34 +02:00
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2016-03-28 01:02:34 +02:00
NumGrpTyp++)
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps) // If there are groups of this type
2017-05-30 11:35:01 +02:00
{
2019-04-04 10:45:15 +02:00
ICanChangeMyGrps |= Grp_ListGrpsForChangeMySelection (&Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp],
2017-06-04 18:18:54 +02:00
&NumGrpsThisTypeIBelong);
2017-05-30 11:35:01 +02:00
NumGrpsIBelong += NumGrpsThisTypeIBelong;
}
2019-10-23 19:05:05 +02:00
HTM_TABLE_End ();
2016-03-28 01:02:34 +02:00
/***** End form *****/
if (PutFormToChangeGrps)
{
2017-06-04 18:18:54 +02:00
if (ICanChangeMyGrps)
2017-06-11 19:02:40 +02:00
Btn_PutConfirmButton (NumGrpsIBelong ? Txt_Change_my_groups :
2017-05-30 11:35:01 +02:00
Txt_Enrol_in_groups);
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2016-03-28 01:02:34 +02:00
}
}
else // This course has no groups
{
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_INFO,Txt_No_groups_have_been_created_in_the_course_X,
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.FullName);
2017-03-01 17:06:24 +01:00
/***** Button to create group *****/
if (ICanEdit)
{
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActReqEdiGrp);
2017-06-11 19:02:40 +02:00
Btn_PutConfirmButton (Txt_Create_group);
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2017-03-01 17:06:24 +01:00
}
2016-03-16 15:00:47 +01:00
}
2017-06-12 14:16:33 +02:00
/***** End box *****/
2019-10-25 22:48:34 +02:00
Box_BoxEnd ();
2014-12-01 23:55:08 +01:00
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.NumGrps) // This course has groups
2016-03-28 01:02:34 +02:00
/***** Free list of groups types and groups in this course *****/
Grp_FreeListGrpTypesAndGrps ();
2016-03-16 15:00:47 +01:00
}
/*****************************************************************************/
/*************************** Put icon to edit groups *************************/
/*****************************************************************************/
2020-04-08 18:18:46 +02:00
static void Grp_PutIconToEditGroups (__attribute__((unused)) void *Args)
2016-03-16 15:00:47 +01:00
{
2020-04-08 18:18:46 +02:00
Ico_PutContextualIconToEdit (ActReqEdiGrp,NULL,
NULL,NULL);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********** Show warnings to students before form to change groups **********/
/*****************************************************************************/
static void Grp_ShowWarningToStdsToChangeGrps (void)
{
extern const char *Txt_You_have_to_register_compulsorily_at_least_in_one_group_of_type_X;
extern const char *Txt_You_have_to_register_compulsorily_in_one_group_of_type_X;
extern const char *Txt_You_can_register_voluntarily_in_one_or_more_groups_of_type_X;
extern const char *Txt_You_can_register_voluntarily_in_one_group_of_type_X;
unsigned NumGrpTyp;
struct GroupType *GrpTyp;
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
{
2019-04-04 10:45:15 +02:00
GrpTyp = &Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp];
2019-02-18 14:41:46 +01:00
// If there are groups of this type...
if (GrpTyp->NumGrps)
// If I don't belong to any group
if (!Grp_CheckIfIBelongToGrpsOfType (GrpTyp->GrpTypCod)) // Fast check (not necesary, but avoid slow check)
// If there is any group of this type available
2019-02-18 17:30:35 +01:00
if (Grp_GetIfAvailableGrpTyp (GrpTyp->GrpTypCod)) // Slow check
2014-12-01 23:55:08 +01:00
{
2017-03-30 11:20:06 +02:00
if (GrpTyp->MandatoryEnrolment)
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_WARNING,GrpTyp->MultipleEnrolment ? Txt_You_have_to_register_compulsorily_at_least_in_one_group_of_type_X :
Txt_You_have_to_register_compulsorily_in_one_group_of_type_X,
GrpTyp->GrpTypName);
2014-12-01 23:55:08 +01:00
else
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_INFO,GrpTyp->MultipleEnrolment ? Txt_You_can_register_voluntarily_in_one_or_more_groups_of_type_X :
Txt_You_can_register_voluntarily_in_one_group_of_type_X,
GrpTyp->GrpTypName);
2014-12-01 23:55:08 +01:00
}
}
}
/*****************************************************************************/
/*************** List the groups of a type to register in ********************/
/*****************************************************************************/
2017-05-30 11:35:01 +02:00
// Returns true if I can change my selection
2014-12-01 23:55:08 +01:00
2017-06-04 18:18:54 +02:00
static bool Grp_ListGrpsForChangeMySelection (struct GroupType *GrpTyp,
unsigned *NumGrpsThisTypeIBelong)
2014-12-01 23:55:08 +01:00
{
struct ListCodGrps LstGrpsIBelong;
unsigned NumGrpThisType;
struct Group *Grp;
bool IBelongToThisGroup;
2017-06-20 01:58:16 +02:00
bool IBelongToAClosedGroup;
bool ICanChangeMySelectionForThisGrpTyp;
bool ICanChangeMySelectionForThisGrp;
2019-11-04 18:17:39 +01:00
char StrGrpCod[32];
2014-12-01 23:55:08 +01:00
/***** Write heading *****/
Grp_WriteGrpHead (GrpTyp);
/***** Query in the database the group of this type that I belong to *****/
2019-04-04 10:45:15 +02:00
Grp_GetLstCodGrpsUsrBelongs (Gbl.Hierarchy.Crs.CrsCod,GrpTyp->GrpTypCod,
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.UsrDat.UsrCod,&LstGrpsIBelong);
2017-05-30 11:35:01 +02:00
*NumGrpsThisTypeIBelong = LstGrpsIBelong.NumGrps;
2014-12-01 23:55:08 +01:00
2017-06-20 01:58:16 +02:00
/***** Check if I can change my selection *****/
switch (Gbl.Usrs.Me.Role.Logged)
{
case Rol_STD:
if (GrpTyp->MultipleEnrolment) // Enrolment is multiple
{
for (NumGrpThisType = 0, ICanChangeMySelectionForThisGrpTyp = false;
NumGrpThisType < GrpTyp->NumGrps && !ICanChangeMySelectionForThisGrpTyp;
NumGrpThisType++)
{
Grp = &(GrpTyp->LstGrps[NumGrpThisType]);
if (Grp->Open) // If group is open
{
IBelongToThisGroup = Grp_CheckIfGrpIsInList (Grp->GrpCod,&LstGrpsIBelong);
if (IBelongToThisGroup) // I belong to this group
ICanChangeMySelectionForThisGrpTyp = true; // I can unregister from group
else // I don't belong
if (Grp->NumUsrs[Rol_STD] < Grp->MaxStudents) // Group is not full
ICanChangeMySelectionForThisGrpTyp = true; // I can register into group
}
}
}
else // Enrolment is single
{
/* Step 1: Check if I belong to a closed group */
for (NumGrpThisType = 0, IBelongToAClosedGroup = false;
NumGrpThisType < GrpTyp->NumGrps && !IBelongToAClosedGroup;
NumGrpThisType++)
{
Grp = &(GrpTyp->LstGrps[NumGrpThisType]);
if (!Grp->Open) // If group is closed
{
IBelongToThisGroup = Grp_CheckIfGrpIsInList (Grp->GrpCod,&LstGrpsIBelong);
if (IBelongToThisGroup) // I belong to this group
IBelongToAClosedGroup = true; // I belong to a closed group
}
}
if (IBelongToAClosedGroup) // I belong to a closed group
ICanChangeMySelectionForThisGrpTyp = false; // I can not unregister
else // I don't belong to a closed group
/* Step 2: Check if I can register in at least one group to which I don't belong */
for (NumGrpThisType = 0, ICanChangeMySelectionForThisGrpTyp = false;
NumGrpThisType < GrpTyp->NumGrps && !ICanChangeMySelectionForThisGrpTyp;
NumGrpThisType++)
{
Grp = &(GrpTyp->LstGrps[NumGrpThisType]);
if (Grp->Open && // If group is open...
Grp->NumUsrs[Rol_STD] < Grp->MaxStudents) // ...and not full
{
IBelongToThisGroup = Grp_CheckIfGrpIsInList (Grp->GrpCod,&LstGrpsIBelong);
if (!IBelongToThisGroup) // I don't belong to this group
ICanChangeMySelectionForThisGrpTyp = true; // I can register into this group
}
}
}
break;
case Rol_TCH:
case Rol_SYS_ADM:
ICanChangeMySelectionForThisGrpTyp = true; // I can not register/unregister
break;
default:
ICanChangeMySelectionForThisGrpTyp = false; // I can not register/unregister
break;
}
2014-12-01 23:55:08 +01:00
/***** List the groups *****/
for (NumGrpThisType = 0;
NumGrpThisType < GrpTyp->NumGrps;
NumGrpThisType++)
{
Grp = &(GrpTyp->LstGrps[NumGrpThisType]);
IBelongToThisGroup = Grp_CheckIfGrpIsInList (Grp->GrpCod,&LstGrpsIBelong);
2017-06-20 01:58:16 +02:00
/* Selection disabled? */
if (ICanChangeMySelectionForThisGrpTyp) // I can change my selection for this group type
2017-05-30 11:35:01 +02:00
{
2017-06-20 01:58:16 +02:00
ICanChangeMySelectionForThisGrp = true;
if (Gbl.Usrs.Me.Role.Logged == Rol_STD)
{
2017-05-30 11:35:01 +02:00
if (Grp->Open) // If group is open
{
2017-06-20 01:58:16 +02:00
if (!IBelongToThisGroup && // I don't belong to group
Grp->NumUsrs[Rol_STD] >= Grp->MaxStudents) // Group is full
ICanChangeMySelectionForThisGrp = false;
2017-05-30 11:35:01 +02:00
}
2017-06-20 01:58:16 +02:00
else // If group is closed
ICanChangeMySelectionForThisGrp = false;
}
}
else // I can not change my selection for this group type
ICanChangeMySelectionForThisGrp = false;
2019-11-04 20:41:35 +01:00
/* Put radio item or checkbox to select the group */
HTM_TR_Begin (NULL);
if (IBelongToThisGroup)
HTM_TD_Begin ("class=\"LM LIGHT_BLUE\"");
else
HTM_TD_Begin ("class=\"LM\"");
2019-11-04 18:17:39 +01:00
snprintf (StrGrpCod,sizeof (StrGrpCod),
"GrpCod%ld",
GrpTyp->GrpTypCod);
if (Gbl.Usrs.Me.Role.Logged == Rol_STD && // If I am a student
!GrpTyp->MultipleEnrolment && // ...and the enrolment is single
GrpTyp->NumGrps > 1) // ...and there are more than one group
{
/* Put a radio item */
if (GrpTyp->MandatoryEnrolment)
HTM_INPUT_RADIO (StrGrpCod,false,
"id=\"Grp%ld\" value=\"%ld\"%s%s",
Grp->GrpCod,Grp->GrpCod,
IBelongToThisGroup ? " checked=\"checked\"" : "", // Group selected?
ICanChangeMySelectionForThisGrp ? "" :
IBelongToThisGroup ? " readonly" : // I can not unregister (disabled does not work because the value is not submitted)
" disabled=\"disabled\""); // I can not register
else // If the enrolment is not mandatory, I can select no groups
HTM_INPUT_RADIO (StrGrpCod,false,
"id=\"Grp%ld\" value=\"%ld\"%s%s"
" onclick=\"selectUnselectRadio(this,this.form.GrpCod%ld,%u)\"",
Grp->GrpCod,Grp->GrpCod,
IBelongToThisGroup ? " checked=\"checked\"" : "", // Group selected?
ICanChangeMySelectionForThisGrp ? "" :
IBelongToThisGroup ? " readonly" : // I can not unregister (disabled does not work because the value is not submitted)
" disabled=\"disabled\"", // I can not register
GrpTyp->GrpTypCod,GrpTyp->NumGrps);
}
else
/* Put a checkbox item */
2020-03-12 13:53:37 +01:00
HTM_INPUT_CHECKBOX (StrGrpCod,HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-04 20:41:35 +01:00
"id=\"Grp%ld\" value=\"%ld\"%s%s",
Grp->GrpCod,Grp->GrpCod,
IBelongToThisGroup ? " checked=\"checked\"" : "",
ICanChangeMySelectionForThisGrp ? "" :
IBelongToThisGroup ? " readonly" : // I can not unregister (disabled does not work because the value is not submitted)
" disabled=\"disabled\""); // I can not register
2017-06-20 01:58:16 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
Grp_WriteRowGrp (Grp,IBelongToThisGroup);
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/***** Free memory with the list of groups a the that belongs the user *****/
Grp_FreeListCodGrp (&LstGrpsIBelong);
2017-06-20 01:58:16 +02:00
return ICanChangeMySelectionForThisGrpTyp;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*************** Show list of groups to register/remove users ****************/
/*****************************************************************************/
2019-03-08 01:18:31 +01:00
// If UsrCod > 0 ==> mark her/his groups as checked
2014-12-01 23:55:08 +01:00
// If UsrCod <= 0 ==> do not mark any group as checked
void Grp_ShowLstGrpsToChgOtherUsrsGrps (long UsrCod)
{
2016-11-13 20:54:06 +01:00
extern const char *Hlp_USERS_Groups;
2015-02-08 18:39:58 +01:00
extern const char *Txt_Groups;
2014-12-01 23:55:08 +01:00
unsigned NumGrpTyp;
/***** Get list of groups types and groups in current course *****/
Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS);
2019-10-26 02:19:42 +02:00
/***** Begin box and table *****/
2020-03-26 02:54:30 +01:00
Box_BoxTableBegin (NULL,Txt_Groups,
NULL,NULL,
2017-06-12 15:03:29 +02:00
Hlp_USERS_Groups,Box_NOT_CLOSABLE,0);
2014-12-01 23:55:08 +01:00
/***** List to select the groups the user belongs to *****/
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps)
Grp_ListGrpsToAddOrRemUsrs (&Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp],UsrCod);
2014-12-01 23:55:08 +01:00
2017-06-12 14:16:33 +02:00
/***** End table and box *****/
2019-11-25 23:18:08 +01:00
Box_BoxTableEnd ();
2014-12-01 23:55:08 +01:00
/***** Free list of groups types and groups in current course *****/
Grp_FreeListGrpTypesAndGrps ();
}
/*****************************************************************************/
/*************** List groups of a type to add or remove users ****************/
/*****************************************************************************/
2019-03-08 01:18:31 +01:00
// If UsrCod > 0 ==> mark her/his groups as checked
2014-12-01 23:55:08 +01:00
// If UsrCod <= 0 ==> do not mark any group as checked
static void Grp_ListGrpsToAddOrRemUsrs (struct GroupType *GrpTyp,long UsrCod)
{
struct ListCodGrps LstGrpsUsrBelongs;
unsigned NumGrpThisType;
bool UsrBelongsToThisGroup;
struct Group *Grp;
2019-11-04 20:41:35 +01:00
char StrGrpCod[32];
2014-12-01 23:55:08 +01:00
/***** Write heading *****/
Grp_WriteGrpHead (GrpTyp);
2019-03-08 01:18:31 +01:00
/***** Query the groups of this type which the user belongs to *****/
2014-12-01 23:55:08 +01:00
if (UsrCod > 0)
2019-04-04 10:45:15 +02:00
Grp_GetLstCodGrpsUsrBelongs (Gbl.Hierarchy.Crs.CrsCod,GrpTyp->GrpTypCod,
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Other.UsrDat.UsrCod,&LstGrpsUsrBelongs);
/***** List the groups *****/
for (NumGrpThisType = 0;
NumGrpThisType < GrpTyp->NumGrps;
NumGrpThisType++)
{
Grp = &(GrpTyp->LstGrps[NumGrpThisType]);
UsrBelongsToThisGroup = (UsrCod > 0) ? Grp_CheckIfGrpIsInList (Grp->GrpCod,&LstGrpsUsrBelongs) :
false;
2019-03-09 22:01:06 +01:00
/* Start row */
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-03-09 22:01:06 +01:00
/* Start cell for checkbox */
2014-12-01 23:55:08 +01:00
if (UsrBelongsToThisGroup)
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM LIGHT_BLUE\"");
2019-10-08 23:28:51 +02:00
else
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
2019-03-09 22:01:06 +01:00
/* Put checkbox to select the group */
// Always checkbox, not radio, because the role in the form may be teacher,
// so if he/she is registered as teacher, he/she can belong to several groups
2019-11-04 20:41:35 +01:00
snprintf (StrGrpCod,sizeof (StrGrpCod),
"GrpCod%ld",
GrpTyp->GrpTypCod);
2020-03-12 13:53:37 +01:00
HTM_INPUT_CHECKBOX (StrGrpCod,HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-07 14:34:03 +01:00
"id=\"Grp%ld\" value=\"%ld\"%s",
2019-11-04 20:41:35 +01:00
Grp->GrpCod,Grp->GrpCod,
UsrBelongsToThisGroup ? " checked=\"checked\"" : ""); // I can not register
2019-03-09 22:01:06 +01:00
/* End cell for checkbox */
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
2019-03-09 22:01:06 +01:00
/* Write cell for group */
2014-12-01 23:55:08 +01:00
Grp_WriteRowGrp (Grp,UsrBelongsToThisGroup);
2019-03-09 22:01:06 +01:00
/* End row */
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/***** Free memory with the lists of groups *****/
if (UsrCod > 0)
Grp_FreeListCodGrp (&LstGrpsUsrBelongs);
}
/*****************************************************************************/
/******* Write a list of groups as checkbox form for unique selection ********/
/*****************************************************************************/
2017-06-23 09:56:01 +02:00
static void Grp_ListGrpsForMultipleSelection (struct GroupType *GrpTyp,
2017-07-02 18:53:35 +02:00
Grp_WhichGroups_t GroupsSelectableByStdsOrNETs)
2014-12-01 23:55:08 +01:00
{
2017-05-30 21:43:05 +02:00
extern const char *Txt_users_with_no_group;
2014-12-01 23:55:08 +01:00
unsigned NumGrpThisType;
unsigned NumGrpSel;
struct ListCodGrps LstGrpsIBelong;
bool IBelongToThisGroup;
2017-06-06 20:27:46 +02:00
bool ICanSelUnselGroup;
2019-11-04 20:41:35 +01:00
bool Checked;
2014-12-01 23:55:08 +01:00
struct Group *Grp;
2017-05-30 21:43:05 +02:00
Rol_Role_t Role;
2014-12-01 23:55:08 +01:00
/***** Write heading *****/
Grp_WriteGrpHead (GrpTyp);
/***** Query from the database the groups of this type which I belong to *****/
2019-04-04 10:45:15 +02:00
Grp_GetLstCodGrpsUsrBelongs (Gbl.Hierarchy.Crs.CrsCod,GrpTyp->GrpTypCod,
2014-12-01 23:55:08 +01:00
Gbl.Usrs.Me.UsrDat.UsrCod,&LstGrpsIBelong);
2017-06-06 20:27:46 +02:00
/***** List the groups of this type *****/
2014-12-01 23:55:08 +01:00
for (NumGrpThisType = 0;
NumGrpThisType < GrpTyp->NumGrps;
NumGrpThisType++)
{
2017-06-06 20:27:46 +02:00
/* Pointer to group */
2014-12-01 23:55:08 +01:00
Grp = &(GrpTyp->LstGrps[NumGrpThisType]);
2017-06-06 20:27:46 +02:00
/* Check if I belong to his group */
2014-12-01 23:55:08 +01:00
IBelongToThisGroup = Grp_CheckIfGrpIsInList (Grp->GrpCod,&LstGrpsIBelong);
2017-06-06 20:27:46 +02:00
/* Check if I can select / unselect this group */
if (IBelongToThisGroup)
ICanSelUnselGroup = true;
else
switch (Gbl.Usrs.Me.Role.Logged)
{
2017-07-02 18:53:35 +02:00
case Rol_STD:
2017-06-06 20:27:46 +02:00
case Rol_NET:
2017-07-02 18:53:35 +02:00
ICanSelUnselGroup = (GroupsSelectableByStdsOrNETs == Grp_ALL_GROUPS) ||
2017-06-23 09:56:01 +02:00
IBelongToThisGroup;
2017-06-06 20:27:46 +02:00
break;
case Rol_TCH:
case Rol_DEG_ADM:
case Rol_CTR_ADM:
case Rol_INS_ADM:
case Rol_SYS_ADM:
2017-07-02 18:53:35 +02:00
ICanSelUnselGroup = true; // GroupsSelectable is ignored
2017-06-06 20:27:46 +02:00
break;
default:
2017-07-02 18:53:35 +02:00
ICanSelUnselGroup = false; // GroupsSelectable is ignored
2017-06-06 20:27:46 +02:00
break;
}
2019-11-04 20:41:35 +01:00
/* This group should be checked? */
2014-12-01 23:55:08 +01:00
if (Gbl.Usrs.ClassPhoto.AllGroups)
2019-11-04 20:41:35 +01:00
Checked = true;
2014-12-01 23:55:08 +01:00
else
2019-11-04 20:41:35 +01:00
for (NumGrpSel = 0, Checked = false;
2019-04-04 10:45:15 +02:00
NumGrpSel < Gbl.Crs.Grps.LstGrpsSel.NumGrps;
2014-12-01 23:55:08 +01:00
NumGrpSel++)
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrpSel] == Grp->GrpCod)
2014-12-01 23:55:08 +01:00
{
2019-11-04 20:41:35 +01:00
Checked = true;
2014-12-01 23:55:08 +01:00
break;
}
2019-11-04 20:41:35 +01:00
/* Put checkbox to select the group */
HTM_TR_Begin (NULL);
if (IBelongToThisGroup)
HTM_TD_Begin ("class=\"LM LIGHT_BLUE\"");
2017-06-06 20:27:46 +02:00
else
2019-11-04 20:41:35 +01:00
HTM_TD_Begin ("class=\"LM\"");
2020-03-12 13:53:37 +01:00
HTM_INPUT_CHECKBOX ("GrpCods",HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-04 20:41:35 +01:00
"id=\"Grp%ld\" value=\"%ld\"%s%s",
Grp->GrpCod,Grp->GrpCod,
Checked ? " checked=\"checked\"" : "",
ICanSelUnselGroup ? " onclick=\"checkParent(this,'AllGroups')\"" :
" disabled=\"disabled\"");
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
Grp_WriteRowGrp (Grp,IBelongToThisGroup);
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/***** Free memory with the list of groups which I belongs to *****/
Grp_FreeListCodGrp (&LstGrpsIBelong);
/***** Write rows to select the students who don't belong to any group *****/
/* To get the students who don't belong to a type of group, use group code -(GrpTyp->GrpTypCod) */
/* Write checkbox to select the group */
2019-04-10 17:46:42 +02:00
ICanSelUnselGroup = (Gbl.Usrs.Me.Role.Logged >= Rol_STD);
2017-06-06 20:27:46 +02:00
if (ICanSelUnselGroup)
{
if (Gbl.Usrs.ClassPhoto.AllGroups)
2019-11-04 20:41:35 +01:00
Checked = true;
2017-06-06 20:27:46 +02:00
else
2019-11-04 20:41:35 +01:00
for (NumGrpSel = 0, Checked = false;
2019-04-04 10:45:15 +02:00
NumGrpSel < Gbl.Crs.Grps.LstGrpsSel.NumGrps;
2017-06-06 20:27:46 +02:00
NumGrpSel++)
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.LstGrpsSel.GrpCods[NumGrpSel] == -(GrpTyp->GrpTypCod))
2017-06-06 20:27:46 +02:00
{
2019-11-04 20:41:35 +01:00
Checked = true;
2017-06-06 20:27:46 +02:00
break;
}
}
2014-12-01 23:55:08 +01:00
else
2019-11-04 20:41:35 +01:00
Checked = false;
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"LM\"");
2020-03-12 13:53:37 +01:00
HTM_INPUT_CHECKBOX ("GrpCods",HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-07 10:24:00 +01:00
"id=\"Grp%ld\" value=\"%ld\"%s"
" onclick=\"checkParent(this,'AllGroups')\"",
-GrpTyp->GrpTypCod,-GrpTyp->GrpTypCod,
2019-11-04 20:41:35 +01:00
ICanSelUnselGroup ? (Checked ? " checked=\"checked\"" : "") :
2020-03-12 13:53:37 +01:00
" disabled=\"disabled\"");
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/* Column closed/open */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/* Group name = students with no group */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT LM\"");
2019-11-02 23:40:52 +01:00
HTM_LABEL_Begin ("for=\"Grp%ld\"",-GrpTyp->GrpTypCod);
2019-11-10 12:36:37 +01:00
HTM_Txt (Txt_users_with_no_group);
2019-11-02 12:59:31 +01:00
HTM_LABEL_End ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
2020-04-14 17:15:17 +02:00
/* Room */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT LM\"");
HTM_TD_End ();
2019-01-04 23:15:00 +01:00
2014-12-01 23:55:08 +01:00
/* Number of students who don't belong to any group of this type */
2019-12-26 22:29:04 +01:00
for (Role = Rol_TCH;
2017-05-30 21:43:05 +02:00
Role >= Rol_STD;
Role--)
2019-10-07 15:15:55 +02:00
{
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM\"");
2019-11-10 16:47:05 +01:00
HTM_UnsignedLong (Grp_CountNumUsrsInNoGrpsOfType (Role,GrpTyp->GrpTypCod));
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 15:15:55 +02:00
}
2014-12-01 23:55:08 +01:00
2019-10-05 13:27:58 +02:00
/* Last empty columns for max. students and vacants */
2019-10-23 19:05:05 +02:00
HTM_TD_Empty (2);
2019-10-05 13:27:58 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************** Write a row with the head for list of groups *****************/
/*****************************************************************************/
static void Grp_WriteGrpHead (struct GroupType *GrpTyp)
{
extern const char *Txt_Opening_of_groups;
extern const char *Txt_Group;
2020-04-14 17:15:17 +02:00
extern const char *Txt_Room;
2014-12-01 23:55:08 +01:00
extern const char *Txt_Max_BR_students;
2017-05-30 21:43:05 +02:00
extern const char *Txt_ROLES_PLURAL_BRIEF_Abc[Rol_NUM_ROLES];
2014-12-01 23:55:08 +01:00
extern const char *Txt_Vacants;
2015-10-26 20:02:07 +01:00
static unsigned UniqueId = 0;
2019-11-01 22:53:39 +01:00
char *Id;
2017-05-30 21:43:05 +02:00
Rol_Role_t Role;
2014-12-01 23:55:08 +01:00
/***** Name of group type *****/
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
HTM_TD_Begin ("colspan=\"9\" class=\"GRP_TITLE LM\"");
2019-11-09 21:08:20 +01:00
HTM_BR ();
2019-11-10 12:36:37 +01:00
HTM_Txt (GrpTyp->GrpTypName);
2014-12-01 23:55:08 +01:00
if (GrpTyp->MustBeOpened)
{
2015-10-26 20:02:07 +01:00
UniqueId++;
2019-11-01 22:53:39 +01:00
if (asprintf (&Id,"open_time_%u",UniqueId) < 0)
Lay_NotEnoughMemoryExit ();
2019-11-09 21:08:20 +01:00
HTM_BR ();
2020-01-11 15:22:02 +01:00
HTM_TxtColonNBSP (Txt_Opening_of_groups);
2019-11-07 10:24:00 +01:00
HTM_SPAN_Begin ("id=\"%s\"",Id);
HTM_SPAN_End ();
2019-11-01 23:35:55 +01:00
Dat_WriteLocalDateHMSFromUTC (Id,GrpTyp->OpenTimeUTC,
2019-11-02 12:10:58 +01:00
Gbl.Prefs.DateFormat,Dat_SEPARATOR_COMMA,
2019-11-02 11:45:41 +01:00
true,true,true,0x7);
2019-11-06 19:45:20 +01:00
free (Id);
2014-12-01 23:55:08 +01:00
}
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
/***** Head row with title of each column *****/
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-12 00:07:52 +02:00
2019-10-23 19:05:05 +02:00
HTM_TH_Empty (2);
HTM_TH (1,1,"LM",Txt_Group);
2020-04-14 17:15:17 +02:00
HTM_TH (1,1,"LM",Txt_Room);
2017-05-30 21:43:05 +02:00
for (Role = Rol_TCH;
Role >= Rol_STD;
Role--)
2019-10-23 19:05:05 +02:00
HTM_TH (1,1,"CM",Txt_ROLES_PLURAL_BRIEF_Abc[Role]);
HTM_TH (1,1,"CM",Txt_Max_BR_students);
HTM_TH (1,1,"CM",Txt_Vacants);
2019-10-12 00:07:52 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** Write a row with the data of a group *********************/
/*****************************************************************************/
static void Grp_WriteRowGrp (struct Group *Grp,bool Highlight)
{
extern const char *Txt_Group_X_open;
extern const char *Txt_Group_X_closed;
int Vacant;
2017-05-30 21:43:05 +02:00
Rol_Role_t Role;
2019-11-08 01:10:32 +01:00
char StrMaxStudents[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
2014-12-01 23:55:08 +01:00
/***** Write icon to show if group is open or closed *****/
if (Highlight)
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"BM LIGHT_BLUE\"");
2019-10-08 23:28:51 +02:00
else
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"BM\"");
2019-01-12 19:46:33 +01:00
Ico_PutIconOff (Grp->Open ? "unlock.svg" :
"lock.svg",
2019-12-30 21:47:07 +01:00
Str_BuildStringStr (Grp->Open ? Txt_Group_X_open :
Txt_Group_X_closed,
Grp->GrpName));
Str_FreeString ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Group name *****/
if (Highlight)
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM LIGHT_BLUE\"");
2019-10-08 23:28:51 +02:00
else
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
2019-11-02 23:40:52 +01:00
HTM_LABEL_Begin ("for=\"Grp%ld\" class=\"DAT\"",Grp->GrpCod);
2019-11-10 12:36:37 +01:00
HTM_Txt (Grp->GrpName);
2019-11-02 12:59:31 +01:00
HTM_LABEL_End ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
2020-04-14 17:15:17 +02:00
/***** Room *****/
2019-01-04 23:15:00 +01:00
if (Highlight)
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT LM LIGHT_BLUE\"");
2019-10-08 23:28:51 +02:00
else
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT LM\"");
2020-04-14 17:15:17 +02:00
HTM_Txt (Grp->Room.ShrtName);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-01-04 23:15:00 +01:00
2017-05-30 21:43:05 +02:00
/***** Current number of users in this group *****/
for (Role = Rol_TCH;
Role >= Rol_STD;
Role--)
{
if (Highlight)
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM LIGHT_BLUE\"");
2019-10-08 23:28:51 +02:00
else
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM\"");
2019-11-11 10:59:24 +01:00
HTM_Int (Grp->NumUsrs[Role]);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2017-05-30 21:43:05 +02:00
}
2014-12-01 23:55:08 +01:00
/***** Max. number of students in this group *****/
if (Highlight)
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM LIGHT_BLUE\"");
2019-10-08 23:28:51 +02:00
else
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM\"");
2019-11-03 23:59:20 +01:00
Grp_WriteMaxStds (StrMaxStudents,Grp->MaxStudents);
2019-11-11 10:59:24 +01:00
HTM_TxtF ("%s&nbsp;",StrMaxStudents);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Vacants in this group *****/
if (Highlight)
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM LIGHT_BLUE\"");
2019-10-08 23:28:51 +02:00
else
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM\"");
2017-05-30 21:43:05 +02:00
if (Grp->MaxStudents <= Grp_MAX_STUDENTS_IN_A_GROUP)
2014-12-01 23:55:08 +01:00
{
2017-05-30 21:43:05 +02:00
Vacant = (int) Grp->MaxStudents - (int) Grp->NumUsrs[Rol_STD];
2019-11-10 13:31:47 +01:00
HTM_Unsigned (Vacant > 0 ? (unsigned) Vacant :
0);
2014-12-01 23:55:08 +01:00
}
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************* Put a form to create a new group type *****************/
/*****************************************************************************/
static void Grp_PutFormToCreateGroupType (void)
{
extern const char *Txt_New_type_of_group;
extern const char *Txt_It_is_optional_to_choose_a_group;
extern const char *Txt_It_is_mandatory_to_choose_a_group;
extern const char *Txt_A_student_can_belong_to_several_groups;
extern const char *Txt_A_student_can_only_belong_to_one_group;
extern const char *Txt_The_groups_will_automatically_open;
extern const char *Txt_The_groups_will_not_automatically_open;
extern const char *Txt_Create_type_of_group;
2019-10-20 22:00:28 +02:00
/***** Begin form *****/
2019-10-26 01:56:36 +02:00
HTM_SECTION_Begin (Grp_NEW_GROUP_TYPE_SECTION_ID);
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActNewGrpTyp,Grp_GROUP_TYPES_SECTION_ID);
2014-12-01 23:55:08 +01:00
2019-10-26 02:19:42 +02:00
/***** Begin box *****/
2020-03-26 02:54:30 +01:00
Box_BoxTableBegin (NULL,Txt_New_type_of_group,
NULL,NULL,
2017-06-12 15:03:29 +02:00
NULL,Box_NOT_CLOSABLE,2);
2014-12-01 23:55:08 +01:00
/***** Write heading *****/
Grp_WriteHeadingGroupTypes ();
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-08 23:28:51 +02:00
/***** Column to remove group type, disabled here *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"BM\"");
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Name of group type *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
2019-11-04 12:25:48 +01:00
HTM_INPUT_TEXT ("GrpTypName",Grp_MAX_CHARS_GROUP_TYPE_NAME,
2020-04-27 03:16:55 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName,HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-04 09:45:57 +01:00
"size=\"12\" required=\"required\"");
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Is it mandatory to register in any groups of this type? *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2020-04-27 03:16:55 +02:00
HTM_SELECT_Begin (HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-05 15:47:35 +01:00
"name=\"MandatoryEnrolment\" style=\"width:150px;\"");
2019-11-07 01:13:21 +01:00
HTM_OPTION (HTM_Type_STRING,"N",
!Gbl.Crs.Grps.GrpTyp.MandatoryEnrolment,false,
"%s",Txt_It_is_optional_to_choose_a_group);
HTM_OPTION (HTM_Type_STRING,"Y",
Gbl.Crs.Grps.GrpTyp.MandatoryEnrolment,false,
"%s",Txt_It_is_mandatory_to_choose_a_group);
2019-11-05 08:46:38 +01:00
HTM_SELECT_End ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Is it possible to register in multiple groups of this type? *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2020-04-27 03:16:55 +02:00
HTM_SELECT_Begin (HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-05 15:47:35 +01:00
"name=\"MultipleEnrolment\" style=\"width:150px;\"");
2019-11-07 01:13:21 +01:00
HTM_OPTION (HTM_Type_STRING,"N",
!Gbl.Crs.Grps.GrpTyp.MultipleEnrolment,false,
"%s",Txt_A_student_can_only_belong_to_one_group);
HTM_OPTION (HTM_Type_STRING,"Y",
Gbl.Crs.Grps.GrpTyp.MultipleEnrolment,false,
"%s",Txt_A_student_can_belong_to_several_groups);
2019-11-05 08:46:38 +01:00
HTM_SELECT_End ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Open time *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
HTM_TABLE_BeginPadding (2);
HTM_TR_Begin (NULL);
2019-10-07 15:15:55 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\" style=\"width:20px;\"");
2019-10-29 21:41:54 +01:00
Ico_PutIcon ("clock.svg",
Gbl.Crs.Grps.GrpTyp.MustBeOpened ? Txt_The_groups_will_automatically_open :
Txt_The_groups_will_not_automatically_open,
Gbl.Crs.Grps.GrpTyp.MustBeOpened ? "CONTEXT_ICO_16x16" :
"ICO_HIDDEN CONTEXT_ICO_16x16");
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 15:15:55 +02:00
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"LM\"");
2015-10-26 20:02:07 +01:00
Dat_WriteFormClientLocalDateTimeFromTimeUTC ("open_time",
"Open",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.OpenTimeUTC,
2015-10-26 20:02:07 +01:00
Gbl.Now.Date.Year,
Gbl.Now.Date.Year + 1,
2016-12-03 20:08:01 +01:00
Dat_FORM_SECONDS_ON,
2017-02-26 20:09:21 +01:00
Dat_HMS_DO_NOT_SET, // Don't set hour, minute and second
false); // Don't submit on change
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 15:15:55 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
HTM_TABLE_End ();
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Number of groups of this type *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM\"");
2019-11-10 13:51:07 +01:00
HTM_Unsigned (0); // It's a new group type ==> 0 groups
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 15:15:55 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
2017-06-12 14:16:33 +02:00
/***** End table, send button and end box *****/
2019-11-25 23:18:08 +01:00
Box_BoxTableWithButtonEnd (Btn_CREATE_BUTTON,Txt_Create_type_of_group);
2014-12-01 23:55:08 +01:00
2015-04-11 23:46:21 +02:00
/***** End form *****/
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-26 01:56:36 +02:00
HTM_SECTION_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********************** Put a form to create a new group ********************/
/*****************************************************************************/
2020-04-14 17:15:17 +02:00
static void Grp_PutFormToCreateGroup (const struct Roo_Rooms *Rooms)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_New_group;
2015-07-22 11:18:11 +02:00
extern const char *Txt_Group_closed;
extern const char *Txt_File_zones_disabled;
2020-04-14 17:15:17 +02:00
extern const char *Txt_No_assigned_room;
extern const char *Txt_Another_room;
2014-12-01 23:55:08 +01:00
extern const char *Txt_Create_group;
unsigned NumGrpTyp;
2020-04-15 02:17:57 +02:00
unsigned NumRoo;
2017-05-30 21:43:05 +02:00
Rol_Role_t Role;
2019-11-08 01:10:32 +01:00
char StrMaxStudents[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
2014-12-01 23:55:08 +01:00
2019-10-20 22:00:28 +02:00
/***** Begin form *****/
2019-10-26 01:56:36 +02:00
HTM_SECTION_Begin (Grp_NEW_GROUP_SECTION_ID);
2018-11-09 20:47:39 +01:00
Frm_StartFormAnchor (ActNewGrp,Grp_GROUPS_SECTION_ID);
2014-12-01 23:55:08 +01:00
2019-10-26 02:19:42 +02:00
/***** Begin box and table *****/
2020-03-26 02:54:30 +01:00
Box_BoxTableBegin (NULL,Txt_New_group,
NULL,NULL,
2017-06-12 15:03:29 +02:00
NULL,Box_NOT_CLOSABLE,2);
2014-12-01 23:55:08 +01:00
/***** Write heading *****/
Grp_WriteHeadingGroups ();
2019-10-23 19:05:05 +02:00
HTM_TR_Begin (NULL);
2019-10-08 23:28:51 +02:00
/***** Empty column to remove *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"BM\"");
HTM_TD_End ();
2019-01-12 19:46:33 +01:00
/***** Disabled icon to open group *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"BM\"");
2019-01-12 19:46:33 +01:00
Ico_PutIconOff ("lock.svg",Txt_Group_closed);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-01-12 19:46:33 +01:00
/***** Disabled icon for archive zone *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"BM\"");
2019-01-12 19:46:33 +01:00
Ico_PutIconOff ("folder-red.svg",Txt_File_zones_disabled);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Group type *****/
2019-01-04 22:46:46 +01:00
/* Start selector */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2020-04-27 03:16:55 +02:00
HTM_SELECT_Begin (HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-05 15:47:35 +01:00
"name=\"GrpTypCod\" style=\"width:100px;\"");
2019-01-04 22:46:46 +01:00
/* Options for group types */
2014-12-01 23:55:08 +01:00
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
2019-11-07 01:13:21 +01:00
HTM_OPTION (HTM_Type_LONG,&Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod,
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod ==
Gbl.Crs.Grps.GrpTyp.GrpTypCod,false,
"%s",Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypName);
2019-01-04 22:46:46 +01:00
/* End selector */
2019-11-05 08:46:38 +01:00
HTM_SELECT_End ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
/***** Group name *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2020-04-27 03:16:55 +02:00
HTM_INPUT_TEXT ("GrpName",Grp_MAX_CHARS_GROUP_NAME,Gbl.Crs.Grps.GrpName,
HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-04 09:45:57 +01:00
"size=\"20\" required=\"required\"");
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2014-12-01 23:55:08 +01:00
2020-04-14 17:15:17 +02:00
/***** Room *****/
2019-01-04 22:46:46 +01:00
/* Start selector */
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2020-04-27 03:16:55 +02:00
HTM_SELECT_Begin (HTM_DONT_SUBMIT_ON_CHANGE,
2020-04-14 17:15:17 +02:00
"name=\"RooCod\" style=\"width:100px;\"");
2019-01-04 22:46:46 +01:00
2020-04-14 17:15:17 +02:00
/* Option for no assigned room */
HTM_OPTION (HTM_Type_STRING,"-1",Gbl.Crs.Grps.RooCod < 0,false,
"%s",Txt_No_assigned_room);
2019-01-04 22:46:46 +01:00
2020-04-14 17:15:17 +02:00
/* Option for another room */
HTM_OPTION (HTM_Type_STRING,"0",Gbl.Crs.Grps.RooCod == 0,false,
"%s",Txt_Another_room);
2019-01-04 22:46:46 +01:00
2020-04-14 17:15:17 +02:00
/* Options for rooms */
2020-04-15 02:17:57 +02:00
for (NumRoo = 0;
NumRoo < Rooms->Num;
NumRoo++)
HTM_OPTION (HTM_Type_LONG,&Rooms->Lst[NumRoo].RooCod,
Rooms->Lst[NumRoo].RooCod == Gbl.Crs.Grps.RooCod,false,
"%s",Rooms->Lst[NumRoo].ShrtName);
2019-01-04 22:46:46 +01:00
/* End selector */
2019-11-05 08:46:38 +01:00
HTM_SELECT_End ();
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-01-04 12:53:40 +01:00
2017-05-30 21:43:05 +02:00
/***** Current number of users in this group *****/
for (Role = Rol_TCH;
Role >= Rol_STD;
Role--)
2019-10-07 15:15:55 +02:00
{
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"DAT CM\"");
2019-11-10 13:51:07 +01:00
HTM_Unsigned (0);
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 15:15:55 +02:00
}
2017-05-30 21:43:05 +02:00
2014-12-01 23:55:08 +01:00
/***** Maximum number of students *****/
2019-10-23 19:05:05 +02:00
HTM_TD_Begin ("class=\"CM\"");
2019-11-03 23:59:20 +01:00
Grp_WriteMaxStds (StrMaxStudents,Gbl.Crs.Grps.MaxStudents);
2020-04-27 03:16:55 +02:00
HTM_INPUT_TEXT ("MaxStudents",Cns_MAX_DECIMAL_DIGITS_UINT,StrMaxStudents,
HTM_DONT_SUBMIT_ON_CHANGE,
2019-11-04 09:45:57 +01:00
"size=\"3\"");
2019-10-23 19:05:05 +02:00
HTM_TD_End ();
2019-10-07 15:15:55 +02:00
2019-10-23 19:05:05 +02:00
HTM_TR_End ();
2014-12-01 23:55:08 +01:00
2017-06-12 14:16:33 +02:00
/***** End table, send button and end box *****/
2019-11-25 23:18:08 +01:00
Box_BoxTableWithButtonEnd (Btn_CREATE_BUTTON,Txt_Create_group);
2014-12-01 23:55:08 +01:00
2017-06-12 14:16:33 +02:00
/***** End form *****/
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2019-10-26 01:56:36 +02:00
HTM_SECTION_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********** Create a list with current group types in this course ***********/
/*****************************************************************************/
void Grp_GetListGrpTypesInThisCrs (Grp_WhichGroupTypes_t WhichGroupTypes)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2018-10-31 10:19:01 +01:00
unsigned long NumGrpTyp;
2014-12-01 23:55:08 +01:00
2019-04-04 10:45:15 +02:00
if (++Gbl.Crs.Grps.GrpTypes.NestedCalls > 1) // If list is created yet, there's nothing to do
2014-12-01 23:55:08 +01:00
return;
/***** Open groups of this course that must be opened
if open time is in the past *****/
Grp_OpenGroupsAutomatically ();
/***** Get group types with groups + groups types without groups from database *****/
// The tables in the second part of the UNION requires ALIAS in order to LOCK TABLES when registering in groups
switch (WhichGroupTypes)
{
case Grp_ONLY_GROUP_TYPES_WITH_GROUPS:
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.Num =
2018-10-31 10:19:01 +01:00
(unsigned) DB_QuerySELECT (&mysql_res,"can not get types of group"
" of a course",
"SELECT crs_grp_types.GrpTypCod,crs_grp_types.GrpTypName,"
"crs_grp_types.Mandatory,crs_grp_types.Multiple,"
"crs_grp_types.MustBeOpened,"
"UNIX_TIMESTAMP(crs_grp_types.OpenTime),"
"COUNT(crs_grp.GrpCod)"
" FROM crs_grp_types,crs_grp"
" WHERE crs_grp_types.CrsCod=%ld"
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod"
" GROUP BY crs_grp_types.GrpTypCod"
" ORDER BY crs_grp_types.GrpTypName",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod);
2014-12-01 23:55:08 +01:00
break;
case Grp_ALL_GROUP_TYPES:
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.Num =
2018-10-31 10:19:01 +01:00
(unsigned) DB_QuerySELECT (&mysql_res,"can not get types of group"
" of a course",
"(SELECT crs_grp_types.GrpTypCod,crs_grp_types.GrpTypName AS GrpTypName,"
"crs_grp_types.Mandatory,crs_grp_types.Multiple,"
"crs_grp_types.MustBeOpened,"
"UNIX_TIMESTAMP(crs_grp_types.OpenTime),"
"COUNT(crs_grp.GrpCod)"
" FROM crs_grp_types,crs_grp"
" WHERE crs_grp_types.CrsCod=%ld"
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod"
" GROUP BY crs_grp_types.GrpTypCod)"
" UNION "
"(SELECT GrpTypCod,GrpTypName,"
"Mandatory,Multiple,"
"MustBeOpened,"
"UNIX_TIMESTAMP(OpenTime),"
"0"
" FROM crs_grp_types WHERE CrsCod=%ld"
" AND GrpTypCod NOT IN (SELECT GrpTypCod FROM crs_grp))"
" ORDER BY GrpTypName",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Hierarchy.Crs.CrsCod);
2014-12-01 23:55:08 +01:00
break;
}
/***** Get group types *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.NumGrpsTotal = 0;
2014-12-01 23:55:08 +01:00
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpTypes.Num)
2014-12-01 23:55:08 +01:00
{
/***** Create a list of group types *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpTypes.LstGrpTypes = (struct GroupType *) calloc (Gbl.Crs.Grps.GrpTypes.Num,sizeof (struct GroupType))) == NULL)
2018-10-18 20:06:54 +02:00
Lay_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
/***** Get group types *****/
2018-10-31 10:19:01 +01:00
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2018-10-31 10:19:01 +01:00
NumGrpTyp++)
2014-12-01 23:55:08 +01:00
{
/* Get next group type */
row = mysql_fetch_row (mysql_res);
/* Get group type code (row[0]) */
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Wrong type of group.");
/* Get group type name (row[1]) */
2019-04-04 10:45:15 +02:00
Str_Copy (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypName,row[1],
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_TYPE_NAME);
2014-12-01 23:55:08 +01:00
/* Is it mandatory to register in any groups of this type? (row[2]) */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MandatoryEnrolment = (row[2][0] == 'Y');
2014-12-01 23:55:08 +01:00
/* Is it possible to register in multiple groups of this type? (row[3]) */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MultipleEnrolment = (row[3][0] == 'Y');
2014-12-01 23:55:08 +01:00
/* Groups of this type must be opened? (row[4]) */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MustBeOpened = (row[4][0] == 'Y');
2014-12-01 23:55:08 +01:00
2015-10-26 20:02:07 +01:00
/* Get open time (row[5] holds the open time UTC) */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].OpenTimeUTC = Dat_GetUNIXTimeFromStr (row[5]);
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].MustBeOpened &= Grp_CheckIfOpenTimeInTheFuture (Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].OpenTimeUTC);
2014-12-01 23:55:08 +01:00
/* Number of groups of this type (row[6]) */
2019-04-04 10:45:15 +02:00
if (sscanf (row[6],"%u",&Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps) != 1)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Wrong number of groups of a type.");
/* Add number of groups to total number of groups */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.NumGrpsTotal += Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps;
2014-12-01 23:55:08 +01:00
/* Initialize pointer to the list of groups of this type */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].LstGrps = NULL;
2014-12-01 23:55:08 +01:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/***************** Open automatically groups in this course ******************/
/*****************************************************************************/
void Grp_OpenGroupsAutomatically (void)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumGrpTypes;
unsigned NumGrpTyp;
long GrpTypCod;
/***** Find group types to be opened *****/
2018-10-31 10:19:01 +01:00
NumGrpTypes =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get the types of group"
" to be opened",
"SELECT GrpTypCod FROM crs_grp_types"
" WHERE CrsCod=%ld AND MustBeOpened='Y'"
" AND OpenTime<=NOW()",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod);
2018-10-31 10:19:01 +01:00
2014-12-01 23:55:08 +01:00
for (NumGrpTyp = 0;
NumGrpTyp < NumGrpTypes;
NumGrpTyp++)
{
/* Get next group TYPE */
row = mysql_fetch_row (mysql_res);
if ((GrpTypCod = Str_ConvertStrCodToLongCod (row[0])) > 0)
{
/***** Open all the closed groups in this course the must be opened
and with open time in the past ****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not open groups",
"UPDATE crs_grp SET Open='Y'"
" WHERE GrpTypCod=%ld AND Open='N'",
GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** To not try to open groups again, set MustBeOpened to false *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update the opening of a type of group",
"UPDATE crs_grp_types SET MustBeOpened='N'"
" WHERE GrpTypCod=%ld",
GrpTypCod);
2014-12-01 23:55:08 +01:00
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/********* Create a list with group types and groups in this course **********/
/*****************************************************************************/
void Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_WhichGroupTypes_t WhichGroupTypes)
{
unsigned NumGrpTyp;
unsigned NumGrp;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
struct GroupType *GrpTyp;
struct Group *Grp;
2017-05-30 21:43:05 +02:00
Rol_Role_t Role;
2014-12-01 23:55:08 +01:00
/***** First we get the list of group types *****/
Grp_GetListGrpTypesInThisCrs (WhichGroupTypes);
/***** Then we get the list of groups for each group type *****/
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
{
2019-04-04 10:45:15 +02:00
GrpTyp = &Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp];
2014-12-01 23:55:08 +01:00
if (GrpTyp->NumGrps) // If there are groups of this type...
{
/***** Query database *****/
if ((NumRows = Grp_GetGrpsOfType (GrpTyp->GrpTypCod,&mysql_res)) > 0) // Groups found...
{
// NumRows should be equal to GrpTyp->NumGrps
GrpTyp->NumGrps = (unsigned) NumRows;
/***** Create list with groups of this type *****/
if ((GrpTyp->LstGrps = (struct Group *) calloc (GrpTyp->NumGrps,sizeof (struct Group))) == NULL)
2018-10-18 20:06:54 +02:00
Lay_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
/***** Get the groups of this type *****/
for (NumGrp = 0;
NumGrp < GrpTyp->NumGrps;
NumGrp++)
{
Grp = &(GrpTyp->LstGrps[NumGrp]);
/* Get next group */
row = mysql_fetch_row (mysql_res);
/* Get group code (row[0]) */
if ((Grp->GrpCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of group.");
/* Get group name (row[1]) */
2017-01-17 03:10:43 +01:00
Str_Copy (Grp->GrpName,row[1],
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_NAME);
2014-12-01 23:55:08 +01:00
2020-04-14 17:15:17 +02:00
/* Get room code (row[2]) */
Grp->Room.RooCod = Str_ConvertStrCodToLongCod (row[2]);
2017-05-30 21:43:05 +02:00
2020-04-14 17:15:17 +02:00
/* Get room short name (row[3]) */
2019-01-07 17:29:10 +01:00
if (row[3]) // May be NULL because of LEFT JOIN
2020-04-14 17:15:17 +02:00
Str_Copy (Grp->Room.ShrtName,row[3],
Roo_MAX_BYTES_SHRT_NAME);
2019-01-07 17:29:10 +01:00
else // NULL
2020-04-14 17:15:17 +02:00
Grp->Room.ShrtName[0] = '\0';
2019-01-05 11:29:54 +01:00
2017-05-30 21:43:05 +02:00
/* Get number of current users in group */
for (Role = Rol_TCH;
Role >= Rol_STD;
Role--)
Grp->NumUsrs[Role] = Grp_CountNumUsrsInGrp (Role,Grp->GrpCod);
2014-12-01 23:55:08 +01:00
2019-01-05 11:29:54 +01:00
/* Get maximum number of students in group (row[4]) */
Grp->MaxStudents = Grp_ConvertToNumMaxStdsGrp (row[4]);
2014-12-01 23:55:08 +01:00
2019-01-05 11:29:54 +01:00
/* Get whether group is open ('Y') or closed ('N') (row[5]) */
Grp->Open = (row[5][0] == 'Y');
2019-01-04 11:59:31 +01:00
2019-01-05 11:29:54 +01:00
/* Get whether group have file zones ('Y') or not ('N') (row[6]) */
Grp->FileZones = (row[6][0] == 'Y');
2014-12-01 23:55:08 +01:00
}
}
2019-01-05 11:29:54 +01:00
else // Error: groups should be found, but really they haven't be found.
// This never should happen.
2014-12-01 23:55:08 +01:00
GrpTyp->NumGrps = 0;
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
}
}
/*****************************************************************************/
/********* Free list of groups types and list of groups of each type *********/
/*****************************************************************************/
void Grp_FreeListGrpTypesAndGrps (void)
{
unsigned NumGrpTyp;
struct GroupType *GrpTyp;
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpTypes.NestedCalls > 0)
if (--Gbl.Crs.Grps.GrpTypes.NestedCalls == 0)
if (Gbl.Crs.Grps.GrpTypes.LstGrpTypes)
2014-12-01 23:55:08 +01:00
{
/***** Free memory used for each list of groups (one list for each group type) *****/
for (NumGrpTyp = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
{
2019-04-04 10:45:15 +02:00
GrpTyp = &Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp];
2014-12-01 23:55:08 +01:00
if (GrpTyp->LstGrps)
{
2019-11-06 19:45:20 +01:00
free (GrpTyp->LstGrps);
2014-12-01 23:55:08 +01:00
GrpTyp->LstGrps = NULL;
GrpTyp->NumGrps = 0;
}
}
/***** Free memory used by the list of group types *****/
2019-11-06 19:45:20 +01:00
free (Gbl.Crs.Grps.GrpTypes.LstGrpTypes);
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.LstGrpTypes = NULL;
Gbl.Crs.Grps.GrpTypes.Num = 0;
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/*********** Query the number of groups that hay in this course **************/
/*****************************************************************************/
unsigned Grp_CountNumGrpsInCurrentCrs (void)
{
/***** Get number of group in current course from database *****/
2018-11-03 20:52:00 +01:00
return
(unsigned) DB_QueryCOUNT ("can not get number of groups in this course",
"SELECT COUNT(*) FROM crs_grp_types,crs_grp"
" WHERE crs_grp_types.CrsCod=%ld"
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** Count number of groups in a group type *******************/
/*****************************************************************************/
static unsigned Grp_CountNumGrpsInThisCrsOfType (long GrpTypCod)
{
/***** Get number of groups of a type from database *****/
2018-11-03 20:52:00 +01:00
return
(unsigned) DB_QueryCOUNT ("can not get number of groups of a type",
"SELECT COUNT(*) FROM crs_grp"
" WHERE GrpTypCod=%ld",
GrpTypCod);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2019-01-04 11:59:31 +01:00
/******************** Get groups of a type in this course ********************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
unsigned long Grp_GetGrpsOfType (long GrpTypCod,MYSQL_RES **mysql_res)
{
/***** Get groups of a type from database *****/
2020-04-14 17:15:17 +02:00
// Don't use INNER JOIN because there are groups without assigned room
2018-10-31 10:19:01 +01:00
return DB_QuerySELECT (mysql_res,"can not get groups of a type",
2019-01-05 11:29:54 +01:00
"SELECT crs_grp.GrpCod,"
"crs_grp.GrpName,"
2020-04-14 17:15:17 +02:00
"crs_grp.RooCod,"
"rooms.ShortName,"
2019-01-05 11:29:54 +01:00
"crs_grp.MaxStudents,"
"crs_grp.Open,"
"crs_grp.FileZones"
2019-01-07 17:00:04 +01:00
" FROM crs_grp"
2020-04-14 17:15:17 +02:00
" LEFT JOIN rooms"
" ON crs_grp.RooCod=rooms.RooCod"
2019-01-05 11:29:54 +01:00
" WHERE crs_grp.GrpTypCod=%ld"
" ORDER BY crs_grp.GrpName",
2018-10-31 10:19:01 +01:00
GrpTypCod);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Get data of a group type from its code ******************/
/*****************************************************************************/
// GrpTyp->GrpTypCod must have the code of the type of group
static void Grp_GetDataOfGroupTypeByCod (struct GroupType *GrpTyp)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
/***** Get data of a type of group from database *****/
2019-11-11 11:20:31 +01:00
if (DB_QuerySELECT (&mysql_res,"can not get type of group",
"SELECT GrpTypName," // row[0]
"Mandatory," // row[1]
"Multiple," // row[2]
"MustBeOpened," // row[3]
"UNIX_TIMESTAMP(OpenTime)" // row[4]
2018-10-31 10:19:01 +01:00
" FROM crs_grp_types"
" WHERE CrsCod=%ld AND GrpTypCod=%ld",
2019-11-11 11:20:31 +01:00
Gbl.Hierarchy.Crs.CrsCod,GrpTyp->GrpTypCod) != 1)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Error when getting type of group.");
/***** Get some data of group type *****/
row = mysql_fetch_row (mysql_res);
2017-01-17 03:10:43 +01:00
Str_Copy (GrpTyp->GrpTypName,row[0],
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_TYPE_NAME);
2017-03-30 11:20:06 +02:00
GrpTyp->MandatoryEnrolment = (row[1][0] == 'Y');
GrpTyp->MultipleEnrolment = (row[2][0] == 'Y');
GrpTyp->MustBeOpened = (row[3][0] == 'Y');
2015-10-26 20:02:07 +01:00
GrpTyp->OpenTimeUTC = Dat_GetUNIXTimeFromStr (row[4]);
2014-12-01 23:55:08 +01:00
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
2017-03-30 11:20:06 +02:00
/************* Check if a group type has multiple enrolment *****************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2017-03-30 11:20:06 +02:00
static bool Grp_GetMultipleEnrolmentOfAGroupType (long GrpTypCod)
2014-12-01 23:55:08 +01:00
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2017-03-30 11:20:06 +02:00
bool MultipleEnrolment;
2014-12-01 23:55:08 +01:00
/***** Get data of a type of group from database *****/
2018-10-31 10:19:01 +01:00
if (DB_QuerySELECT (&mysql_res,"can not get if type of group"
" has multiple enrolment",
"SELECT Multiple FROM crs_grp_types"
" WHERE GrpTypCod=%ld",
GrpTypCod) != 1)
2019-11-11 11:20:31 +01:00
Lay_ShowErrorAndExit ("Error when getting type of enrolment.");
2014-12-01 23:55:08 +01:00
2017-03-30 11:20:06 +02:00
/***** Get multiple enrolment *****/
2014-12-01 23:55:08 +01:00
row = mysql_fetch_row (mysql_res);
2017-03-30 11:20:06 +02:00
MultipleEnrolment = (row[0][0] == 'Y');
2014-12-01 23:55:08 +01:00
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
2017-03-30 11:20:06 +02:00
return MultipleEnrolment;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************** Get data of a group from its code ********************/
/*****************************************************************************/
void Grp_GetDataOfGroupByCod (struct GroupData *GrpDat)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
2016-12-28 02:40:15 +01:00
/***** Reset values *****/
2019-01-07 17:00:04 +01:00
GrpDat->GrpTypCod = -1L;
GrpDat->CrsCod = -1L;
GrpDat->GrpTypName[0] = '\0';
GrpDat->GrpName[0] = '\0';
2020-04-14 17:15:17 +02:00
GrpDat->Room.RooCod = -1L;
GrpDat->Room.ShrtName[0] = '\0';
2019-01-07 17:00:04 +01:00
GrpDat->MaxStudents = 0;
GrpDat->Vacant = 0;
GrpDat->Open = false;
GrpDat->FileZones = false;
GrpDat->MultipleEnrolment = false;
2016-12-28 02:40:15 +01:00
if (GrpDat->GrpCod > 0)
{
/***** Get data of a group from database *****/
2018-10-31 10:19:01 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get data of a group",
2019-01-07 17:29:10 +01:00
"SELECT crs_grp.GrpTypCod," // row[0]
"crs_grp_types.CrsCod," // row[1]
"crs_grp_types.GrpTypName," // row[2]
"crs_grp_types.Multiple," // row[3]
"crs_grp.GrpName," // row[4]
2020-04-14 17:15:17 +02:00
"crs_grp.RooCod," // row[5]
"rooms.ShortName," // row[6]
2019-01-07 17:29:10 +01:00
"crs_grp.MaxStudents," // row[7]
"crs_grp.Open," // row[8]
"crs_grp.FileZones" // row[9]
2019-01-07 17:00:04 +01:00
" FROM (crs_grp,crs_grp_types)"
2020-04-14 17:15:17 +02:00
" LEFT JOIN rooms"
" ON crs_grp.RooCod=rooms.RooCod"
2018-10-31 10:19:01 +01:00
" WHERE crs_grp.GrpCod=%ld"
" AND crs_grp.GrpTypCod=crs_grp_types.GrpTypCod",
GrpDat->GrpCod);
2016-12-28 02:40:15 +01:00
if (NumRows == 1)
{
/***** Get data of group *****/
row = mysql_fetch_row (mysql_res);
2015-01-24 19:30:44 +01:00
2016-12-28 02:40:15 +01:00
/* Get the code of the group type (row[0]) */
if ((GrpDat->GrpTypCod = Str_ConvertStrCodToLongCod (row[0])) <= 0)
Lay_ShowErrorAndExit ("Wrong code of type of group.");
2015-01-24 19:30:44 +01:00
2016-12-28 02:40:15 +01:00
/* Get the code of the course (row[1]) */
if ((GrpDat->CrsCod = Str_ConvertStrCodToLongCod (row[1])) <= 0)
Lay_ShowErrorAndExit ("Wrong code of course.");
2015-01-24 19:30:44 +01:00
2016-12-28 02:40:15 +01:00
/* Get the name of the group type (row[2]) */
2017-01-17 03:10:43 +01:00
Str_Copy (GrpDat->GrpTypName,row[2],
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_TYPE_NAME);
2015-01-24 19:30:44 +01:00
2016-12-28 02:40:15 +01:00
/* Get whether a student may be in one or multiple groups (row[3]) */
2017-03-30 11:20:06 +02:00
GrpDat->MultipleEnrolment = (row[3][0] == 'Y');
2015-01-24 19:30:44 +01:00
2016-12-28 02:40:15 +01:00
/* Get the name of the group (row[4]) */
2017-01-17 03:10:43 +01:00
Str_Copy (GrpDat->GrpName,row[4],
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_NAME);
2015-01-24 19:30:44 +01:00
2019-01-04 11:59:31 +01:00
/* Get the code of the course (row[5]) */
2020-04-14 17:15:17 +02:00
GrpDat->Room.RooCod = Str_ConvertStrCodToLongCod (row[5]);
2019-01-04 11:59:31 +01:00
2020-04-14 17:15:17 +02:00
/* Get the name of the room (row[6]) */
2019-01-07 17:29:10 +01:00
if (row[6]) // May be NULL because of LEFT JOIN
2020-04-14 17:15:17 +02:00
Str_Copy (GrpDat->Room.ShrtName,row[6],
Roo_MAX_BYTES_SHRT_NAME);
2019-01-07 17:29:10 +01:00
else // NULL
2020-04-14 17:15:17 +02:00
GrpDat->Room.ShrtName[0] = '\0';
2019-01-07 17:00:04 +01:00
/* Get maximum number of students (row[7]) */
GrpDat->MaxStudents = Grp_ConvertToNumMaxStdsGrp (row[7]);
2015-01-24 19:30:44 +01:00
2019-01-07 17:00:04 +01:00
/* Get whether group is open or closed (row[8]) */
GrpDat->Open = (row[8][0] == 'Y');
2015-01-24 19:30:44 +01:00
2019-01-07 17:00:04 +01:00
/* Get whether group has file zones (row[9]) */
GrpDat->FileZones = (row[9][0] == 'Y');
2016-12-28 02:40:15 +01:00
}
2014-12-01 23:55:08 +01:00
2016-12-28 02:40:15 +01:00
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************** Get the type of group of a group *********************/
/*****************************************************************************/
static long Grp_GetTypeOfGroupOfAGroup (long GrpCod)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
long GrpTypCod;
/***** Get data of a group from database *****/
2018-10-31 10:19:01 +01:00
if (DB_QuerySELECT (&mysql_res,"can not get the type of a group",
"SELECT GrpTypCod"
" FROM crs_grp"
" WHERE GrpCod=%ld",
GrpCod) != 1)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Error when getting group.");
/***** Get data of group *****/
row = mysql_fetch_row (mysql_res);
/* Get the code of the group type (row[0]) */
if ((GrpTypCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of type of group.");
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return GrpTypCod;
}
/*****************************************************************************/
/******************** Check if a group exists in database ********************/
/*****************************************************************************/
bool Grp_CheckIfGroupExists (long GrpCod)
{
/***** Get if a group exists from database *****/
2018-11-03 20:52:00 +01:00
return (DB_QueryCOUNT ("can not check if a group exists",
2018-11-04 20:51:38 +01:00
"SELECT COUNT(*) FROM crs_grp"
" WHERE GrpCod=%ld",
2018-11-03 20:52:00 +01:00
GrpCod) != 0);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Check if a group belongs to a course ********************/
/*****************************************************************************/
bool Grp_CheckIfGroupBelongsToCourse (long GrpCod,long CrsCod)
{
/***** Get if a group exists from database *****/
2018-11-03 20:52:00 +01:00
return (DB_QueryCOUNT ("can not check if a group belongs to a course",
"SELECT COUNT(*) FROM crs_grp,crs_grp_types"
" WHERE crs_grp.GrpCod=%ld"
" AND crs_grp.GrpTypCod=crs_grp_types.GrpTypCod"
" AND crs_grp_types.CrsCod=%ld",
GrpCod,CrsCod) != 0);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2017-05-30 21:43:05 +02:00
/********************* Count number of users in a group **********************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2017-05-30 21:43:05 +02:00
unsigned Grp_CountNumUsrsInGrp (Rol_Role_t Role,long GrpCod)
2014-12-01 23:55:08 +01:00
{
/***** Get number of students in a group from database *****/
2018-11-03 20:52:00 +01:00
return
(unsigned) DB_QueryCOUNT ("can not get number of users in a group",
"SELECT COUNT(*)"
" FROM crs_grp_usr,crs_grp,crs_grp_types,crs_usr"
" WHERE crs_grp_usr.GrpCod=%ld"
" AND crs_grp_usr.GrpCod=crs_grp.GrpCod"
" AND crs_grp.GrpTypCod=crs_grp_types.GrpTypCod"
" AND crs_grp_types.CrsCod=crs_usr.CrsCod"
" AND crs_grp_usr.UsrCod=crs_usr.UsrCod"
" AND crs_usr.Role=%u",
GrpCod,(unsigned) Role);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2017-05-30 21:43:05 +02:00
/*** Count # of users of current course not belonging to groups of a type ****/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2018-10-31 10:19:01 +01:00
static unsigned long Grp_CountNumUsrsInNoGrpsOfType (Rol_Role_t Role,long GrpTypCod)
2014-12-01 23:55:08 +01:00
{
2017-05-30 21:43:05 +02:00
/***** Get number of users not belonging to groups of a type ******/
2018-10-31 10:19:01 +01:00
return DB_QueryCOUNT ("can not get the number of users"
" not belonging to groups of a type",
"SELECT COUNT(UsrCod) FROM crs_usr"
" WHERE CrsCod=%ld AND Role=%u"
" AND UsrCod NOT IN"
" (SELECT DISTINCT crs_grp_usr.UsrCod"
" FROM crs_grp,crs_grp_usr"
" WHERE crs_grp.GrpTypCod=%ld"
" AND crs_grp.GrpCod=crs_grp_usr.GrpCod)",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod,
2018-10-31 10:19:01 +01:00
(unsigned) Role,GrpTypCod);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2019-02-18 14:41:46 +01:00
/********* Check if I belong to any groups of a given type I belong **********/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2019-02-18 14:41:46 +01:00
static bool Grp_CheckIfIBelongToGrpsOfType (long GrpTypCod)
2014-12-01 23:55:08 +01:00
{
2019-02-18 14:41:46 +01:00
unsigned long NumGrps;
2014-12-01 23:55:08 +01:00
2017-06-20 01:58:16 +02:00
/***** Get a group which I belong to from database *****/
2019-02-18 14:41:46 +01:00
NumGrps = DB_QueryCOUNT ("can not check if you belong to a group type",
"SELECT COUNT(crs_grp.GrpCod)"
" FROM crs_grp,crs_grp_usr"
" WHERE crs_grp.GrpTypCod=%ld"
" AND crs_grp.GrpCod=crs_grp_usr.GrpCod"
" AND crs_grp_usr.UsrCod=%ld", // I belong
GrpTypCod,Gbl.Usrs.Me.UsrDat.UsrCod);
2014-12-01 23:55:08 +01:00
2019-02-18 14:41:46 +01:00
return (NumGrps != 0);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2017-06-20 14:43:26 +02:00
/************************ Check if I belong to a group ***********************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2017-06-20 14:43:26 +02:00
// Return true if I belong to group with code GrpCod
void Grp_FlushCacheIBelongToGrp (void)
{
Gbl.Cache.IBelongToGrp.GrpCod = -1L;
Gbl.Cache.IBelongToGrp.IBelong = false;
}
2014-12-01 23:55:08 +01:00
bool Grp_GetIfIBelongToGrp (long GrpCod)
{
2017-06-20 14:43:26 +02:00
/***** 1. Fast check: Trivial case *****/
if (GrpCod <= 0)
return false;
/***** 2. Fast check: Is already calculated if I belong to group? *****/
if (GrpCod == Gbl.Cache.IBelongToGrp.GrpCod)
return Gbl.Cache.IBelongToGrp.IBelong;
2014-12-01 23:55:08 +01:00
2017-06-20 14:43:26 +02:00
/***** 3. Slow check: Get if I belong to a group from database *****/
Gbl.Cache.IBelongToGrp.GrpCod = GrpCod;
2018-11-03 20:52:00 +01:00
Gbl.Cache.IBelongToGrp.IBelong =
(DB_QueryCOUNT ("can not check if you belong to a group",
"SELECT COUNT(*) FROM crs_grp_usr"
" WHERE GrpCod=%ld AND UsrCod=%ld",
GrpCod,Gbl.Usrs.Me.UsrDat.UsrCod) != 0);
2017-06-20 14:43:26 +02:00
return Gbl.Cache.IBelongToGrp.IBelong;
}
/*****************************************************************************/
/*************** Check if a user belongs to any of my courses ****************/
/*****************************************************************************/
void Grp_FlushCacheUsrSharesAnyOfMyGrpsInCurrentCrs (void)
{
Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.UsrCod = -1L;
Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.Shares = false;
}
bool Grp_CheckIfUsrSharesAnyOfMyGrpsInCurrentCrs (const struct UsrData *UsrDat)
{
2018-10-10 14:03:06 +02:00
bool ItsMe;
2017-06-20 14:43:26 +02:00
/***** 1. Fast check: Am I logged? *****/
if (!Gbl.Usrs.Me.Logged)
return false;
/***** 2. Fast check: Is it a valid user code? *****/
if (UsrDat->UsrCod <= 0)
return false;
/***** 3. Fast check: Is it a course selected? *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Hierarchy.Crs.CrsCod <= 0)
2017-06-20 14:43:26 +02:00
return false;
/***** 4. Fast check: Do I belong to the current course? *****/
if (!Gbl.Usrs.Me.IBelongToCurrentCrs)
return false;
/***** 5. Fast check: It's me? *****/
2018-10-10 23:56:42 +02:00
ItsMe = Usr_ItsMe (UsrDat->UsrCod);
2018-10-10 14:03:06 +02:00
if (ItsMe)
2017-06-20 14:43:26 +02:00
return true;
/***** 6. Fast check: Is already calculated if user shares
any group in the current course with me? *****/
if (UsrDat->UsrCod == Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.UsrCod)
return Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.Shares;
/***** 7. Fast / slow check: Does he/she belong to the current course? *****/
if (!Usr_CheckIfUsrBelongsToCurrentCrs (UsrDat))
{
Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.UsrCod = UsrDat->UsrCod;
Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.Shares = false;
return false;
}
2017-06-23 15:12:49 +02:00
/***** 8. Fast check: Course has groups? *****/
2019-04-04 10:45:15 +02:00
if (!Gbl.Crs.Grps.NumGrps)
2017-06-23 15:12:49 +02:00
{
Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.UsrCod = UsrDat->UsrCod;
Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.Shares = true;
return true;
}
// Course has groups
/***** 9. Slow check: Get if user shares any group in this course with me from database *****/
2017-06-20 14:43:26 +02:00
/* Check if user shares any group with me */
Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.UsrCod = UsrDat->UsrCod;
2018-11-03 20:52:00 +01:00
Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.Shares =
(DB_QueryCOUNT ("can not check if a user shares any group"
" in the current course with you",
"SELECT COUNT(*) FROM crs_grp_usr"
" WHERE UsrCod=%ld"
" AND GrpCod IN"
" (SELECT crs_grp_usr.GrpCod"
" FROM crs_grp_usr,crs_grp,crs_grp_types"
" WHERE crs_grp_usr.UsrCod=%ld"
" AND crs_grp_usr.GrpCod=crs_grp.GrpCod"
" AND crs_grp.GrpTypCod=crs_grp_types.GrpTypCod"
" AND crs_grp_types.CrsCod=%ld)",
UsrDat->UsrCod,
Gbl.Usrs.Me.UsrDat.UsrCod,
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod) != 0);
2017-06-20 14:43:26 +02:00
return Gbl.Cache.UsrSharesAnyOfMyGrpsInCurrentCrs.Shares;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2019-02-18 17:30:35 +01:00
/**** Get if any group in group-type/this-course is open and has vacants *****/
2019-02-18 02:42:15 +01:00
/*****************************************************************************/
2019-02-18 14:41:46 +01:00
// If GrpTypCod > 0 ==> restrict to the given group type, mandatory or not
// If GrpTypCod <= 0 ==> all mandatory group types in the current course
2019-02-18 02:42:15 +01:00
2019-02-18 17:30:35 +01:00
bool Grp_GetIfAvailableGrpTyp (long GrpTypCod)
2019-02-18 02:42:15 +01:00
{
2019-02-18 09:40:46 +01:00
unsigned NumGrpTypes;
2019-02-18 14:41:46 +01:00
char *SubQueryGrpTypes;
if (GrpTypCod > 0) // restrict to the given group type, mandatory or not
{
if (asprintf (&SubQueryGrpTypes,"crs_grp_types.GrpTypCod=%ld",
GrpTypCod) < 0)
Lay_NotEnoughMemoryExit ();
}
else // all mandatory group types in the current course
{
if (asprintf (&SubQueryGrpTypes,"crs_grp_types.CrsCod=%ld"
" AND crs_grp_types.Mandatory='Y'",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod) < 0)
2019-02-18 14:41:46 +01:00
Lay_NotEnoughMemoryExit ();
}
2019-02-18 02:42:15 +01:00
2019-02-18 09:40:46 +01:00
/***** Get the number of types of group in this course
with one or more open groups with vacants, from database *****/
NumGrpTypes =
(unsigned) DB_QueryCOUNT ("can not check if there has available mandatory group types",
"SELECT COUNT(GrpTypCod) FROM "
"("
2014-12-01 23:55:08 +01:00
2019-02-18 14:41:46 +01:00
// Available mandatory groups with students
"SELECT GrpTypCod FROM"
" ("
2019-02-18 09:40:46 +01:00
"SELECT crs_grp_types.GrpTypCod AS GrpTypCod,"
2018-11-03 20:52:00 +01:00
"COUNT(*) AS NumStudents,"
"crs_grp.MaxStudents as MaxStudents"
" FROM crs_grp_types,crs_grp,crs_grp_usr,crs_usr"
2019-02-18 14:41:46 +01:00
" WHERE %s" // Which group types?
2018-11-03 20:52:00 +01:00
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod"
2019-02-18 09:40:46 +01:00
" AND crs_grp.Open='Y'" // Open
2019-02-18 14:41:46 +01:00
" AND crs_grp.MaxStudents>0" // Admits students
2018-11-03 20:52:00 +01:00
" AND crs_grp_types.CrsCod=crs_usr.CrsCod"
" AND crs_grp.GrpCod=crs_grp_usr.GrpCod"
" AND crs_grp_usr.UsrCod=crs_usr.UsrCod"
2019-02-18 14:41:46 +01:00
" AND crs_usr.Role=%u" // Student
2018-11-03 20:52:00 +01:00
" GROUP BY crs_grp.GrpCod"
2019-02-18 09:40:46 +01:00
" HAVING NumStudents<MaxStudents" // Not full
2019-02-18 14:41:46 +01:00
") AS available_grp_types_with_stds"
2019-02-18 02:42:15 +01:00
2019-02-18 09:40:46 +01:00
" UNION "
2019-02-18 14:41:46 +01:00
// Available mandatory groups...
"SELECT crs_grp_types.GrpTypCod AS GrpTypCod"
2019-02-18 09:40:46 +01:00
" FROM crs_grp_types,crs_grp"
2019-02-18 14:41:46 +01:00
" WHERE %s" // Which group types?
2018-11-03 20:52:00 +01:00
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod"
2019-02-18 09:40:46 +01:00
" AND crs_grp.Open='Y'" // Open
2019-02-18 14:41:46 +01:00
" AND crs_grp.MaxStudents>0" // Admits students
// ...without students
" AND crs_grp.GrpCod NOT IN"
2019-02-18 09:40:46 +01:00
" (SELECT crs_grp_usr.GrpCod"
" FROM crs_usr,crs_grp_usr"
" WHERE crs_usr.CrsCod=%ld"
2019-02-18 14:41:46 +01:00
" AND crs_usr.Role=%u" // Student
2019-02-18 09:40:46 +01:00
" AND crs_usr.UsrCod=crs_grp_usr.UsrCod)"
2019-02-18 02:42:15 +01:00
2019-02-18 14:41:46 +01:00
") AS available_grp_types"
2019-02-18 09:40:46 +01:00
2019-02-18 14:41:46 +01:00
// ...to which I don't belong
" WHERE GrpTypCod NOT IN"
" (SELECT crs_grp_types.GrpTypCod"
" FROM crs_grp_types,crs_grp,crs_grp_usr"
" WHERE %s" // Which group types?
2018-11-03 20:52:00 +01:00
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod"
2019-02-18 17:30:35 +01:00
" AND crs_grp.Open='Y'" // Open
" AND crs_grp.MaxStudents>0" // Admits students
2018-11-03 20:52:00 +01:00
" AND crs_grp.GrpCod=crs_grp_usr.GrpCod"
2019-02-18 14:41:46 +01:00
" AND crs_grp_usr.UsrCod=%ld)", // I belong
2018-11-03 20:52:00 +01:00
2019-02-18 14:41:46 +01:00
SubQueryGrpTypes,(unsigned) Rol_STD,
SubQueryGrpTypes,
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod,(unsigned) Rol_STD,
2019-02-18 14:41:46 +01:00
SubQueryGrpTypes,Gbl.Usrs.Me.UsrDat.UsrCod);
2019-02-18 09:40:46 +01:00
2019-02-18 14:41:46 +01:00
/***** Free allocated memory for subquery *****/
2019-11-06 19:45:20 +01:00
free (SubQueryGrpTypes);
2014-12-01 23:55:08 +01:00
return (NumGrpTypes != 0);
}
/*****************************************************************************/
/****** Query list of group codes of a type to which a user belongs to *******/
/*****************************************************************************/
// If CrsCod < 0 ==> get the groups from all the user's courses
// If GrpTypCod < 0 ==> get the groups of any type
static void Grp_GetLstCodGrpsUsrBelongs (long CrsCod,long GrpTypCod,
long UsrCod,struct ListCodGrps *LstGrps)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumGrp;
/***** Get groups which a user belong to from database *****/
if (CrsCod < 0) // Query the groups from all the user's courses
2018-10-31 10:19:01 +01:00
LstGrps->NumGrps =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get the groups"
" which a user belongs to",
"SELECT GrpCod"
" FROM crs_grp_usr"
" WHERE UsrCod=%ld", // Groups will be unordered
UsrCod);
2014-12-01 23:55:08 +01:00
else if (GrpTypCod < 0) // Query the groups of any type in the course
2018-10-31 10:19:01 +01:00
LstGrps->NumGrps =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get the groups"
" which a user belongs to",
"SELECT crs_grp.GrpCod"
" FROM crs_grp_types,crs_grp,crs_grp_usr"
" WHERE crs_grp_types.CrsCod=%ld"
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod"
" AND crs_grp.GrpCod=crs_grp_usr.GrpCod"
" AND crs_grp_usr.UsrCod=%ld"
" ORDER BY crs_grp_types.GrpTypName,crs_grp.GrpName",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod,UsrCod);
2014-12-01 23:55:08 +01:00
else // Query only the groups of specified type in the course
2018-10-31 10:19:01 +01:00
LstGrps->NumGrps =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get the groups"
" which a user belongs to",
"SELECT crs_grp.GrpCod"
" FROM crs_grp_types,crs_grp,crs_grp_usr"
" WHERE crs_grp_types.CrsCod=%ld"
" AND crs_grp_types.GrpTypCod=%ld"
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod"
" AND crs_grp.GrpCod=crs_grp_usr.GrpCod"
" AND crs_grp_usr.UsrCod=%ld"
" ORDER BY crs_grp.GrpName",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod,GrpTypCod,UsrCod);
2014-12-01 23:55:08 +01:00
/***** Get the groups *****/
if (LstGrps->NumGrps)
{
/***** Create a list of groups the user belongs to *****/
2017-01-19 20:55:31 +01:00
if ((LstGrps->GrpCods = (long *) calloc (LstGrps->NumGrps,sizeof (long))) == NULL)
2018-10-18 20:06:54 +02:00
Lay_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
for (NumGrp = 0;
NumGrp < LstGrps->NumGrps;
NumGrp++)
{
row = mysql_fetch_row (mysql_res);
/* Get the code of group (row[0]) */
2017-01-19 20:55:31 +01:00
if ((LstGrps->GrpCods[NumGrp] = Str_ConvertStrCodToLongCod (row[0])) < 0)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Wrong code of group.");
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/********** Query list of group codes with file zones I belong to ************/
/*****************************************************************************/
void Grp_GetLstCodGrpsWithFileZonesIBelong (struct ListCodGrps *LstGrps)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumGrp;
/***** Get groups which I belong to from database *****/
2018-10-31 10:19:01 +01:00
LstGrps->NumGrps =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get the groups"
" which you belong to",
"SELECT crs_grp.GrpCod"
" FROM crs_grp_types,crs_grp,crs_grp_usr"
" WHERE crs_grp_types.CrsCod=%ld"
" AND crs_grp_types.GrpTypCod=crs_grp.GrpTypCod"
" AND crs_grp.FileZones='Y'"
" AND crs_grp.GrpCod=crs_grp_usr.GrpCod"
" AND crs_grp_usr.UsrCod=%ld"
" ORDER BY crs_grp_types.GrpTypName,crs_grp.GrpName",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod,Gbl.Usrs.Me.UsrDat.UsrCod);
2014-12-01 23:55:08 +01:00
/***** Get the groups *****/
if (LstGrps->NumGrps)
{
/***** Create a list of groups I belong to *****/
2017-01-19 20:55:31 +01:00
if ((LstGrps->GrpCods = (long *) calloc (LstGrps->NumGrps,sizeof (long))) == NULL)
2018-10-18 20:06:54 +02:00
Lay_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
for (NumGrp = 0;
NumGrp < LstGrps->NumGrps;
NumGrp++)
{
row = mysql_fetch_row (mysql_res);
/* Get the code of group (row[0]) */
2017-01-19 20:55:31 +01:00
if ((LstGrps->GrpCods[NumGrp] = Str_ConvertStrCodToLongCod (row[0])) < 0)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Wrong code of group.");
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/******** Check if a group is in a list of groups which I belong to **********/
/*****************************************************************************/
static bool Grp_CheckIfGrpIsInList (long GrpCod,struct ListCodGrps *LstGrps)
{
unsigned NumGrp;
for (NumGrp = 0;
NumGrp < LstGrps->NumGrps;
NumGrp++)
2017-01-19 20:55:31 +01:00
if (GrpCod == LstGrps->GrpCods[NumGrp])
2014-12-01 23:55:08 +01:00
return true;
return false;
}
/*****************************************************************************/
/********** Query names of groups of a type which user belongs to ************/
/*****************************************************************************/
void Grp_GetNamesGrpsStdBelongsTo (long GrpTypCod,long UsrCod,char *GroupNames)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2017-01-16 01:51:01 +01:00
unsigned long NumRow;
unsigned long NumRows;
2018-10-31 10:19:01 +01:00
size_t MaxLength = (Grp_MAX_BYTES_GROUP_NAME + 2) *
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.NumGrpsTotal;
2014-12-01 23:55:08 +01:00
/***** Get the names of groups which a user belongs to, from database *****/
2018-10-31 10:19:01 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get the names of groups"
" a user belongs to",
"SELECT crs_grp.GrpName"
" FROM crs_grp,crs_grp_usr"
" WHERE crs_grp.GrpTypCod=%ld"
" AND crs_grp.GrpCod=crs_grp_usr.GrpCod"
" AND crs_grp_usr.UsrCod=%ld"
" ORDER BY crs_grp.GrpName",
GrpTypCod,UsrCod);
2014-12-01 23:55:08 +01:00
/***** Get the groups *****/
GroupNames[0] = '\0';
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next group */
row = mysql_fetch_row (mysql_res);
/* El group name in row[0] */
if (NumRow)
2017-01-17 03:33:05 +01:00
Str_Concat (GroupNames,", ",
MaxLength);
Str_Concat (GroupNames,row[0],
MaxLength);
2014-12-01 23:55:08 +01:00
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/****************** Receive form to create a new group type ******************/
/*****************************************************************************/
2020-05-05 21:49:00 +02:00
void Grp_ReceiveFormNewGrpTyp (void)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_The_type_of_group_X_already_exists;
2017-04-29 02:20:34 +02:00
extern const char *Txt_Created_new_type_of_group_X;
2014-12-01 23:55:08 +01:00
extern const char *Txt_You_must_specify_the_name_of_the_new_type_of_group;
2017-05-11 23:45:46 +02:00
Ale_AlertType_t AlertType;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_TYPE_NAME];
2014-12-01 23:55:08 +01:00
/***** Get parameters from form *****/
/* Get the name of group type */
2019-04-04 10:45:15 +02:00
Par_GetParToText ("GrpTypName",Gbl.Crs.Grps.GrpTyp.GrpTypName,
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_TYPE_NAME);
2014-12-01 23:55:08 +01:00
/* Get whether it is mandatory to regisrer in any group of this type */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.MandatoryEnrolment = Par_GetParToBool ("MandatoryEnrolment");
2014-12-01 23:55:08 +01:00
/* Get whether it is possible to register in multiple groups of this type */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.MultipleEnrolment = Par_GetParToBool ("MultipleEnrolment");
2014-12-01 23:55:08 +01:00
/* Get open time */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.OpenTimeUTC = Dat_GetTimeUTCFromForm ("OpenTimeUTC");
Gbl.Crs.Grps.GrpTyp.MustBeOpened = Grp_CheckIfOpenTimeInTheFuture (Gbl.Crs.Grps.GrpTyp.OpenTimeUTC);
2014-12-01 23:55:08 +01:00
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpTyp.GrpTypName[0]) // If there's a group type name
2014-12-01 23:55:08 +01:00
{
/***** If name of group type was in database... *****/
2019-04-04 10:45:15 +02:00
if (Grp_CheckIfGroupTypeNameExists (Gbl.Crs.Grps.GrpTyp.GrpTypName,-1L))
2014-12-01 23:55:08 +01:00
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_WARNING;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_type_of_group_X_already_exists,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName);
2014-12-01 23:55:08 +01:00
}
else // Add new group type to database
2017-04-29 02:20:34 +02:00
{
2014-12-01 23:55:08 +01:00
Grp_CreateGroupType ();
2017-04-29 02:20:34 +02:00
2017-05-11 23:45:46 +02:00
AlertType = Ale_SUCCESS;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_Created_new_type_of_group_X,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName);
2017-04-29 02:20:34 +02:00
}
2014-12-01 23:55:08 +01:00
}
else // If there is not a group type name
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_WARNING;
2019-03-09 20:12:44 +01:00
Str_Copy (AlertTxt,Txt_You_must_specify_the_name_of_the_new_type_of_group,
sizeof (AlertTxt) - 1);
2014-12-01 23:55:08 +01:00
}
/***** Show the form again *****/
2019-03-09 20:12:44 +01:00
Grp_ReqEditGroupsInternal (AlertType,AlertTxt,
2017-05-11 23:45:46 +02:00
Ale_INFO,NULL);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************** Check if the open time if in the future ********************/
/*****************************************************************************/
2015-10-26 20:02:07 +01:00
static bool Grp_CheckIfOpenTimeInTheFuture (time_t OpenTimeUTC)
2014-12-01 23:55:08 +01:00
{
2015-10-26 20:02:07 +01:00
/***** If open time is 0 ==> groups must no be opened *****/
if (OpenTimeUTC == (time_t) 0)
2014-12-01 23:55:08 +01:00
return false;
/***** Is open time in the future? *****/
2015-10-27 19:00:21 +01:00
return (OpenTimeUTC > Gbl.StartExecutionTimeUTC);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************** Receive form to create a new group *********************/
/*****************************************************************************/
2020-05-05 21:49:00 +02:00
void Grp_ReceiveFormNewGrp (void)
2014-12-01 23:55:08 +01:00
{
extern const char *Txt_The_group_X_already_exists;
2017-04-28 18:03:30 +02:00
extern const char *Txt_Created_new_group_X;
2014-12-01 23:55:08 +01:00
extern const char *Txt_You_must_specify_the_name_of_the_new_group;
2017-05-11 23:45:46 +02:00
Ale_AlertType_t AlertType;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_NAME];
2014-12-01 23:55:08 +01:00
/***** Get parameters from form *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpTyp.GrpTypCod = Grp_GetParamGrpTypCod ()) > 0) // Group type valid
2014-12-01 23:55:08 +01:00
{
/* Get group name */
2019-04-04 10:45:15 +02:00
Par_GetParToText ("GrpName",Gbl.Crs.Grps.GrpName,
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_NAME);
2014-12-01 23:55:08 +01:00
2020-04-14 17:15:17 +02:00
/* Get room */
Gbl.Crs.Grps.RooCod = Roo_GetParamRooCod ();
2019-01-04 22:46:46 +01:00
2014-12-01 23:55:08 +01:00
/* Get maximum number of students */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.MaxStudents = (unsigned)
2017-01-29 21:41:08 +01:00
Par_GetParToUnsignedLong ("MaxStudents",
0,
Grp_MAX_STUDENTS_IN_A_GROUP,
Grp_NUM_STUDENTS_NOT_LIMITED);
2014-12-01 23:55:08 +01:00
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpName[0]) // If there's a group name
2014-12-01 23:55:08 +01:00
{
/***** If name of group was in database... *****/
2019-04-04 10:45:15 +02:00
if (Grp_CheckIfGroupNameExists (Gbl.Crs.Grps.GrpTyp.GrpTypCod,Gbl.Crs.Grps.GrpName,-1L))
2014-12-01 23:55:08 +01:00
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_WARNING;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_group_X_already_exists,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpName);
2014-12-01 23:55:08 +01:00
}
else // Add new group to database
2017-04-28 18:03:30 +02:00
{
2014-12-01 23:55:08 +01:00
Grp_CreateGroup ();
2017-04-28 18:03:30 +02:00
/* Write success message */
2017-05-11 23:45:46 +02:00
AlertType = Ale_SUCCESS;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_Created_new_group_X,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpName);
2017-04-28 18:03:30 +02:00
}
2014-12-01 23:55:08 +01:00
}
else // If there is not a group name
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_ERROR;
2019-03-09 20:12:44 +01:00
Str_Copy (AlertTxt,Txt_You_must_specify_the_name_of_the_new_group,
sizeof (AlertTxt) - 1);
2014-12-01 23:55:08 +01:00
}
}
else // Invalid group type
2017-04-28 18:03:30 +02:00
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_ERROR;
2019-03-09 20:12:44 +01:00
Str_Copy (AlertTxt,"Wrong type of group.",
sizeof (AlertTxt) - 1);
2017-04-28 18:03:30 +02:00
}
2014-12-01 23:55:08 +01:00
/***** Show the form again *****/
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
2019-03-09 20:12:44 +01:00
AlertType,AlertTxt);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Check if name of group type exists **********************/
/*****************************************************************************/
static bool Grp_CheckIfGroupTypeNameExists (const char *GrpTypName,long GrpTypCod)
{
/***** Get number of group types with a name from database *****/
2018-11-03 20:52:00 +01:00
return (DB_QueryCOUNT ("can not check if the name of type of group"
" already existed",
"SELECT COUNT(*) FROM crs_grp_types"
" WHERE CrsCod=%ld AND GrpTypName='%s'"
" AND GrpTypCod<>%ld",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod,GrpTypName,GrpTypCod) != 0);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************ Check if name of group exists **********************/
/*****************************************************************************/
static bool Grp_CheckIfGroupNameExists (long GrpTypCod,const char *GrpName,long GrpCod)
{
/***** Get number of groups with a type and a name from database *****/
2018-11-03 20:52:00 +01:00
return (DB_QueryCOUNT ("can not check if the name of group already existed",
"SELECT COUNT(*) FROM crs_grp"
" WHERE GrpTypCod=%ld"
" AND GrpName='%s'"
" AND GrpCod<>%ld",
GrpTypCod,GrpName,GrpCod) != 0);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************** Create a new group type **************************/
/*****************************************************************************/
static void Grp_CreateGroupType (void)
{
/***** Create a new group type *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod =
2018-11-03 01:45:36 +01:00
DB_QueryINSERTandReturnCode ("can not create type of group",
"INSERT INTO crs_grp_types"
" (CrsCod,GrpTypName,Mandatory,Multiple,MustBeOpened,OpenTime)"
" VALUES"
" (%ld,'%s','%c','%c','%c',FROM_UNIXTIME(%ld))",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod,Gbl.Crs.Grps.GrpTyp.GrpTypName,
Gbl.Crs.Grps.GrpTyp.MandatoryEnrolment ? 'Y' :
2018-11-03 01:45:36 +01:00
'N',
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.MultipleEnrolment ? 'Y' :
2018-11-03 01:45:36 +01:00
'N',
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.MustBeOpened ? 'Y' :
2018-11-03 01:45:36 +01:00
'N',
2019-04-04 10:45:15 +02:00
(long) Gbl.Crs.Grps.GrpTyp.OpenTimeUTC);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************************** Create a new group ****************************/
/*****************************************************************************/
static void Grp_CreateGroup (void)
{
2017-04-28 18:03:30 +02:00
/***** Create a new group *****/
2018-11-02 19:37:11 +01:00
DB_QueryINSERT ("can not create group",
"INSERT INTO crs_grp"
2020-04-14 17:15:17 +02:00
" (GrpTypCod,GrpName,RooCod,MaxStudents,Open,FileZones)"
2018-11-02 19:37:11 +01:00
" VALUES"
2019-01-04 22:46:46 +01:00
" (%ld,'%s',%ld,%u,'N','N')",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod,
Gbl.Crs.Grps.GrpName,
2020-04-14 17:15:17 +02:00
Gbl.Crs.Grps.RooCod,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.MaxStudents);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************* Request removing of a group type **********************/
/*****************************************************************************/
void Grp_ReqRemGroupType (void)
{
unsigned NumGrps;
/***** Get the code of the group type *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpTyp.GrpTypCod = Grp_GetParamGrpTypCod ()) < 0)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
/***** Check if this group type has groups *****/
2019-04-04 10:45:15 +02:00
if ((NumGrps = Grp_CountNumGrpsInThisCrsOfType (Gbl.Crs.Grps.GrpTyp.GrpTypCod))) // Group type has groups ==> Ask for confirmation
2014-12-01 23:55:08 +01:00
Grp_AskConfirmRemGrpTypWithGrps (NumGrps);
else // Group type has no groups ==> remove directly
Grp_RemoveGroupTypeCompletely ();
}
/*****************************************************************************/
/************************* Request removal of a group ************************/
/*****************************************************************************/
void Grp_ReqRemGroup (void)
{
/***** Get group code *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpCod = Grp_GetParamGrpCod ()) == -1L)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
/***** Confirm removing *****/
Grp_AskConfirmRemGrp ();
}
/*****************************************************************************/
/********** Ask for confirmation to remove a group type with groups **********/
/*****************************************************************************/
static void Grp_AskConfirmRemGrpTypWithGrps (unsigned NumGrps)
{
extern const char *Txt_Do_you_really_want_to_remove_the_type_of_group_X_1_group_;
extern const char *Txt_Do_you_really_want_to_remove_the_type_of_group_X_Y_groups_;
extern const char *Txt_Remove_type_of_group;
/***** Get data of the group type from database *****/
2019-04-04 10:45:15 +02:00
Grp_GetDataOfGroupTypeByCod (&Gbl.Crs.Grps.GrpTyp);
2014-12-01 23:55:08 +01:00
2017-04-29 02:20:34 +02:00
/***** Start section to edit group types *****/
Grp_ReqEditGroupsInternal0 ();
2017-04-28 14:12:37 +02:00
/***** Show question and button to remove type of group *****/
2014-12-01 23:55:08 +01:00
if (NumGrps == 1)
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton (ActRemGrpTyp,Grp_GROUP_TYPES_SECTION_ID,NULL,
2020-04-08 18:18:46 +02:00
Grp_PutParamRemGrpTyp,&Gbl.Crs.Grps.GrpTyp.GrpTypCod,
2019-02-17 01:14:55 +01:00
Btn_REMOVE_BUTTON,Txt_Remove_type_of_group,
Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_type_of_group_X_1_group_,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName);
2014-12-01 23:55:08 +01:00
else
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton (ActRemGrpTyp,Grp_GROUP_TYPES_SECTION_ID,NULL,
2020-04-08 18:18:46 +02:00
Grp_PutParamRemGrpTyp,&Gbl.Crs.Grps.GrpTyp.GrpTypCod,
2019-02-17 01:14:55 +01:00
Btn_REMOVE_BUTTON,Txt_Remove_type_of_group,
Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_type_of_group_X_Y_groups_,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName,NumGrps);
2017-04-28 14:12:37 +02:00
2017-04-29 02:20:34 +02:00
/***** Show the form to edit group types and groups again *****/
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal1 (Ale_INFO,NULL);
Grp_ReqEditGroupsInternal2 (Ale_INFO,NULL);
2017-04-28 14:12:37 +02:00
}
/*****************************************************************************/
/**************** Put parameter to remove a type of group ********************/
/*****************************************************************************/
2020-04-08 18:18:46 +02:00
static void Grp_PutParamRemGrpTyp (void *GrpTypCod)
2017-04-28 14:12:37 +02:00
{
2020-04-08 18:18:46 +02:00
if (GrpTypCod)
Grp_PutParamGrpTypCod (*((long *) GrpTypCod));
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Ask for confirmation to remove a group ******************/
/*****************************************************************************/
static void Grp_AskConfirmRemGrp (void)
{
extern const char *Txt_Do_you_really_want_to_remove_the_group_X;
extern const char *Txt_Do_you_really_want_to_remove_the_group_X_1_student_;
extern const char *Txt_Do_you_really_want_to_remove_the_group_X_Y_students_;
extern const char *Txt_Remove_group;
struct GroupData GrpDat;
unsigned NumStds;
2017-04-28 13:10:46 +02:00
/***** Get name of the group from database *****/
2019-04-04 10:45:15 +02:00
GrpDat.GrpCod = Gbl.Crs.Grps.GrpCod;
2014-12-01 23:55:08 +01:00
Grp_GetDataOfGroupByCod (&GrpDat);
2017-04-28 13:10:46 +02:00
/***** Count number of students in group *****/
2019-04-04 10:45:15 +02:00
NumStds = Grp_CountNumUsrsInGrp (Rol_STD,Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
2017-04-29 02:20:34 +02:00
/***** Show the form to edit group types again *****/
Grp_ReqEditGroupsInternal0 ();
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal1 (Ale_INFO,NULL);
2017-04-29 02:20:34 +02:00
2017-04-28 13:10:46 +02:00
/***** Show question and button to remove group *****/
2014-12-01 23:55:08 +01:00
if (NumStds == 0)
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton (ActRemGrp,Grp_GROUPS_SECTION_ID,NULL,
2020-04-08 18:18:46 +02:00
Grp_PutParamRemGrp,&Gbl.Crs.Grps.GrpCod,
2019-02-17 01:14:55 +01:00
Btn_REMOVE_BUTTON,Txt_Remove_group,
Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_group_X,
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
else if (NumStds == 1)
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton (ActRemGrp,Grp_GROUPS_SECTION_ID,NULL,
2020-04-08 18:18:46 +02:00
Grp_PutParamRemGrp,&Gbl.Crs.Grps.GrpCod,
2019-02-17 01:14:55 +01:00
Btn_REMOVE_BUTTON,Txt_Remove_group,
Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_group_X_1_student_,
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
else
2019-02-17 01:14:55 +01:00
Ale_ShowAlertAndButton (ActRemGrp,Grp_GROUPS_SECTION_ID,NULL,
2020-04-08 18:18:46 +02:00
Grp_PutParamRemGrp,&Gbl.Crs.Grps.GrpCod,
2019-02-17 01:14:55 +01:00
Btn_REMOVE_BUTTON,Txt_Remove_group,
Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_group_X_Y_students_,
GrpDat.GrpName,NumStds);
2017-04-28 13:10:46 +02:00
2017-04-29 02:20:34 +02:00
/***** Show the form to edit groups again *****/
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal2 (Ale_INFO,NULL);
2017-04-28 13:10:46 +02:00
}
/*****************************************************************************/
/*********************** Put parameter to remove a group *********************/
/*****************************************************************************/
2020-04-08 18:18:46 +02:00
static void Grp_PutParamRemGrp (void *GrpCod)
2017-04-28 13:10:46 +02:00
{
2020-04-08 18:18:46 +02:00
if (GrpCod)
Grp_PutParamGrpCod (*((long *) GrpCod));
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2017-04-28 13:10:46 +02:00
/**************************** Remove a group type ****************************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
void Grp_RemoveGroupType (void)
{
/***** Get param with code of group type *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpTyp.GrpTypCod = Grp_GetParamGrpTypCod ()) < 0)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of type of group is missing.");
/***** Remove group type and its groups *****/
Grp_RemoveGroupTypeCompletely ();
}
/*****************************************************************************/
/******************************* Remove a group ******************************/
/*****************************************************************************/
void Grp_RemoveGroup (void)
{
/***** Get param with group code *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpCod = Grp_GetParamGrpCod ()) == -1L)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
/***** Remove group *****/
Grp_RemoveGroupCompletely ();
}
/*****************************************************************************/
2017-04-29 02:20:34 +02:00
/********************* Remove a group type from database *********************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
static void Grp_RemoveGroupTypeCompletely (void)
{
extern const char *Txt_Type_of_group_X_removed;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_TYPE_NAME];
2014-12-01 23:55:08 +01:00
/***** Get name and type of the group from database *****/
2019-04-04 10:45:15 +02:00
Grp_GetDataOfGroupTypeByCod (&Gbl.Crs.Grps.GrpTyp);
2014-12-01 23:55:08 +01:00
/***** Remove file zones of all the groups of this type *****/
2019-04-04 10:45:15 +02:00
Brw_RemoveZonesOfGroupsOfType (Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Remove the associations of assignments to groups of this type *****/
2019-04-04 10:45:15 +02:00
Asg_RemoveGroupsOfType (Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Remove the associations of attendance events to groups of this type *****/
2019-04-04 10:45:15 +02:00
Att_RemoveGroupsOfType (Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
2019-09-27 20:22:32 +02:00
/***** Remove the associations of matches to groups of this type *****/
Mch_RemoveGroupsOfType (Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Remove the associations of surveys to groups of this type *****/
2019-04-04 10:45:15 +02:00
Svy_RemoveGroupsOfType (Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Change all groups of this type in course timetable *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update all groups of a type in course timetable",
"UPDATE timetable_crs SET GrpCod=-1"
" WHERE GrpCod IN"
" (SELECT GrpCod FROM crs_grp WHERE GrpTypCod=%ld)",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Remove all the students in groups of this type *****/
2018-11-02 22:00:31 +01:00
DB_QueryDELETE ("can not remove users from all groups of a type",
"DELETE FROM crs_grp_usr WHERE GrpCod IN"
" (SELECT GrpCod FROM crs_grp WHERE GrpTypCod=%ld)",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Remove all the groups of this type *****/
2018-11-02 22:00:31 +01:00
DB_QueryDELETE ("can not remove groups of a type",
"DELETE FROM crs_grp WHERE GrpTypCod=%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Remove the group type *****/
2018-11-02 22:00:31 +01:00
DB_QueryDELETE ("can not remove a type of group",
"DELETE FROM crs_grp_types WHERE GrpTypCod=%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
2018-10-16 21:56:01 +02:00
/***** Create message to show the change made *****/
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_Type_of_group_X_removed,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName);
2014-12-01 23:55:08 +01:00
/***** Show the form again *****/
2019-03-09 20:12:44 +01:00
Grp_ReqEditGroupsInternal (Ale_SUCCESS,AlertTxt,
2017-05-11 23:45:46 +02:00
Ale_INFO,NULL);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******* Remove a group from data base and remove group common zone **********/
/*****************************************************************************/
static void Grp_RemoveGroupCompletely (void)
{
extern const char *Txt_Group_X_removed;
struct GroupData GrpDat;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_NAME];
2014-12-01 23:55:08 +01:00
/***** Get name and type of the group from database *****/
2019-04-04 10:45:15 +02:00
GrpDat.GrpCod = Gbl.Crs.Grps.GrpCod;
2014-12-01 23:55:08 +01:00
Grp_GetDataOfGroupByCod (&GrpDat);
/***** Remove file zones of this group *****/
2019-04-04 10:45:15 +02:00
Brw_RemoveGrpZones (Gbl.Hierarchy.Crs.CrsCod,GrpDat.GrpCod);
2014-12-01 23:55:08 +01:00
2019-09-27 20:22:32 +02:00
/***** Remove this group from all assignments *****/
2014-12-01 23:55:08 +01:00
Asg_RemoveGroup (GrpDat.GrpCod);
2019-09-27 20:22:32 +02:00
/***** Remove this group from all attendance events *****/
2014-12-01 23:55:08 +01:00
Att_RemoveGroup (GrpDat.GrpCod);
2019-09-27 20:22:32 +02:00
/***** Remove this group from all matches *****/
Mch_RemoveGroup (GrpDat.GrpCod);
/***** Remove this group from all surveys *****/
2014-12-01 23:55:08 +01:00
Svy_RemoveGroup (GrpDat.GrpCod);
/***** Change this group in course timetable *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update a group in course timetable",
"UPDATE timetable_crs SET GrpCod=-1 WHERE GrpCod=%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
/***** Remove all the students in this group *****/
2018-11-02 22:00:31 +01:00
DB_QueryDELETE ("can not remove users from a group",
"DELETE FROM crs_grp_usr WHERE GrpCod=%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
/***** Remove the group *****/
2018-11-02 22:00:31 +01:00
DB_QueryDELETE ("can not remove a group",
"DELETE FROM crs_grp WHERE GrpCod=%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
2018-10-16 21:56:01 +02:00
/***** Create message to show the change made *****/
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_Group_X_removed,
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
/***** Show the form again *****/
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
2019-03-09 20:12:44 +01:00
Ale_SUCCESS,AlertTxt);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************************* Open a group ********************************/
/*****************************************************************************/
void Grp_OpenGroup (void)
{
extern const char *Txt_The_group_X_is_now_open;
struct GroupData GrpDat;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_NAME];
2014-12-01 23:55:08 +01:00
/***** Get group code *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpCod = Grp_GetParamGrpCod ()) == -1)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
/***** Get group data from database *****/
2019-04-04 10:45:15 +02:00
GrpDat.GrpCod = Gbl.Crs.Grps.GrpCod;
2014-12-01 23:55:08 +01:00
Grp_GetDataOfGroupByCod (&GrpDat);
/***** Update the table of groups changing open/close status *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not open a group",
"UPDATE crs_grp SET Open='Y' WHERE GrpCod=%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
2018-10-16 21:56:01 +02:00
/***** Create message to show the change made *****/
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_group_X_is_now_open,
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
/***** Show the form again *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.Open = true;
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
2019-03-09 20:12:44 +01:00
Ale_SUCCESS,AlertTxt);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************************* Close a group *******************************/
/*****************************************************************************/
void Grp_CloseGroup (void)
{
extern const char *Txt_The_group_X_is_now_closed;
struct GroupData GrpDat;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_NAME];
2014-12-01 23:55:08 +01:00
/***** Get group code *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpCod = Grp_GetParamGrpCod ()) == -1)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
/***** Get group data from database *****/
2019-04-04 10:45:15 +02:00
GrpDat.GrpCod = Gbl.Crs.Grps.GrpCod;
2014-12-01 23:55:08 +01:00
Grp_GetDataOfGroupByCod (&GrpDat);
/***** Update the table of groups changing open/close status *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not close a group",
"UPDATE crs_grp SET Open='N' WHERE GrpCod=%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
2018-10-16 21:56:01 +02:00
/***** Create message to show the change made *****/
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_group_X_is_now_closed,
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
/***** Show the form again *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.Open = false;
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
2019-03-09 20:12:44 +01:00
Ale_SUCCESS,AlertTxt);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************ Enable file zones of a group ***********************/
/*****************************************************************************/
void Grp_EnableFileZonesGrp (void)
{
extern const char *Txt_File_zones_of_the_group_X_are_now_enabled;
struct GroupData GrpDat;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_NAME];
2014-12-01 23:55:08 +01:00
/***** Get group code *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpCod = Grp_GetParamGrpCod ()) == -1)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
/***** Get group data from database *****/
2019-04-04 10:45:15 +02:00
GrpDat.GrpCod = Gbl.Crs.Grps.GrpCod;
2014-12-01 23:55:08 +01:00
Grp_GetDataOfGroupByCod (&GrpDat);
/***** Update the table of groups changing file zones status *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not enable file zones of a group",
"UPDATE crs_grp SET FileZones='Y' WHERE GrpCod=%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
2018-10-16 21:56:01 +02:00
/***** Create message to show the change made *****/
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_File_zones_of_the_group_X_are_now_enabled,
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
/***** Show the form again *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.FileZones = true;
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
2019-03-09 20:12:44 +01:00
Ale_SUCCESS,AlertTxt);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********************** Disable file zones of a group ***********************/
/*****************************************************************************/
void Grp_DisableFileZonesGrp (void)
{
extern const char *Txt_File_zones_of_the_group_X_are_now_disabled;
struct GroupData GrpDat;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_NAME];
2014-12-01 23:55:08 +01:00
/***** Get group code *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpCod = Grp_GetParamGrpCod ()) == -1)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
/***** Get group data from database *****/
2019-04-04 10:45:15 +02:00
GrpDat.GrpCod = Gbl.Crs.Grps.GrpCod;
2014-12-01 23:55:08 +01:00
Grp_GetDataOfGroupByCod (&GrpDat);
/***** Update the table of groups changing file zones status *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not disable file zones of a group",
"UPDATE crs_grp SET FileZones='N' WHERE GrpCod=%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
2018-10-16 21:56:01 +02:00
/***** Create message to show the change made *****/
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_File_zones_of_the_group_X_are_now_disabled,
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
/***** Show the form again *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.FileZones = false;
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
2019-03-09 20:12:44 +01:00
Ale_SUCCESS,AlertTxt);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********************** Change the group type of a group ********************/
/*****************************************************************************/
void Grp_ChangeGroupType (void)
{
extern const char *Txt_The_group_X_already_exists;
extern const char *Txt_The_type_of_group_of_the_group_X_has_changed;
long NewGrpTypCod;
struct GroupData GrpDat;
2017-05-11 23:45:46 +02:00
Ale_AlertType_t AlertType;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_NAME];
2014-12-01 23:55:08 +01:00
/***** Get parameters from form *****/
/* Get group code */
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpCod = Grp_GetParamGrpCod ()) == -1L)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
/* Get the new group type */
NewGrpTypCod = Grp_GetParamGrpTypCod ();
/* Get from the database the type and the name of the group */
2019-04-04 10:45:15 +02:00
GrpDat.GrpCod = Gbl.Crs.Grps.GrpCod;
2014-12-01 23:55:08 +01:00
Grp_GetDataOfGroupByCod (&GrpDat);
/***** If group was in database... *****/
if (Grp_CheckIfGroupNameExists (NewGrpTypCod,GrpDat.GrpName,-1L))
{
2018-10-16 21:56:01 +02:00
/* Create warning message */
2017-05-11 23:45:46 +02:00
AlertType = Ale_WARNING;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_group_X_already_exists,
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
}
2018-10-16 21:56:01 +02:00
else // Group is not in database
2014-12-01 23:55:08 +01:00
{
/* Update the table of groups changing old type by new type */
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update the type of a group",
"UPDATE crs_grp SET GrpTypCod=%ld WHERE GrpCod=%ld",
2019-04-04 10:45:15 +02:00
NewGrpTypCod,Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
2018-10-16 21:56:01 +02:00
/* Create message to show the change made */
2017-05-11 23:45:46 +02:00
AlertType = Ale_SUCCESS;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_type_of_group_of_the_group_X_has_changed,
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
}
/***** Show the form again *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod = NewGrpTypCod;
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
2019-03-09 20:12:44 +01:00
AlertType,AlertTxt);
2014-12-01 23:55:08 +01:00
}
2019-01-04 22:46:46 +01:00
/*****************************************************************************/
2020-04-14 17:15:17 +02:00
/************************* Change the room of a group ************************/
2019-01-04 22:46:46 +01:00
/*****************************************************************************/
2020-04-14 17:15:17 +02:00
void Grp_ChangeGroupRoom (void)
2019-01-04 22:46:46 +01:00
{
2020-04-14 17:15:17 +02:00
extern const char *Txt_The_room_assigned_to_the_group_X_has_changed;
long NewRooCod;
2019-01-04 22:46:46 +01:00
struct GroupData GrpDat;
Ale_AlertType_t AlertType;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_NAME];
2019-01-04 22:46:46 +01:00
/***** Get parameters from form *****/
/* Get group code */
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpCod = Grp_GetParamGrpCod ()) == -1L)
2019-01-04 22:46:46 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
2020-04-14 17:15:17 +02:00
/* Get the new room */
NewRooCod = Roo_GetParamRooCod ();
2019-01-04 22:46:46 +01:00
/* Get from the database the name of the group */
2019-04-04 10:45:15 +02:00
GrpDat.GrpCod = Gbl.Crs.Grps.GrpCod;
2019-01-04 22:46:46 +01:00
Grp_GetDataOfGroupByCod (&GrpDat);
2020-04-14 17:15:17 +02:00
/***** Update the table of groups changing old room by new room *****/
DB_QueryUPDATE ("can not update the room of a group",
"UPDATE crs_grp SET RooCod=%ld WHERE GrpCod=%ld",
NewRooCod,Gbl.Crs.Grps.GrpCod);
2019-01-04 22:46:46 +01:00
/* Create message to show the change made */
AlertType = Ale_SUCCESS;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2020-04-14 17:15:17 +02:00
Txt_The_room_assigned_to_the_group_X_has_changed,
2019-01-04 22:46:46 +01:00
GrpDat.GrpName);
/***** Show the form again *****/
2020-04-14 17:15:17 +02:00
Gbl.Crs.Grps.RooCod = NewRooCod;
2019-01-04 22:46:46 +01:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
2019-03-09 20:12:44 +01:00
AlertType,AlertTxt);
2019-01-04 22:46:46 +01:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/************ Change mandatory registration to a group of a type *************/
/*****************************************************************************/
void Grp_ChangeMandatGrpTyp (void)
{
2017-03-30 11:20:06 +02:00
extern const char *Txt_The_type_of_enrolment_of_the_type_of_group_X_has_not_changed;
extern const char *Txt_The_enrolment_of_students_into_groups_of_type_X_is_now_mandatory;
extern const char *Txt_The_enrolment_of_students_into_groups_of_type_X_is_now_voluntary;
bool NewMandatoryEnrolment;
2017-05-11 23:45:46 +02:00
Ale_AlertType_t AlertType;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_TYPE_NAME];
2014-12-01 23:55:08 +01:00
/***** Get parameters of the form *****/
/* Get the c<>digo of type of group */
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpTyp.GrpTypCod = Grp_GetParamGrpTypCod ()) < 0)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of type of group is missing.");
2017-03-30 11:20:06 +02:00
/* Get the new type of enrolment (mandatory or voluntaria) of this type of group */
NewMandatoryEnrolment = Par_GetParToBool ("MandatoryEnrolment");
2014-12-01 23:55:08 +01:00
2017-03-30 11:20:06 +02:00
/* Get from the database the name of the type and the old type of enrolment */
2019-04-04 10:45:15 +02:00
Grp_GetDataOfGroupTypeByCod (&Gbl.Crs.Grps.GrpTyp);
2014-12-01 23:55:08 +01:00
2017-03-30 11:20:06 +02:00
/***** Check if the old type of enrolment match the new
2019-01-02 15:10:51 +01:00
(this happens when return is pressed without changes) *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpTyp.MandatoryEnrolment == NewMandatoryEnrolment)
2014-12-01 23:55:08 +01:00
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_INFO;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_type_of_enrolment_of_the_type_of_group_X_has_not_changed,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName);
2014-12-01 23:55:08 +01:00
}
else
{
2017-03-30 11:20:06 +02:00
/***** Update of the table of types of group changing the old type of enrolment by the new *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update enrolment type of a type of group",
2019-11-06 22:47:12 +01:00
"UPDATE crs_grp_types SET Mandatory='%c'"
" WHERE GrpTypCod=%ld",
2018-11-03 12:16:40 +01:00
NewMandatoryEnrolment ? 'Y' :
'N',
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Write message to show the change made *****/
2017-05-11 23:45:46 +02:00
AlertType = Ale_SUCCESS;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
NewMandatoryEnrolment ? Txt_The_enrolment_of_students_into_groups_of_type_X_is_now_mandatory :
Txt_The_enrolment_of_students_into_groups_of_type_X_is_now_voluntary,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName);
2014-12-01 23:55:08 +01:00
}
/***** Show the form again *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.MandatoryEnrolment = NewMandatoryEnrolment;
2019-03-09 20:12:44 +01:00
Grp_ReqEditGroupsInternal (AlertType,AlertTxt,
2017-05-11 23:45:46 +02:00
Ale_INFO,NULL);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2017-03-30 11:20:06 +02:00
/******** Change multiple enrolment to one or more groups of a type *********/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
void Grp_ChangeMultiGrpTyp (void)
{
2017-03-30 11:20:06 +02:00
extern const char *Txt_The_type_of_enrolment_of_the_type_of_group_X_has_not_changed;
2014-12-01 23:55:08 +01:00
extern const char *Txt_Now_each_student_can_belong_to_multiple_groups_of_type_X;
extern const char *Txt_Now_each_student_can_only_belong_to_a_group_of_type_X;
2017-03-30 11:20:06 +02:00
bool NewMultipleEnrolment;
2017-05-11 23:45:46 +02:00
Ale_AlertType_t AlertType;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_TYPE_NAME];
2014-12-01 23:55:08 +01:00
/***** Get parameters from the form *****/
/* Get the code of type of group */
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpTyp.GrpTypCod = Grp_GetParamGrpTypCod ()) < 0)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of type of group is missing.");
2017-03-30 11:20:06 +02:00
/* Get the new type of enrolment (single or multiple) of this type of group */
NewMultipleEnrolment = Par_GetParToBool ("MultipleEnrolment");
2014-12-01 23:55:08 +01:00
2017-03-30 11:20:06 +02:00
/* Get from the database the name of the type and the old type of enrolment */
2019-04-04 10:45:15 +02:00
Grp_GetDataOfGroupTypeByCod (&Gbl.Crs.Grps.GrpTyp);
2014-12-01 23:55:08 +01:00
2017-03-30 11:20:06 +02:00
/***** Check if the old type of enrolment match the new one
2014-12-01 23:55:08 +01:00
(this happends when return is pressed without changes) *****/
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.Grps.GrpTyp.MultipleEnrolment == NewMultipleEnrolment)
2014-12-01 23:55:08 +01:00
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_INFO;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_type_of_enrolment_of_the_type_of_group_X_has_not_changed,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName);
2014-12-01 23:55:08 +01:00
}
else
{
2017-03-30 11:20:06 +02:00
/***** Update of the table of types of group changing the old type of enrolment by the new *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update enrolment type of a type of group",
"UPDATE crs_grp_types SET Multiple='%c'"
" WHERE GrpTypCod=%ld",
NewMultipleEnrolment ? 'Y' :
'N',
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Write message to show the change made *****/
2017-05-11 23:45:46 +02:00
AlertType = Ale_SUCCESS;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
NewMultipleEnrolment ? Txt_Now_each_student_can_belong_to_multiple_groups_of_type_X :
Txt_Now_each_student_can_only_belong_to_a_group_of_type_X,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName);
2014-12-01 23:55:08 +01:00
}
/***** Show the form again *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.MultipleEnrolment = NewMultipleEnrolment;
2019-03-09 20:12:44 +01:00
Grp_ReqEditGroupsInternal (AlertType,AlertTxt,
2017-05-11 23:45:46 +02:00
Ale_INFO,NULL);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** Change open time for a type of group *********************/
/*****************************************************************************/
void Grp_ChangeOpenTimeGrpTyp (void)
{
extern const char *Txt_The_date_time_of_opening_of_groups_has_changed;
/***** Get the code of type of group *****/
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpTyp.GrpTypCod = Grp_GetParamGrpTypCod ()) < 0)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of type of group is missing.");
/***** Get from the database the data of this type of group *****/
2019-04-04 10:45:15 +02:00
Grp_GetDataOfGroupTypeByCod (&Gbl.Crs.Grps.GrpTyp);
2014-12-01 23:55:08 +01:00
/***** Get open time *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.OpenTimeUTC = Dat_GetTimeUTCFromForm ("OpenTimeUTC");
Gbl.Crs.Grps.GrpTyp.MustBeOpened = Grp_CheckIfOpenTimeInTheFuture (Gbl.Crs.Grps.GrpTyp.OpenTimeUTC);
2014-12-01 23:55:08 +01:00
2016-04-30 17:16:41 +02:00
/***** Update the table of types of group
2017-03-30 11:20:06 +02:00
changing the old open time of enrolment by the new *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update enrolment type of a type of group",
"UPDATE crs_grp_types"
" SET MustBeOpened='%c',OpenTime=FROM_UNIXTIME(%ld)"
" WHERE GrpTypCod=%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.MustBeOpened ? 'Y' :
2018-11-03 12:16:40 +01:00
'N',
2019-04-04 10:45:15 +02:00
(long) Gbl.Crs.Grps.GrpTyp.OpenTimeUTC,
Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Write message to show the change made *****/
2019-02-16 16:18:54 +01:00
Ale_ShowAlert (Ale_SUCCESS,Txt_The_date_time_of_opening_of_groups_has_changed);
2014-12-01 23:55:08 +01:00
/***** Show the form again *****/
2019-03-09 20:12:44 +01:00
Grp_ReqEditGroupsInternal (Ale_SUCCESS,NULL,
2017-05-11 23:45:46 +02:00
Ale_INFO,NULL);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************** Change maximum of students in a group *********************/
/*****************************************************************************/
void Grp_ChangeMaxStdsGrp (void)
{
2019-01-02 22:06:29 +01:00
extern const char *Txt_The_maximum_number_of_students_in_group_X_has_not_changed;
2019-01-02 15:10:51 +01:00
extern const char *Txt_The_group_X_does_not_have_a_student_limit_now;
2019-01-02 22:06:29 +01:00
extern const char *Txt_The_maximum_number_of_students_in_group_X_is_now_Y;
2014-12-01 23:55:08 +01:00
struct GroupData GrpDat;
unsigned NewMaxStds;
2017-05-11 23:45:46 +02:00
Ale_AlertType_t AlertType;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_NAME];
2014-12-01 23:55:08 +01:00
/***** Get parameters of the form *****/
/* Get group code */
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpCod = Grp_GetParamGrpCod ()) == -1)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
/* Get the new maximum number of students of the group */
2017-01-29 21:41:08 +01:00
NewMaxStds = (unsigned)
Par_GetParToUnsignedLong ("MaxStudents",
0,
Grp_MAX_STUDENTS_IN_A_GROUP,
Grp_NUM_STUDENTS_NOT_LIMITED);
2014-12-01 23:55:08 +01:00
2019-01-02 15:10:51 +01:00
/* Get from the database the type, name, and old maximum of students of the group */
2019-04-04 10:45:15 +02:00
GrpDat.GrpCod = Gbl.Crs.Grps.GrpCod;
2014-12-01 23:55:08 +01:00
Grp_GetDataOfGroupByCod (&GrpDat);
2019-01-02 15:10:51 +01:00
/***** Check if the old maximum of students equals the new one
(this happens when return is pressed without changes) *****/
2014-12-01 23:55:08 +01:00
if (GrpDat.MaxStudents == NewMaxStds)
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_INFO;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2019-01-02 22:06:29 +01:00
Txt_The_maximum_number_of_students_in_group_X_has_not_changed,
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
}
else
{
/***** Update the table of groups changing the old maximum of students to the new *****/
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update the maximum number of students"
" in a group",
"UPDATE crs_grp SET MaxStudents=%u WHERE GrpCod=%ld",
2019-04-04 10:45:15 +02:00
NewMaxStds,Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
/***** Write message to show the change made *****/
2017-05-11 23:45:46 +02:00
AlertType = Ale_SUCCESS;
2017-01-29 12:42:19 +01:00
if (NewMaxStds > Grp_MAX_STUDENTS_IN_A_GROUP)
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2019-01-02 15:10:51 +01:00
Txt_The_group_X_does_not_have_a_student_limit_now,
2018-10-16 21:56:01 +02:00
GrpDat.GrpName);
2014-12-01 23:55:08 +01:00
else
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2019-01-02 22:06:29 +01:00
Txt_The_maximum_number_of_students_in_group_X_is_now_Y,
GrpDat.GrpName,NewMaxStds);
2014-12-01 23:55:08 +01:00
}
/***** Show the form again *****/
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.MaxStudents = NewMaxStds;
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
2019-03-09 20:12:44 +01:00
AlertType,AlertTxt);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2019-01-02 15:10:51 +01:00
/************* Write the maximum number of students in a group ***************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2019-11-08 01:10:32 +01:00
static void Grp_WriteMaxStds (char Str[Cns_MAX_DECIMAL_DIGITS_UINT + 1],unsigned MaxStudents)
2014-12-01 23:55:08 +01:00
{
2017-05-30 21:43:05 +02:00
if (MaxStudents <= Grp_MAX_STUDENTS_IN_A_GROUP)
2019-11-08 01:10:32 +01:00
snprintf (Str,Cns_MAX_DECIMAL_DIGITS_UINT + 1,
2019-11-03 23:59:20 +01:00
"%u",
MaxStudents);
else
Str[0] = '\0';
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********* Convert string to maximum number of students in a group ***********/
/*****************************************************************************/
unsigned Grp_ConvertToNumMaxStdsGrp (const char *StrMaxStudents)
{
unsigned MaxStudents;
if (sscanf (StrMaxStudents,"%u",&MaxStudents) != 1)
2017-01-29 12:42:19 +01:00
return Grp_NUM_STUDENTS_NOT_LIMITED;
2014-12-01 23:55:08 +01:00
else if (MaxStudents > Grp_MAX_STUDENTS_IN_A_GROUP)
2017-01-29 12:42:19 +01:00
return Grp_NUM_STUDENTS_NOT_LIMITED;
2014-12-01 23:55:08 +01:00
return MaxStudents;
}
/*****************************************************************************/
/***************************** Rename a group type ***************************/
/*****************************************************************************/
void Grp_RenameGroupType (void)
{
2019-12-20 00:30:54 +01:00
extern const char *Txt_You_can_not_leave_the_field_empty;
2014-12-01 23:55:08 +01:00
extern const char *Txt_The_type_of_group_X_already_exists;
extern const char *Txt_The_type_of_group_X_has_been_renamed_as_Y;
extern const char *Txt_The_name_of_the_type_of_group_X_has_not_changed;
2017-03-07 11:03:05 +01:00
char NewNameGrpTyp[Grp_MAX_BYTES_GROUP_TYPE_NAME + 1];
2017-05-11 23:45:46 +02:00
Ale_AlertType_t AlertType;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_TYPE_NAME];
2014-12-01 23:55:08 +01:00
/***** Get parameters from form *****/
/* Get the code of the group type */
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpTyp.GrpTypCod = Grp_GetParamGrpTypCod ()) < 0)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of type of group is missing.");
/* Get the new name for the group type */
2017-03-07 11:03:05 +01:00
Par_GetParToText ("GrpTypName",NewNameGrpTyp,Grp_MAX_BYTES_GROUP_TYPE_NAME);
2014-12-01 23:55:08 +01:00
/***** Get from the database the old name of the group type *****/
2019-04-04 10:45:15 +02:00
Grp_GetDataOfGroupTypeByCod (&Gbl.Crs.Grps.GrpTyp);
2014-12-01 23:55:08 +01:00
/***** Check if new name is empty *****/
2019-12-20 00:30:54 +01:00
if (NewNameGrpTyp[0])
2014-12-01 23:55:08 +01:00
{
2019-01-02 15:10:51 +01:00
/***** Check if old and new names are the same
(this happens when return is pressed without changes) *****/
2019-04-04 10:45:15 +02:00
if (strcmp (Gbl.Crs.Grps.GrpTyp.GrpTypName,NewNameGrpTyp)) // Different names
2014-12-01 23:55:08 +01:00
{
/***** If group type was in database... *****/
2019-04-04 10:45:15 +02:00
if (Grp_CheckIfGroupTypeNameExists (NewNameGrpTyp,Gbl.Crs.Grps.GrpTyp.GrpTypCod))
2014-12-01 23:55:08 +01:00
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_WARNING;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_type_of_group_X_already_exists,
NewNameGrpTyp);
2014-12-01 23:55:08 +01:00
}
else
{
/* Update the table changing old name by new name */
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update the type of a group",
"UPDATE crs_grp_types SET GrpTypName='%s'"
" WHERE GrpTypCod=%ld",
NewNameGrpTyp,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypCod);
2014-12-01 23:55:08 +01:00
/***** Write message to show the change made *****/
2017-05-11 23:45:46 +02:00
AlertType = Ale_SUCCESS;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_type_of_group_X_has_been_renamed_as_Y,
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTyp.GrpTypName,NewNameGrpTyp);
2014-12-01 23:55:08 +01:00
}
}
else // The same name
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_INFO;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_name_of_the_type_of_group_X_has_not_changed,
NewNameGrpTyp);
2014-12-01 23:55:08 +01:00
}
}
2019-12-20 00:30:54 +01:00
else
{
AlertType = Ale_WARNING;
Str_Copy (AlertTxt,Txt_You_can_not_leave_the_field_empty,
sizeof (AlertTxt) - 1);
}
2014-12-01 23:55:08 +01:00
/***** Show the form again *****/
2019-04-04 10:45:15 +02:00
Str_Copy (Gbl.Crs.Grps.GrpTyp.GrpTypName,NewNameGrpTyp,
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_TYPE_NAME);
2019-03-09 20:12:44 +01:00
Grp_ReqEditGroupsInternal (AlertType,AlertTxt,
2017-05-11 23:45:46 +02:00
Ale_INFO,NULL);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************************* Rename a group ******************************/
/*****************************************************************************/
void Grp_RenameGroup (void)
{
2019-12-20 00:30:54 +01:00
extern const char *Txt_You_can_not_leave_the_field_empty;
2014-12-01 23:55:08 +01:00
extern const char *Txt_The_group_X_already_exists;
extern const char *Txt_The_group_X_has_been_renamed_as_Y;
extern const char *Txt_The_name_of_the_group_X_has_not_changed;
struct GroupData GrpDat;
2017-03-07 11:03:05 +01:00
char NewNameGrp[Grp_MAX_BYTES_GROUP_NAME + 1];
2017-05-11 23:45:46 +02:00
Ale_AlertType_t AlertType;
2019-03-09 20:12:44 +01:00
char AlertTxt[256 + Grp_MAX_BYTES_GROUP_NAME];
2014-12-01 23:55:08 +01:00
/***** Get parameters from form *****/
/* Get the code of the group */
2019-04-04 10:45:15 +02:00
if ((Gbl.Crs.Grps.GrpCod = Grp_GetParamGrpCod ()) == -1L)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Code of group is missing.");
/* Get the new name for the group */
2017-03-07 11:03:05 +01:00
Par_GetParToText ("GrpName",NewNameGrp,Grp_MAX_BYTES_GROUP_NAME);
2014-12-01 23:55:08 +01:00
/***** Get from the database the type and the old name of the group *****/
2019-04-04 10:45:15 +02:00
GrpDat.GrpCod = Gbl.Crs.Grps.GrpCod;
2014-12-01 23:55:08 +01:00
Grp_GetDataOfGroupByCod (&GrpDat);
/***** Check if new name is empty *****/
if (!NewNameGrp[0])
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_WARNING;
2019-12-20 00:30:54 +01:00
Str_Copy (AlertTxt,Txt_You_can_not_leave_the_field_empty,
sizeof (AlertTxt) - 1);
2014-12-01 23:55:08 +01:00
}
else
{
2019-01-02 15:10:51 +01:00
/***** Check if old and new names are the same
(this happens when return is pressed without changes) *****/
2014-12-01 23:55:08 +01:00
if (strcmp (GrpDat.GrpName,NewNameGrp)) // Different names
{
/***** If group was in database... *****/
2019-04-04 10:45:15 +02:00
if (Grp_CheckIfGroupNameExists (GrpDat.GrpTypCod,NewNameGrp,Gbl.Crs.Grps.GrpCod))
2014-12-01 23:55:08 +01:00
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_WARNING;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_group_X_already_exists,
NewNameGrp);
2014-12-01 23:55:08 +01:00
}
else
{
/* Update the table changing old name by new name */
2018-11-03 12:16:40 +01:00
DB_QueryUPDATE ("can not update the name of a group",
"UPDATE crs_grp SET GrpName='%s' WHERE GrpCod=%ld",
2019-04-04 10:45:15 +02:00
NewNameGrp,Gbl.Crs.Grps.GrpCod);
2014-12-01 23:55:08 +01:00
/***** Write message to show the change made *****/
2017-05-11 23:45:46 +02:00
AlertType = Ale_SUCCESS;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_group_X_has_been_renamed_as_Y,
GrpDat.GrpName,NewNameGrp);
2014-12-01 23:55:08 +01:00
}
}
else // The same name
{
2017-05-11 23:45:46 +02:00
AlertType = Ale_INFO;
2019-03-09 20:12:44 +01:00
snprintf (AlertTxt,sizeof (AlertTxt),
2018-10-16 21:56:01 +02:00
Txt_The_name_of_the_group_X_has_not_changed,
NewNameGrp);
2014-12-01 23:55:08 +01:00
}
}
/***** Show the form again *****/
2019-04-04 10:45:15 +02:00
Str_Copy (Gbl.Crs.Grps.GrpName,NewNameGrp,
2017-03-07 11:03:05 +01:00
Grp_MAX_BYTES_GROUP_NAME);
2017-05-11 23:45:46 +02:00
Grp_ReqEditGroupsInternal (Ale_INFO,NULL,
2019-03-09 20:12:44 +01:00
AlertType,AlertTxt);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Get parameter with code of group type *******************/
/*****************************************************************************/
static long Grp_GetParamGrpTypCod (void)
{
2017-01-28 20:32:50 +01:00
/***** Get code of group type *****/
return Par_GetParToLong ("GrpTypCod");
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********************** Get parameter with group code ***********************/
/*****************************************************************************/
static long Grp_GetParamGrpCod (void)
{
2017-01-28 20:32:50 +01:00
/***** Get group code *****/
return Par_GetParToLong ("GrpCod");
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** Write parameter with code of group type ******************/
/*****************************************************************************/
static void Grp_PutParamGrpTypCod (long GrpTypCod)
{
2019-11-03 13:19:32 +01:00
Par_PutHiddenParamLong (NULL,"GrpTypCod",GrpTypCod);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************* Write parameter with code of group ********************/
/*****************************************************************************/
void Grp_PutParamGrpCod (long GrpCod)
{
2019-11-03 13:19:32 +01:00
Par_PutHiddenParamLong (NULL,"GrpCod",GrpCod);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/************************ Get list of group codes selected *******************/
/*****************************************************************************/
void Grp_GetLstCodsGrpWanted (struct ListCodGrps *LstGrpsWanted)
{
unsigned NumGrpTyp;
2019-11-08 01:10:32 +01:00
char Param[6 + Cns_MAX_DECIMAL_DIGITS_LONG + 1];
char LongStr[1 + Cns_MAX_DECIMAL_DIGITS_LONG + 1];
2014-12-01 23:55:08 +01:00
char **LstStrCodGrps;
const char *Ptr;
unsigned NumGrpWanted;
/***** Allocate memory for the strings with group codes in each type *****/
2019-04-04 10:45:15 +02:00
if ((LstStrCodGrps = (char **) calloc (Gbl.Crs.Grps.GrpTypes.Num,sizeof (char *))) == NULL)
2018-10-18 20:06:54 +02:00
Lay_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
/***** Get lists with the groups that I want in each type
in order to count the total number of groups selected *****/
for (NumGrpTyp = 0, LstGrpsWanted->NumGrps = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
{
/***** Allocate memory for the list of group codes of this type *****/
2019-11-08 01:10:32 +01:00
if ((LstStrCodGrps[NumGrpTyp] = (char *) malloc ((size_t) ((Cns_MAX_DECIMAL_DIGITS_LONG + 1) *
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps))) == NULL)
2018-10-18 20:06:54 +02:00
Lay_NotEnoughMemoryExit ();
2014-12-01 23:55:08 +01:00
/***** Get the multiple parameter code of group of this type *****/
2018-10-18 02:02:32 +02:00
snprintf (Param,sizeof (Param),
"GrpCod%ld",
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypCod);
2017-01-28 15:58:46 +01:00
Par_GetParMultiToText (Param,LstStrCodGrps[NumGrpTyp],
2019-11-08 01:10:32 +01:00
((Cns_MAX_DECIMAL_DIGITS_LONG + 1) * Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].NumGrps) - 1);
2014-12-01 23:55:08 +01:00
if (LstStrCodGrps[NumGrpTyp][0])
{
/***** Count the number of groups selected of this type of LstCodGrps[NumGrpTyp] *****/
for (Ptr = LstStrCodGrps[NumGrpTyp], NumGrpWanted = 0;
*Ptr;
NumGrpWanted++)
2019-11-08 01:10:32 +01:00
Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2014-12-01 23:55:08 +01:00
/***** Add the number of groups selected of this type to the number of groups selected total *****/
LstGrpsWanted->NumGrps += NumGrpWanted;
}
}
/***** Create the list (argument passed to this function)
with all the groups selected (of all the types) *****/
if (LstGrpsWanted->NumGrps)
{
2017-01-19 20:55:31 +01:00
if ((LstGrpsWanted->GrpCods = (long *) calloc (LstGrpsWanted->NumGrps,sizeof (long))) == NULL)
2017-03-30 11:20:06 +02:00
Lay_ShowErrorAndExit ("Not enoguh memory to store codes of groups in which a user wants to be enroled.");
2014-12-01 23:55:08 +01:00
/***** Get the groups *****/
for (NumGrpTyp = 0, NumGrpWanted = 0;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
{
/* Add the groups selected of this type to the complete list of groups selected */
for (Ptr = LstStrCodGrps[NumGrpTyp];
*Ptr;
NumGrpWanted++)
{
2019-11-08 01:10:32 +01:00
Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
2017-01-19 20:55:31 +01:00
LstGrpsWanted->GrpCods[NumGrpWanted] = Str_ConvertStrCodToLongCod (LongStr);
2014-12-01 23:55:08 +01:00
}
/* Free memory used by the list of group codes of this type */
2019-11-06 19:45:20 +01:00
free (LstStrCodGrps[NumGrpTyp]);
2014-12-01 23:55:08 +01:00
}
}
/***** Free memory used by the lists of group codes of each type *****/
2019-11-06 19:45:20 +01:00
free (LstStrCodGrps);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
2016-12-29 22:19:46 +01:00
/************************** Free list of group codes *************************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
void Grp_FreeListCodGrp (struct ListCodGrps *LstGrps)
{
2017-01-19 20:55:31 +01:00
if (LstGrps->NumGrps && LstGrps->GrpCods)
2019-11-06 19:45:20 +01:00
free (LstGrps->GrpCods);
2017-01-19 20:55:31 +01:00
LstGrps->GrpCods = NULL;
2016-12-29 22:19:46 +01:00
LstGrps->NumGrps = 0;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********** Put parameter that indicates all groups selected ****************/
/*****************************************************************************/
void Grp_PutParamAllGroups (void)
{
Par_PutHiddenParamChar ("AllGroups",'Y');
}
/*****************************************************************************/
2017-09-29 15:05:23 +02:00
/************* Parameter to show only my groups or all groups ****************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2020-03-27 14:56:54 +01:00
void Grp_PutParamWhichGroups (void *WhichGrps)
2014-12-01 23:55:08 +01:00
{
2020-03-26 02:54:30 +01:00
if (WhichGrps)
2020-04-08 18:18:46 +02:00
if (*((Grp_WhichGroups_t *) WhichGrps) != Grp_WHICH_GROUPS_DEFAULT)
2020-03-26 02:54:30 +01:00
Par_PutHiddenParamUnsigned (NULL,"WhichGrps",
2020-04-08 18:18:46 +02:00
(unsigned) *((Grp_WhichGroups_t *) WhichGrps));
2014-12-01 23:55:08 +01:00
}
2016-12-04 20:12:56 +01:00
void Grp_PutParamWhichGrpsOnlyMyGrps (void)
{
2019-11-03 13:19:32 +01:00
Par_PutHiddenParamUnsigned (NULL,"WhichGrps",(unsigned) Grp_MY_GROUPS);
2016-12-04 20:12:56 +01:00
}
void Grp_PutParamWhichGrpsAllGrps (void)
{
2019-11-03 13:19:32 +01:00
Par_PutHiddenParamUnsigned (NULL,"WhichGrps",(unsigned) Grp_ALL_GROUPS);
2016-12-04 20:12:56 +01:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2016-12-05 01:54:03 +01:00
/***** Show form to choice whether to show only my groups or all groups ******/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2020-03-26 02:54:30 +01:00
void Grp_ShowFormToSelWhichGrps (Act_Action_t Action,
void (*FuncParams) (void *Args),void *Args)
2016-12-04 23:09:28 +01:00
{
2017-03-21 00:57:11 +01:00
extern const char *Txt_GROUP_WHICH_GROUPS[2];
2016-12-04 23:09:28 +01:00
Grp_WhichGroups_t WhichGrps;
2020-04-08 18:18:46 +02:00
/***** Start setting selector *****/
Set_StartOneSettingSelector ();
2019-09-29 17:33:39 +02:00
2020-04-08 18:18:46 +02:00
/***** Put icons to select which groups *****/
for (WhichGrps = Grp_MY_GROUPS;
WhichGrps <= Grp_ALL_GROUPS;
WhichGrps++)
{
HTM_DIV_Begin ("class=\"%s\"",
WhichGrps == Gbl.Crs.Grps.WhichGrps ? "PREF_ON" :
"PREF_OFF");
Frm_StartForm (Action);
Par_PutHiddenParamUnsigned (NULL,"WhichGrps",(unsigned) WhichGrps);
if (FuncParams) // Extra parameters depending on the action
FuncParams (Args);
Ico_PutSettingIconLink (WhichGrps == Grp_MY_GROUPS ? "mysitemap.png" :
"sitemap.svg",
Txt_GROUP_WHICH_GROUPS[WhichGrps]);
Frm_EndForm ();
HTM_DIV_End ();
2020-03-26 02:54:30 +01:00
}
2020-04-08 18:18:46 +02:00
/***** End setting selector *****/
Set_EndOneSettingSelector ();
2016-12-04 23:09:28 +01:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2016-12-03 23:13:49 +01:00
/************* Get whether to show only my groups or all groups **************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2020-03-27 14:56:54 +01:00
Grp_WhichGroups_t Grp_GetParamWhichGroups (void)
2014-12-01 23:55:08 +01:00
{
2017-04-14 00:27:38 +02:00
static bool AlreadyGot = false;
2017-01-29 12:42:19 +01:00
Grp_WhichGroups_t WhichGroupsDefault;
2014-12-01 23:55:08 +01:00
2017-04-14 00:27:38 +02:00
if (!AlreadyGot)
2014-12-01 23:55:08 +01:00
{
2017-09-29 15:05:23 +02:00
/***** Get which groups (my groups or all groups) *****/
2017-01-29 12:42:19 +01:00
/* Set default */
switch (Gbl.Action.Act)
{
2019-09-29 17:33:39 +02:00
case ActSeeCrsTT: // Show course timetable
case ActPrnCrsTT: // Print course timetable
case ActChgCrsTT1stDay:// Change first day of week in course timetable
case ActSeeAsg: // List assignments
2019-09-29 18:24:08 +02:00
case ActSeeAllGam: // List games
2019-09-29 17:33:39 +02:00
case ActSeeAllSvy: // List surveys
case ActSeeAtt: // List attendance
/*
If I belong to this course ==> see only my groups
If I don't belong to this course ==> see all groups
*/
WhichGroupsDefault = Gbl.Usrs.Me.IBelongToCurrentCrs ? Grp_MY_GROUPS :
Grp_ALL_GROUPS;
2017-01-29 12:42:19 +01:00
break;
2019-09-29 17:33:39 +02:00
case ActSeeMyTT: // Show my timetable
case ActPrnMyTT: // Print my timetable
case ActChgMyTT1stDay: // Change first day of week in my timetable
/* By default, show only my groups */
WhichGroupsDefault = Grp_MY_GROUPS;
2017-01-29 12:42:19 +01:00
break;
2019-09-29 17:33:39 +02:00
default: // Control never should enter here
2017-01-29 12:42:19 +01:00
WhichGroupsDefault = Grp_WHICH_GROUPS_DEFAULT;
break;
}
/* Get parameter */
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.WhichGrps = (Grp_WhichGroups_t)
2019-09-29 17:33:39 +02:00
Par_GetParToUnsignedLong ("WhichGrps",
0,
Grp_NUM_WHICH_GROUPS - 1,
(unsigned long) WhichGroupsDefault);
2017-04-14 00:27:38 +02:00
AlreadyGot = true;
2014-12-01 23:55:08 +01:00
}
2020-03-26 02:54:30 +01:00
return Gbl.Crs.Grps.WhichGrps;
2014-12-01 23:55:08 +01:00
}