@@ -40,7 +40,7 @@ public function __toString(): string
4040 public function requestGroup (?bool $ send_mail_to_admins = null , bool $ send_mail = true ): void
4141 {
4242 $ send_mail_to_admins ??= CONFIG ["mail " ]["send_pimesg_to_admins " ];
43- if ($ this ->exists ()) {
43+ if ($ this ->exists () && ! $ this -> getIsDisabled () ) {
4444 return ;
4545 }
4646 if ($ this ->SQL ->accDeletionRequestExists ($ this ->getOwner ()->uid )) {
@@ -63,18 +63,74 @@ public function requestGroup(?bool $send_mail_to_admins = null, bool $send_mail
6363 }
6464 }
6565
66+ /**
67+ * email all members that group is now disabled, remove all members, log, set attribute
68+ * the owner must manually remove all members first, but admins don't have this requirement
69+ */
70+ public function disable (bool $ send_mail = true ): void
71+ {
72+ if ($ this ->getIsDisabled ()) {
73+ throw new Exception ("cannot disable an already disabled group " );
74+ }
75+ $ this ->SQL ->addLog ("disable_pi_group " , $ this ->gid );
76+ $ memberuids = $ this ->getMemberUIDs ();
77+ if ($ send_mail ) {
78+ $ member_attributes = $ this ->LDAP ->getUsersAttributes ($ memberuids , ["mail " ]);
79+ $ member_mails = array_map (fn ($ x ) => (string ) $ x ["mail " ][0 ], $ member_attributes );
80+ if (count ($ member_mails ) > 0 ) {
81+ $ this ->MAILER ->sendMail ($ member_mails , "group_disabled " , [
82+ "group_name " => $ this ->gid ,
83+ ]);
84+ }
85+ }
86+ $ this ->setIsDisabled (true );
87+ if (count ($ memberuids ) > 0 ) {
88+ $ this ->entry ->setAttribute ("memberuid " , []);
89+ }
90+ // TODO optimize
91+ // UnityUser::__construct() makes one LDAP query for each user
92+ // updateIsQualified() makes one LDAP query for each member
93+ // if user is no longer in any PI group, disqualify them
94+ foreach ($ memberuids as $ uid ) {
95+ $ user = new UnityUser ($ uid , $ this ->LDAP , $ this ->SQL , $ this ->MAILER , $ this ->WEBHOOK );
96+ $ user ->updateIsQualified ($ send_mail );
97+ }
98+ }
99+
100+ private function reenable (bool $ send_mail = true ): void
101+ {
102+ if (!$ this ->getIsDisabled ()) {
103+ throw new Exception ("cannot re-enable a group that is not disabled " );
104+ }
105+ $ this ->SQL ->addLog ("reenabled_pi_group " , $ this ->gid );
106+ if ($ send_mail ) {
107+ $ this ->MAILER ->sendMail ($ this ->getOwner ()->getMail (), "group_reenabled " , [
108+ "group_name " => $ this ->gid ,
109+ ]);
110+ }
111+ $ this ->setIsDisabled (false );
112+ $ owner_uid = $ this ->getOwner ()->uid ;
113+ if (!$ this ->memberUIDExists ($ owner_uid )) {
114+ $ this ->addMemberUID ($ owner_uid );
115+ }
116+ $ this ->getOwner ()->updateIsQualified ($ send_mail );
117+ }
118+
66119 /**
67120 * This method will create the group (this is what is executed when an admin approved the group)
68121 */
69122 public function approveGroup (bool $ send_mail = true ): void
70123 {
71124 $ uid = $ this ->getOwner ()->uid ;
72125 $ request = $ this ->SQL ->getRequest ($ uid , UnitySQL::REQUEST_BECOME_PI );
73- if ($ this ->exists ()) {
74- return ;
75- }
76126 \ensure ($ this ->getOwner ()->exists ());
77- $ this ->init ();
127+ if (!$ this ->entry ->exists ()) {
128+ $ this ->init ();
129+ } elseif ($ this ->getIsDisabled ()) {
130+ $ this ->reenable ();
131+ } else {
132+ throw new Exception ("cannot approve group that already exists and is not disabled " );
133+ }
78134 $ this ->SQL ->removeRequest ($ this ->getOwner ()->uid , UnitySQL::REQUEST_BECOME_PI );
79135 $ this ->SQL ->addLog ("approved_group " , $ this ->getOwner ()->uid );
80136 if ($ send_mail ) {
@@ -126,42 +182,6 @@ public function cancelGroupJoinRequest(UnityUser $user, bool $send_mail = true):
126182 }
127183 }
128184
129- // /**
130- // * This method will delete the group, either by admin action or PI action
131- // */
132- // public function removeGroup($send_mail = true)
133- // {
134- // // remove any pending requests
135- // // this will silently fail if the request doesn't exist (which is what we want)
136- // $this->SQL->removeRequests($this->gid);
137-
138- // // we don't need to do anything extra if the group is already deleted
139- // if (!$this->exists()) {
140- // return;
141- // }
142-
143- // // first, we must record the users in the group currently
144- // $users = $this->getGroupMembers();
145-
146- // // now we delete the ldap entry
147- // $this->entry->ensureExists();
148- // $this->entry->delete();
149-
150- // // Logs the change
151- // $this->SQL->addLog("removed_group", $this->gid);
152-
153- // // send email to every user of the now deleted PI group
154- // if ($send_mail) {
155- // foreach ($users as $user) {
156- // $this->MAILER->sendMail(
157- // $user->getMail(),
158- // "group_disband",
159- // array("group_name" => $this->gid)
160- // );
161- // }
162- // }
163- // }
164-
165185 /**
166186 * This method is executed when a user is approved to join the group
167187 * (either by admin or the group owner)
@@ -220,7 +240,7 @@ public function removeUser(UnityUser $new_user, bool $send_mail = true): void
220240 return ;
221241 }
222242 if ($ new_user ->uid == $ this ->getOwner ()->uid ) {
223- throw new Exception ("Cannot delete group owner from group. Disband group instead " );
243+ throw new Exception ("Cannot delete group owner from group. Disable group instead " );
224244 }
225245 $ this ->removeMemberUID ($ new_user ->uid );
226246 $ this ->SQL ->addLog (
@@ -326,7 +346,7 @@ private function init(): void
326346 \ensure (!$ this ->entry ->exists ());
327347 $ nextGID = $ this ->LDAP ->getNextPIGIDNumber ();
328348 $ this ->entry ->create ([
329- "objectclass " => UnityLDAP:: POSIX_GROUP_CLASS ,
349+ "objectclass " => [ " unityClusterPIGroup " , " posixGroup " , " top " ] ,
330350 "gidnumber " => strval ($ nextGID ),
331351 "memberuid " => [$ owner ->uid ],
332352 ]);
@@ -376,4 +396,40 @@ public function getGroupMembersAttributes(array $attributes, array $default_valu
376396 $ default_values ,
377397 );
378398 }
399+
400+ public function getIsDisabled (): bool
401+ {
402+ $ value = $ this ->entry ->getAttribute ("isDisabled " );
403+ switch (count ($ value )) {
404+ case 0 :
405+ return false ;
406+ case 1 :
407+ switch ($ value [0 ]) {
408+ case "TRUE " :
409+ return true ;
410+ case "FALSE " :
411+ return false ;
412+ default :
413+ throw new \RuntimeException (
414+ sprintf (
415+ "unexpected value for isDisabled: '%s'. expected 'TRUE' or 'FALSE' " ,
416+ $ value [0 ],
417+ ),
418+ );
419+ }
420+ default :
421+ throw new \RuntimeException (
422+ sprintf (
423+ "expected value of length 0 or 1, found value %s of length %s " ,
424+ _json_encode ($ value ),
425+ count ($ value ),
426+ ),
427+ );
428+ }
429+ }
430+
431+ private function setIsDisabled (bool $ new_value ): void
432+ {
433+ $ this ->entry ->setAttribute ("isDisabled " , $ new_value ? "TRUE " : "FALSE " );
434+ }
379435}
0 commit comments