PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.2.0
Defender Security – Malware Scanner, Login Security & Firewall v6.2.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / component / class-recipient-directory.php

class-recipient-directory.php in Defender Security – Malware Scanner, Login Security & Firewall 6.2.0, at src/component/class-recipient-directory.php

264 lines 7.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Builds recipient directory data for notification modules.
4 *
5 * @package WP_Defender\Component
6 */
7
8 namespace WP_Defender\Component;
9
10 use WP_Defender\Component;
11 use WP_Defender\Model\Notification as Model_Notification;
12 use WP_Defender\Model\Notification\Firewall_Notification;
13
14 /**
15 * Handles recipient search and frontend directory data.
16 */
17 class Recipient_Directory extends Component {
18
19 /**
20 * Notification service.
21 *
22 * @var Notification
23 */
24 private Notification $notification;
25
26 /**
27 * Initialize dependencies.
28 */
29 public function __construct() {
30 $this->notification = wd_di()->get( Notification::class );
31 }
32
33 /**
34 * Search WordPress users by name or email.
35 *
36 * @param string $search Search term.
37 * @return array User result rows.
38 */
39 public function search_users( string $search ): array {
40 if ( strlen( $search ) < 3 ) {
41 return array();
42 }
43
44 $wp_users = get_users(
45 array(
46 'search' => "*{$search}*",
47 'search_columns' => array( 'user_login', 'user_email', 'display_name' ),
48 'number' => 20,
49 )
50 );
51
52 $results = array();
53 foreach ( $wp_users as $user ) {
54 $results[] = array(
55 'id' => (string) $user->ID,
56 'name' => $user->display_name,
57 'email' => $user->user_email,
58 'role' => isset( $user->roles[0] ) ? $user->roles[0] : '',
59 );
60 }
61
62 return $results;
63 }
64
65 /**
66 * Delete a recipient from all notification modules.
67 *
68 * @param string $recipient_id Recipient ID or out-of-house email.
69 * @return void
70 */
71 public function delete_recipient( string $recipient_id ): void {
72 $is_in_house = is_numeric( $recipient_id );
73 $email = '';
74 if ( $is_in_house ) {
75 $user_data = get_userdata( (int) $recipient_id );
76 $email = $user_data ? $user_data->user_email : '';
77 }
78
79 foreach ( $this->notification->get_modules_as_objects() as $model ) {
80 $changed = false;
81
82 if ( $is_in_house ) {
83 if ( '' !== $email && isset( $model->in_house_recipients[ $email ] ) ) {
84 unset( $model->in_house_recipients[ $email ] );
85 $changed = true;
86 }
87 } elseif ( isset( $model->out_house_recipients[ $recipient_id ] ) ) {
88 unset( $model->out_house_recipients[ $recipient_id ] );
89 $changed = true;
90 }
91
92 if ( $changed ) {
93 $model->save();
94 }
95 }
96 }
97
98 /**
99 * Check whether an email already belongs to a recipient in any module.
100 *
101 * @param string $email Email address to look up.
102 * @return bool True when the email is already a recipient.
103 */
104 public function email_exists( string $email ): bool {
105 $email = strtolower( trim( $email ) );
106 if ( '' === $email ) {
107 return false;
108 }
109
110 foreach ( $this->notification->get_modules_as_objects() as $model ) {
111 $recipients = array_merge(
112 array_values( $model->in_house_recipients ),
113 array_values( $model->out_house_recipients )
114 );
115 foreach ( $recipients as $recipient ) {
116 if ( strtolower( trim( (string) ( $recipient['email'] ?? '' ) ) ) === $email ) {
117 return true;
118 }
119 }
120 }
121
122 return false;
123 }
124
125 /**
126 * Get recipients across all modules.
127 *
128 * @return array Recipient data.
129 */
130 public function get_all_recipients(): array {
131 $seen = array();
132 $result = array();
133 $modules = $this->notification->get_modules_as_objects();
134 $avatar_map = $this->get_in_house_avatar_map( $modules );
135
136 foreach ( $modules as $model ) {
137 $this->collect_in_house_recipients( $result, $seen, $model, $avatar_map );
138 $this->collect_out_house_recipients( $result, $seen, $model );
139 }
140
141 return array_values( $result );
142 }
143
144 /**
145 * Collect in-house recipients for one module.
146 *
147 * @param array $result Accumulated recipients list.
148 * @param array $seen Deduplication index.
149 * @param Model_Notification $model Notification model.
150 * @param array $avatar_map Avatar URLs keyed by email.
151 * @return void
152 */
153 private function collect_in_house_recipients( array &$result, array &$seen, Model_Notification $model, array $avatar_map ): void {
154 $counts_as_subscribed = $this->counts_as_subscribed( $model );
155 foreach ( $model->in_house_recipients as $recipient ) {
156 $key = 'u_' . ( $recipient['id'] ?? $recipient['email'] );
157 $base = array(
158 'id' => (string) ( $recipient['id'] ?? $recipient['email'] ),
159 'avatar' => $avatar_map[ $recipient['email'] ] ?? '',
160 'role' => $recipient['role'] ?? '',
161 '_inHouse' => true,
162 );
163 $this->collect_recipient( $result, $seen, $key, $recipient, $model->slug, $base, $counts_as_subscribed );
164 }
165 }
166
167 /**
168 * Collect out-of-house recipients for one module.
169 *
170 * @param array $result Accumulated recipients list.
171 * @param array $seen Deduplication index.
172 * @param Model_Notification $model Notification model.
173 * @return void
174 */
175 private function collect_out_house_recipients( array &$result, array &$seen, Model_Notification $model ): void {
176 $counts_as_subscribed = $this->counts_as_subscribed( $model );
177 foreach ( $model->out_house_recipients as $recipient ) {
178 $key = 'o_' . $recipient['email'];
179 $base = array(
180 'id' => $recipient['email'],
181 'avatar' => '',
182 'role' => '',
183 '_inHouse' => false,
184 );
185 $this->collect_recipient( $result, $seen, $key, $recipient, $model->slug, $base, $counts_as_subscribed );
186 }
187 }
188
189 /**
190 * Whether membership in this module counts as an active subscription.
191 *
192 * Reports and the firewall alert are per-recipient preferences, so they count regardless of the
193 * module's on/off state; otherwise a template toggle would mask a recipient's own preference.
194 * Other notifications count only while their status is active.
195 *
196 * @param Model_Notification $model Notification model.
197 * @return bool
198 */
199 private function counts_as_subscribed( Model_Notification $model ): bool {
200 if ( 'report' === $model->type || Firewall_Notification::SLUG === $model->slug ) {
201 return true;
202 }
203
204 return Model_Notification::STATUS_ACTIVE === $model->status;
205 }
206
207 /**
208 * Get avatar URLs for all in-house recipient emails.
209 *
210 * @param array $modules Notification modules.
211 * @return array
212 */
213 private function get_in_house_avatar_map( array $modules ): array {
214 $in_house_emails = array();
215 foreach ( $modules as $model ) {
216 foreach ( $model->in_house_recipients as $recipient ) {
217 if ( isset( $recipient['email'] ) && '' !== trim( $recipient['email'] ) ) {
218 $in_house_emails[ $recipient['email'] ] = true;
219 }
220 }
221 }
222
223 $avatar_map = array();
224 foreach ( array_keys( $in_house_emails ) as $email ) {
225 $avatar_map[ $email ] = get_avatar_url( $email );
226 }
227
228 return $avatar_map;
229 }
230
231 /**
232 * Add a recipient entry to the result or append its module slug if already seen.
233 *
234 * @param array $result Accumulated recipients list.
235 * @param array $seen Deduplication index.
236 * @param string $key Unique recipient key.
237 * @param array $recipient Recipient data from the model.
238 * @param string $slug Notification module slug.
239 * @param array $base Type-specific fields.
240 * @param bool $counts_as_subscribed Whether membership in the module counts as an active subscription.
241 * @return void
242 */
243 private function collect_recipient( array &$result, array &$seen, string $key, array $recipient, string $slug, array $base, bool $counts_as_subscribed = true ): void {
244 $status = $recipient['status'] ?? '';
245 $canceled = Model_Notification::USER_SUBSCRIBE_CANCELED === $status;
246 $add_slug = $counts_as_subscribed && ! $canceled;
247
248 if ( isset( $seen[ $key ] ) ) {
249 if ( $add_slug ) {
250 $result[ $seen[ $key ] ]['statuses'][] = $slug;
251 }
252 return;
253 }
254
255 $seen[ $key ] = count( $result );
256 $result[] = $base + array(
257 'name' => $recipient['name'],
258 'email' => $recipient['email'],
259 'status' => $status,
260 'statuses' => $add_slug ? array( $slug ) : array(),
261 );
262 }
263 }
264