// swad_enrolment.c: enrolment (registration) or removing of users /* SWAD (Shared Workspace At a Distance), is a web platform developed at the University of Granada (Spain), and used to support university teaching. This file is part of SWAD core. Copyright (C) 1999-2019 Antonio Cañas Vargas This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General 3 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 . */ /*****************************************************************************/ /*********************************** Headers *********************************/ /*****************************************************************************/ #define _GNU_SOURCE // For asprintf #include // For asprintf #include // For exit, system, malloc, free, rand, etc. #include // For string functions #include "swad_account.h" #include "swad_announcement.h" #include "swad_box.h" #include "swad_database.h" #include "swad_duplicate.h" #include "swad_enrolment.h" #include "swad_form.h" #include "swad_global.h" #include "swad_HTML.h" #include "swad_ID.h" #include "swad_match.h" #include "swad_notification.h" #include "swad_parameter.h" #include "swad_role.h" #include "swad_user.h" /*****************************************************************************/ /****************************** Public constants *****************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private constants *****************************/ /*****************************************************************************/ static const bool Enr_ICanAdminOtherUsrs[Rol_NUM_ROLES] = { /* Users who can not admin */ false, // Rol_UNK false, // Rol_GST false, // Rol_USR false, // Rol_STD false, // Rol_NET /* Users who can admin */ true, // Rol_TCH true, // Rol_DEG_ADM true, // Rol_CTR_ADM true, // Rol_INS_ADM true, // Rol_SYS_ADM }; /*****************************************************************************/ /****************************** Internal types *******************************/ /*****************************************************************************/ #define Enr_NUM_REG_REM_USRS_ACTIONS 6 typedef enum { Enr_REG_REM_USRS_UNKNOWN_ACTION = 0, Enr_REGISTER_SPECIFIED_USRS_IN_CRS = 1, Enr_REMOVE_SPECIFIED_USRS_FROM_CRS = 2, Enr_REMOVE_NOT_SPECIFIED_USRS_FROM_CRS = 3, Enr_UPDATE_USRS_IN_CRS = 4, Enr_ELIMINATE_USRS_FROM_PLATFORM = 5, } Enr_RegRemUsrsAction_t; typedef enum { Enr_REQUEST_REMOVE_USR, Enr_REMOVE_USR, } Enr_ReqDelOrDelUsr_t; /* Remove important user production (works and match results)? */ typedef enum { Enr_DO_NOT_REMOVE_USR_PRODUCTION, Enr_REMOVE_USR_PRODUCTION, } Enr_RemoveUsrProduction_t; /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; /*****************************************************************************/ /************************* Internal global variables *************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void Enr_NotifyAfterEnrolment (struct UsrData *UsrDat,Rol_Role_t NewRole); static void Enr_ReqAdminUsrs (Rol_Role_t Role); static void Enr_ShowFormRegRemSeveralUsrs (Rol_Role_t Role); static void Enr_PutAreaToEnterUsrsIDs (void); static void Enr_PutActionsRegRemSeveralUsrs (void); static void Enr_ReceiveFormUsrsCrs (Rol_Role_t Role); static void Enr_PutActionModifyOneUsr (bool *OptionChecked, bool UsrBelongsToCrs,bool ItsMe); static void Enr_PutActionRegOneDegAdm (bool *OptionChecked); static void Enr_PutActionRegOneCtrAdm (bool *OptionChecked); static void Enr_PutActionRegOneInsAdm (bool *OptionChecked); static void Enr_PutActionRepUsrAsDup (bool *OptionChecked); static void Enr_PutActionRemUsrFromCrs (bool *OptionChecked,bool ItsMe); static void Enr_PutActionRemUsrAsDegAdm (bool *OptionChecked,bool ItsMe); static void Enr_PutActionRemUsrAsCtrAdm (bool *OptionChecked,bool ItsMe); static void Enr_PutActionRemUsrAsInsAdm (bool *OptionChecked,bool ItsMe); static void Enr_PutActionRemUsrAcc (bool *OptionChecked,bool ItsMe); static void Enr_StartRegRemOneUsrAction (Enr_RegRemOneUsrAction_t RegRemOneUsrAction, bool *OptionChecked); static void Enr_EndRegRemOneUsrAction (void); static void Enr_RegisterUsr (struct UsrData *UsrDat,Rol_Role_t RegRemRole, struct ListCodGrps *LstGrps,unsigned *NumUsrsRegistered); static void Enr_PutLinkToRemAllStdsThisCrs (void); static void Enr_ShowEnrolmentRequestsGivenRoles (unsigned RolesSelected); static void Enr_RemoveEnrolmentRequest (long CrsCod,long UsrCod); static void Enr_RemoveExpiredEnrolmentRequests (void); static void Enr_ReqRegRemUsr (Rol_Role_t Role); static void Enr_ReqAnotherUsrIDToRegisterRemove (Rol_Role_t Role); static void Enr_AskIfRegRemMe (Rol_Role_t Role); static void Enr_AskIfRegRemAnotherUsr (Rol_Role_t Role); static void Enr_AskIfRegRemUsr (struct ListUsrCods *ListUsrCods,Rol_Role_t Role); static void Enr_ShowFormToEditOtherUsr (void); static void Enr_AddAdm (Hie_Level_t Scope,long Cod,const char *InsCtrDegName); static void Enr_RegisterAdmin (struct UsrData *UsrDat,Hie_Level_t Scope, long Cod,const char *InsCtrDegName); static bool Enr_CheckIfICanRemUsrFromCrs (void); static void Enr_ReqRemAdmOfDeg (void); static void Enr_ReqRemOrRemAdm (Enr_ReqDelOrDelUsr_t ReqDelOrDelUsr,Hie_Level_t Scope, long Cod,const char *InsCtrDegName); static void Enr_ReqAddAdm (Hie_Level_t Scope,long Cod,const char *InsCtrDegName); static void Enr_AskIfRemoveUsrFromCrs (struct UsrData *UsrDat); static void Enr_EffectivelyRemUsrFromCrs (struct UsrData *UsrDat, struct Course *Crs, Enr_RemoveUsrProduction_t RemoveUsrWorks, Cns_QuietOrVerbose_t QuietOrVerbose); static void Enr_AskIfRemAdm (bool ItsMe,Hie_Level_t Scope, const char *InsCtrDegName); static void Enr_EffectivelyRemAdm (struct UsrData *UsrDat,Hie_Level_t Scope, long Cod,const char *InsCtrDegName); /*****************************************************************************/ /** Check if current course has students and show warning no students found **/ /*****************************************************************************/ void Enr_CheckStdsAndPutButtonToRegisterStdsInCurrentCrs (void) { /***** Put link to register students *****/ if (Gbl.Usrs.Me.Role.Logged == Rol_TCH) // Course selected and I am logged as teacher if (!Gbl.Hierarchy.Crs.NumUsrs[Rol_STD]) // No students in course Usr_ShowWarningNoUsersFound (Rol_STD); } /*****************************************************************************/ /****************** Put inline button to register students *******************/ /*****************************************************************************/ void Enr_PutButtonInlineToRegisterStds (long CrsCod) { extern const char *Txt_Register_students; if (Rol_GetRoleUsrInCrs (Gbl.Usrs.Me.UsrDat.UsrCod,CrsCod) == Rol_TCH) // I am a teacher in course if (!Usr_GetNumUsrsInCrs (Rol_STD,CrsCod)) // No students in course { Frm_StartForm (ActReqEnrSevStd); Crs_PutParamCrsCod (CrsCod); Btn_PutCreateButtonInline (Txt_Register_students); Frm_EndForm (); } } /*****************************************************************************/ /************ Show form to request sign up in the current course *************/ /*****************************************************************************/ void Enr_PutLinkToRequestSignUp (void) { extern const char *Txt_Sign_up; /***** Show the form *****/ Lay_PutContextualLinkIconText (ActReqSignUp,NULL,NULL, "hand-point-up.svg", Txt_Sign_up); } /*****************************************************************************/ /***************** Modify the role of a user in a course *********************/ /*****************************************************************************/ void Enr_ModifyRoleInCurrentCrs (struct UsrData *UsrDat,Rol_Role_t NewRole) { /***** Check if user's role is allowed *****/ switch (NewRole) { case Rol_STD: case Rol_NET: case Rol_TCH: break; default: Rol_WrongRoleExit (); } /***** Update the role of a user in a course *****/ DB_QueryUPDATE ("can not modify user's role in course", "UPDATE crs_usr SET Role=%u" " WHERE CrsCod=%ld AND UsrCod=%ld", (unsigned) NewRole,Gbl.Hierarchy.Crs.CrsCod,UsrDat->UsrCod); /***** Flush caches *****/ Usr_FlushCachesUsr (); /***** Set user's roles *****/ UsrDat->Roles.InCurrentCrs.Role = NewRole; UsrDat->Roles.InCurrentCrs.Valid = true; UsrDat->Roles.InCrss = -1; // Force roles to be got from database Rol_GetRolesInAllCrssIfNotYetGot (UsrDat); // Get roles /***** Create notification for this user. If this user wants to receive notifications by email, activate the sending of a notification *****/ Enr_NotifyAfterEnrolment (UsrDat,NewRole); } /*****************************************************************************/ /*********************** Register user in current course *********************/ /*****************************************************************************/ // Before calling this function, you must be sure that // the user does not belong to the current course void Enr_RegisterUsrInCurrentCrs (struct UsrData *UsrDat,Rol_Role_t NewRole, Enr_KeepOrSetAccepted_t KeepOrSetAccepted) { extern const char *Usr_StringsUsrListTypeInDB[Usr_NUM_USR_LIST_TYPES]; /***** Check if user's role is allowed *****/ switch (NewRole) { case Rol_STD: case Rol_NET: case Rol_TCH: break; default: Rol_WrongRoleExit (); } /***** Register user in current course in database *****/ DB_QueryINSERT ("can not register user in course", "INSERT INTO crs_usr" " (CrsCod,UsrCod,Role,Accepted," "LastDowGrpCod,LastComGrpCod,LastAssGrpCod," "NumAccTst,LastAccTst,NumQstsLastTst," "UsrListType,ColsClassPhoto,ListWithPhotos)" " VALUES" " (%ld,%ld,%u,'%c'," "-1,-1,-1," "0,FROM_UNIXTIME(%ld),0," "'%s',%u,'%c')", Gbl.Hierarchy.Crs.CrsCod,UsrDat->UsrCod,(unsigned) NewRole, KeepOrSetAccepted == Enr_SET_ACCEPTED_TO_TRUE ? 'Y' : 'N', (long) (time_t) 0, // The user never accessed to tests in this course Usr_StringsUsrListTypeInDB[Usr_SHOW_USRS_TYPE_DEFAULT], Usr_CLASS_PHOTO_COLS_DEF, Usr_LIST_WITH_PHOTOS_DEF ? 'Y' : 'N'); /***** Flush caches *****/ Usr_FlushCachesUsr (); /***** Set roles *****/ UsrDat->Roles.InCurrentCrs.Role = NewRole; UsrDat->Roles.InCurrentCrs.Valid = true; UsrDat->Roles.InCrss = -1; // Force roles to be got from database Rol_GetRolesInAllCrssIfNotYetGot (UsrDat); // Get roles /***** Create notification for this user. If this user wants to receive notifications by email, activate the sending of a notification *****/ Enr_NotifyAfterEnrolment (UsrDat,NewRole); } /*****************************************************************************/ /********* Create notification after register user in current course *********/ /*****************************************************************************/ static void Enr_NotifyAfterEnrolment (struct UsrData *UsrDat,Rol_Role_t NewRole) { bool CreateNotif; bool NotifyByEmail; Ntf_NotifyEvent_t NotifyEvent; bool ItsMe = Usr_ItsMe (UsrDat->UsrCod); /***** Check if user's role is allowed *****/ switch (NewRole) { case Rol_STD: NotifyEvent = Ntf_EVENT_ENROLMENT_STD; break; case Rol_NET: NotifyEvent = Ntf_EVENT_ENROLMENT_NET; break; case Rol_TCH: NotifyEvent = Ntf_EVENT_ENROLMENT_TCH; break; default: NotifyEvent = Ntf_EVENT_UNKNOWN; Rol_WrongRoleExit (); } /***** Remove possible enrolment request ******/ Enr_RemoveEnrolmentRequest (Gbl.Hierarchy.Crs.CrsCod,UsrDat->UsrCod); /***** Remove old enrolment notifications before inserting the new one ******/ Ntf_MarkNotifToOneUsrAsRemoved (Ntf_EVENT_ENROLMENT_STD,-1,UsrDat->UsrCod); Ntf_MarkNotifToOneUsrAsRemoved (Ntf_EVENT_ENROLMENT_NET,-1,UsrDat->UsrCod); Ntf_MarkNotifToOneUsrAsRemoved (Ntf_EVENT_ENROLMENT_TCH,-1,UsrDat->UsrCod); /***** Create new notification ******/ CreateNotif = (UsrDat->NtfEvents.CreateNotif & (1 << NotifyEvent)); NotifyByEmail = CreateNotif && !ItsMe && (UsrDat->NtfEvents.SendEmail & (1 << NotifyEvent)); if (CreateNotif) Ntf_StoreNotifyEventToOneUser (NotifyEvent,UsrDat,-1L, (Ntf_Status_t) (NotifyByEmail ? Ntf_STATUS_BIT_EMAIL : 0)); } /*****************************************************************************/ /****** Write a form to request another user's ID, @nickname or email ********/ /*****************************************************************************/ void Enr_WriteFormToReqAnotherUsrID (Act_Action_t NextAction,void (*FuncParams) (void)) { extern const char *The_ClassFormInBox[The_NUM_THEMES]; extern const char *Txt_nick_email_or_ID; extern const char *Txt_Continue; /***** Form to request user's ID, @nickname or email address *****/ Frm_StartForm (NextAction); if (FuncParams) FuncParams (); HTM_LABEL_Begin ("for=\"OtherUsrIDNickOrEMail\" class=\"%s RM\"", The_ClassFormInBox[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"%s: ",Txt_nick_email_or_ID); HTM_LABEL_End (); HTM_INPUT_TEXT ("OtherUsrIDNickOrEMail",Cns_MAX_CHARS_EMAIL_ADDRESS,"",false, "size=\"18\" required=\"required\""); /***** Send button*****/ Btn_PutConfirmButton (Txt_Continue); Frm_EndForm (); } /*****************************************************************************/ /****** Request acceptation / refusion of register in current course *********/ /*****************************************************************************/ void Enr_ReqAcceptRegisterInCrs (void) { extern const char *Hlp_USERS_SignUp_confirm_enrolment; extern const char *Txt_Enrolment; extern const char *Txt_A_teacher_or_administrator_has_enroled_you_as_X_into_the_course_Y; extern const char *Txt_ROLES_SINGUL_abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; extern const char *Txt_Confirm_my_enrolment; extern const char *Txt_Remove_me_from_this_course; Ntf_NotifyEvent_t NotifyEvent; /***** Begin box *****/ Box_BoxBegin (NULL,Txt_Enrolment,NULL, Hlp_USERS_SignUp_confirm_enrolment,Box_NOT_CLOSABLE); /***** Show message *****/ Ale_ShowAlert (Ale_INFO,Txt_A_teacher_or_administrator_has_enroled_you_as_X_into_the_course_Y, Txt_ROLES_SINGUL_abc[Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs.Role][Gbl.Usrs.Me.UsrDat.Sex], Gbl.Hierarchy.Crs.FullName); /***** Send button to accept register in the current course *****/ switch (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs.Role) { case Rol_STD: Frm_StartForm (ActAccEnrStd); break; case Rol_NET: Frm_StartForm (ActAccEnrNET); break; case Rol_TCH: Frm_StartForm (ActAccEnrTch); break; default: Rol_WrongRoleExit (); } Btn_PutCreateButtonInline (Txt_Confirm_my_enrolment); Frm_EndForm (); /***** Send button to refuse register in the current course *****/ switch (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs.Role) { case Rol_STD: Frm_StartForm (ActRemMe_Std); break; case Rol_NET: Frm_StartForm (ActRemMe_NET); break; case Rol_TCH: Frm_StartForm (ActRemMe_Tch); break; default: Rol_WrongRoleExit (); } Btn_PutRemoveButtonInline (Txt_Remove_me_from_this_course); Frm_EndForm (); /***** End box *****/ Box_BoxEnd (); /***** Mark possible notification as seen *****/ switch (Gbl.Usrs.Me.UsrDat.Roles.InCurrentCrs.Role) { case Rol_STD: NotifyEvent = Ntf_EVENT_ENROLMENT_STD; break; case Rol_NET: NotifyEvent = Ntf_EVENT_ENROLMENT_NET; break; case Rol_TCH: NotifyEvent = Ntf_EVENT_ENROLMENT_TCH; break; default: NotifyEvent = Ntf_EVENT_UNKNOWN; Rol_WrongRoleExit (); break; } Ntf_MarkNotifAsSeen (NotifyEvent,-1L,Gbl.Hierarchy.Crs.CrsCod, Gbl.Usrs.Me.UsrDat.UsrCod); } /*****************************************************************************/ /****************** Put an enrolment into a notification ********************/ /*****************************************************************************/ void Enr_GetNotifEnrolment (char SummaryStr[Ntf_MAX_BYTES_SUMMARY + 1], long CrsCod,long UsrCod) { extern const char *Txt_ROLES_SINGUL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; MYSQL_RES *mysql_res; MYSQL_ROW row; struct UsrData UsrDat; Rol_Role_t Role; SummaryStr[0] = '\0'; // Return nothing on error // This function may be called inside a web service, so don't report error /***** Get user's role in course from database *****/ if (DB_QuerySELECT (&mysql_res,"can not get user's role" " in course", "SELECT Role" " FROM crs_usr" " WHERE CrsCod=%ld AND UsrCod=%ld", CrsCod,UsrCod) == 1) // Result should have a unique row { /***** Get user's role in course *****/ row = mysql_fetch_row (mysql_res); /* Initialize structure with user's data */ Usr_UsrDataConstructor (&UsrDat); /* Get user's data */ UsrDat.UsrCod = UsrCod; Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&UsrDat,Usr_DONT_GET_PREFS); /* Role (row[0]) */ Role = Rol_ConvertUnsignedStrToRole (row[0]); Str_Copy (SummaryStr,Txt_ROLES_SINGUL_Abc[Role][UsrDat.Sex], Ntf_MAX_BYTES_SUMMARY); /* Free memory used for user's data */ Usr_UsrDataDestructor (&UsrDat); } /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /***************************** Update user's data ****************************/ /*****************************************************************************/ // UsrDat->UsrCod must be > 0 void Enr_UpdateUsrData (struct UsrData *UsrDat) { extern const char *Usr_StringsSexDB[Usr_NUM_SEXS]; char BirthdayStrDB[Usr_BIRTHDAY_STR_DB_LENGTH + 1]; /***** Check if user's code is initialized *****/ if (UsrDat->UsrCod <= 0) Lay_ShowErrorAndExit ("Can not update user's data. Wrong user's code."); /***** Filter some user's data before updating */ Enr_FilterUsrDat (UsrDat); /***** Update user's common data *****/ Usr_CreateBirthdayStrDB (UsrDat,BirthdayStrDB); // It can include start and ending apostrophes DB_QueryUPDATE ("can not update user's data", "UPDATE usr_data" " SET Password='%s'," "Surname1='%s',Surname2='%s',FirstName='%s',Sex='%s'," "CtyCod=%ld," "LocalAddress='%s',LocalPhone='%s'," "FamilyAddress='%s',FamilyPhone='%s'," "OriginPlace='%s',Birthday=%s," "Comments='%s'" " WHERE UsrCod=%ld", UsrDat->Password, UsrDat->Surname1,UsrDat->Surname2,UsrDat->FirstName, Usr_StringsSexDB[UsrDat->Sex], UsrDat->CtyCod, UsrDat->LocalAddress,UsrDat->LocalPhone, UsrDat->FamilyAddress,UsrDat->FamilyPhone, UsrDat->OriginPlace, BirthdayStrDB, UsrDat->Comments ? UsrDat->Comments : "", UsrDat->UsrCod); } /*****************************************************************************/ /************************* Filter some user's data ***************************/ /*****************************************************************************/ void Enr_FilterUsrDat (struct UsrData *UsrDat) { /***** Fix birthday *****/ if (UsrDat->Birthday.Year < Gbl.Now.Date.Year-99 || UsrDat->Birthday.Year > Gbl.Now.Date.Year-16) UsrDat->Birthday.Year = UsrDat->Birthday.Month = UsrDat->Birthday.Day = 0; } /*****************************************************************************/ /**************** Update institution, centre and department ******************/ /*****************************************************************************/ void Enr_UpdateInstitutionCentreDepartment (void) { DB_QueryUPDATE ("can not update institution, centre and department", "UPDATE usr_data" " SET InsCtyCod=%ld,InsCod=%ld,CtrCod=%ld,DptCod=%ld" " WHERE UsrCod=%ld", Gbl.Usrs.Me.UsrDat.InsCtyCod, Gbl.Usrs.Me.UsrDat.InsCod, Gbl.Usrs.Me.UsrDat.Tch.CtrCod, Gbl.Usrs.Me.UsrDat.Tch.DptCod, Gbl.Usrs.Me.UsrDat.UsrCod); } /*****************************************************************************/ /************** Form to request the user's ID of another user ****************/ /*****************************************************************************/ void Enr_ReqAdminStds (void) { Enr_ReqAdminUsrs (Rol_STD); } void Enr_ReqAdminNonEditingTchs (void) { Enr_ReqAdminUsrs (Rol_NET); } void Enr_ReqAdminTchs (void) { Enr_ReqAdminUsrs (Rol_TCH); } static void Enr_ReqAdminUsrs (Rol_Role_t Role) { switch (Gbl.Usrs.Me.Role.Logged) { case Rol_GST: case Rol_STD: case Rol_NET: Enr_AskIfRegRemMe (Role); break; case Rol_TCH: if (Gbl.Hierarchy.Level == Hie_CRS && Role == Rol_STD) Enr_ShowFormRegRemSeveralUsrs (Rol_STD); else Enr_AskIfRegRemMe (Rol_TCH); break; case Rol_DEG_ADM: case Rol_CTR_ADM: case Rol_INS_ADM: case Rol_SYS_ADM: if (Gbl.Hierarchy.Level == Hie_CRS) Enr_ShowFormRegRemSeveralUsrs (Role); else Enr_ReqAnotherUsrIDToRegisterRemove (Role); break; default: Lay_NoPermissionExit (); break; } } /*****************************************************************************/ /***** Register/remove users (taken from a list) in/from current course ******/ /*****************************************************************************/ static void Enr_ShowFormRegRemSeveralUsrs (Rol_Role_t Role) { extern const char *Hlp_USERS_Administration_administer_multiple_users; extern const char *The_ClassTitle[The_NUM_THEMES]; extern const char *Txt_Administer_multiple_students; extern const char *Txt_Administer_multiple_non_editing_teachers; extern const char *Txt_Administer_multiple_teachers; extern const char *Txt_Step_1_Provide_a_list_of_users; extern const char *Txt_Type_or_paste_a_list_of_IDs_nicks_or_emails_; extern const char *Txt_Step_2_Select_the_desired_action; extern const char *Txt_Step_3_Optionally_select_groups; extern const char *Txt_Select_the_groups_in_from_which_you_want_to_register_remove_users_; extern const char *Txt_No_groups_have_been_created_in_the_course_X_Therefore_; extern const char *Txt_Step_4_Confirm_the_enrolment_removing; extern const char *Txt_Confirm; Act_Action_t NextAction; const char *Title; /***** Contextual menu *****/ if (Gbl.Hierarchy.Level == Hie_CRS) // Course selected { Mnu_ContextMenuBegin (); switch (Role) { case Rol_STD: /* Put link to go to admin student */ Enr_PutLinkToAdminOneUsr (ActReqMdfOneStd); /* Put link to remove all the students in the current course */ if (Gbl.Hierarchy.Crs.NumUsrs[Rol_STD]) // This course has students Enr_PutLinkToRemAllStdsThisCrs (); break; case Rol_NET: /* Put link to go to admin teacher */ Enr_PutLinkToAdminOneUsr (ActReqMdfOneTch); break; case Rol_TCH: /* Put link to go to admin teacher */ Enr_PutLinkToAdminOneUsr (ActReqMdfOneTch); break; default: NextAction = ActUnk; Title = NULL; Rol_WrongRoleExit (); break; } Mnu_ContextMenuEnd (); } /***** Form to send students to be enroled / removed *****/ switch (Role) { case Rol_STD: NextAction = ActRcvFrmEnrSevStd; Title = Txt_Administer_multiple_students; break; case Rol_NET: NextAction = ActRcvFrmEnrSevNET; Title = Txt_Administer_multiple_non_editing_teachers; break; case Rol_TCH: NextAction = ActRcvFrmEnrSevTch; Title = Txt_Administer_multiple_teachers; break; default: NextAction = ActUnk; Title = NULL; Rol_WrongRoleExit (); break; } Frm_StartForm (NextAction); /***** Begin box *****/ Box_BoxBegin (NULL,Title,NULL, Hlp_USERS_Administration_administer_multiple_users,Box_NOT_CLOSABLE); /***** Step 1: List of students to be enroled / removed *****/ HTM_DIV_Begin ("class=\"%s LM\"",The_ClassTitle[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"%s",Txt_Step_1_Provide_a_list_of_users); HTM_DIV_End (); Ale_ShowAlert (Ale_INFO,Txt_Type_or_paste_a_list_of_IDs_nicks_or_emails_); Enr_PutAreaToEnterUsrsIDs (); /***** Step 2: Put different actions to register/remove users to/from current course *****/ HTM_DIV_Begin ("class=\"%s LM\"",The_ClassTitle[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"%s",Txt_Step_2_Select_the_desired_action); HTM_DIV_End (); Enr_PutActionsRegRemSeveralUsrs (); /***** Step 3: Select groups in which register / remove users *****/ HTM_DIV_Begin ("class=\"%s LM\"",The_ClassTitle[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"%s",Txt_Step_3_Optionally_select_groups); HTM_DIV_End (); if (Gbl.Hierarchy.Level == Hie_CRS) // Course selected { if (Gbl.Crs.Grps.NumGrps) // This course has groups? { Ale_ShowAlert (Ale_INFO,Txt_Select_the_groups_in_from_which_you_want_to_register_remove_users_); Grp_ShowLstGrpsToChgOtherUsrsGrps (-1L); } else /* Write help message */ Ale_ShowAlert (Ale_INFO,Txt_No_groups_have_been_created_in_the_course_X_Therefore_, Gbl.Hierarchy.Crs.FullName); } /***** Step 4: Confirm register / remove students *****/ HTM_DIV_Begin ("class=\"%s LM\"",The_ClassTitle[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"%s",Txt_Step_4_Confirm_the_enrolment_removing); HTM_DIV_End (); Pwd_AskForConfirmationOnDangerousAction (); /***** Send button and end box *****/ Box_EndBoxWithButton (Btn_CONFIRM_BUTTON,Txt_Confirm); /***** End form *****/ Frm_EndForm (); } /*****************************************************************************/ /******************** Put a link (form) to remove old users ******************/ /*****************************************************************************/ void Enr_PutLinkToRemOldUsrs (void) { extern const char *Txt_Eliminate_old_users; /***** Put form to remove old users *****/ Lay_PutContextualLinkIconText (ActReqRemOldUsr,NULL,NULL, "trash.svg", Txt_Eliminate_old_users); } /*****************************************************************************/ /*********************** Write form to remove old users **********************/ /*****************************************************************************/ void Enr_AskRemoveOldUsrs (void) { extern const char *The_ClassFormInBox[The_NUM_THEMES]; extern const char *Txt_Eliminate_old_users; extern const char *Txt_Eliminate_all_users_who_are_not_enroled_on_any_courses_PART_1_OF_2; extern const char *Txt_Eliminate_all_users_who_are_not_enroled_on_any_courses_PART_2_OF_2; extern const char *Txt_Eliminate; unsigned Months; /***** Begin form *****/ Frm_StartForm (ActRemOldUsr); /***** Begin box *****/ Box_BoxBegin (NULL,Txt_Eliminate_old_users,NULL, NULL,Box_NOT_CLOSABLE); /***** Form to request number of months without clicks *****/ HTM_LABEL_Begin ("class=\"%s\"",The_ClassFormInBox[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"%s ", Txt_Eliminate_all_users_who_are_not_enroled_on_any_courses_PART_1_OF_2); fprintf (Gbl.F.Out,"