// 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 (); fprintf (Gbl.F.Out,"