Completed
Push — master ( 395485...bbad3a )
by Julito
43:12
created

AnnouncementEmail::all_users()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 17
nc 3
nop 0
dl 0
loc 24
rs 8.6845
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 * Announcement Email
6
 *
7
 * @author Laurent Opprecht <[email protected]> for the Univesity of Geneva
8
 * @author Julio Montoya <[email protected]> Adding session support
9
 */
10
class AnnouncementEmail
11
{
12
    protected $course = null;
13
    protected $announcement = null;
14
    public $session_id = null;
15
16
    /**
17
     *
18
     * @param array $courseInfo
19
     * @param int $sessionId
20
     * @param int $announcementId
21
     *
22
     * @return AnnouncementEmail
23
     */
24
    public static function create($courseInfo, $sessionId, $announcementId)
25
    {
26
        return new self($courseInfo, $sessionId, $announcementId);
27
    }
28
29
    /**
30
     * @param array $courseInfo
31
     * @param int $sessionId
32
     * @param int $announcementId
33
     */
34
    public function __construct($courseInfo, $sessionId, $announcementId)
35
    {
36
        if (empty($courseInfo)) {
37
            $courseInfo = api_get_course_info();
38
        }
39
40
        $this->course = $courseInfo;
41
        $this->session_id = !empty($sessionId) ? (int) $sessionId : api_get_session_id();
42
43
        if (is_numeric($announcementId)) {
44
            $announcementId = AnnouncementManager::get_by_id($courseInfo['real_id'], $announcementId);
45
        }
46
        $this->announcement = $announcementId;
47
    }
48
49
    /**
50
     * Course info
51
     *
52
     * @param string $key
53
     *
54
     * @return string|null
55
     */
56 View Code Duplication
    public function course($key = '')
57
    {
58
        $result = $key ? $this->course[$key] : $this->course;
59
        $result = $key == 'id' ? intval($result) : $result;
60
61
        return $result;
62
    }
63
64
    /**
65
     * Announcement info
66
     *
67
     * @param string $key
68
     * @return array
69
     */
70 View Code Duplication
    public function announcement($key = '')
71
    {
72
        $result = $key ? $this->announcement[$key] : $this->announcement;
73
        $result = $key == 'id' ? intval($result) : $result;
74
75
        return $result;
76
    }
77
78
    /**
79
     * Returns either all course users or all session users depending on whether
80
     * session is turned on or not
81
     *
82
     * @return array
83
     */
84
    public function all_users()
85
    {
86
        $courseCode = $this->course('code');
87
        if (empty($this->session_id)) {
88
            $group_id = api_get_group_id();
89
            if (empty($group_id)) {
90
                $userList = CourseManager::get_user_list_from_course_code($courseCode);
91
            } else {
92
                $userList = GroupManager::get_users($group_id);
93
                $new_user_list = array();
94
                foreach ($userList as $user) {
95
                    $new_user_list[] = array('user_id' => $user);
96
                }
97
                $userList = $new_user_list;
98
            }
99
        } else {
100
            $userList = CourseManager::get_user_list_from_course_code(
101
                $courseCode,
102
                $this->session_id
103
            );
104
        }
105
106
        return $userList;
107
    }
108
109
    /**
110
     * Returns users and groups an announcement item has been sent to.
111
     *
112
     * @return array Array of users and groups to whom the element has been sent
113
     */
114
    public function sent_to_info()
115
    {
116
        $result = array();
117
        $result['groups'] = array();
118
        $result['users'] = array();
119
120
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
121
        $tool = TOOL_ANNOUNCEMENT;
122
123
        $id = $this->announcement('id');
124
        $course_id = $this->course('real_id');
125
        $sessionCondition = api_get_session_condition($this->session_id);
126
127
        $sql = "SELECT to_group_id, to_user_id
128
                FROM $table
129
                WHERE
130
                    c_id = $course_id AND
131
                    tool = '$tool' AND
132
                    ref = $id
133
                    $sessionCondition";
134
135
        $rs = Database::query($sql);
136
137
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
138
            // if to_user_id <> 0 then it is sent to a specific user
139
            $user_id = $row['to_user_id'];
140
            if (!empty($user_id)) {
141
                $result['users'][] = (int) $user_id;
142
                // If user is set then skip the group
143
                continue;
144
            }
145
146
            // if to_group_id is null then it is sent to a specific user
147
            // if to_group_id = 0 then it is sent to everybody
148
            $group_id = $row['to_group_id'];
149
            if (!empty($group_id)) {
150
                $result['groups'][] = (int) $group_id;
151
            }
152
        }
153
154
        return $result;
155
    }
156
157
    /**
158
     * Returns the list of user info to which an announcement was sent.
159
     * This function returns a list of actual users even when recipient
160
     * are groups
161
     *
162
     * @return array
163
     */
164
    public function sent_to()
165
    {
166
        $sent_to = $this->sent_to_info();
167
        $users = $sent_to['users'];
168
        $users = $users ? $users : array();
169
        $groups = $sent_to['groups'];
170
171
        if ($users) {
172
            $users = UserManager::get_user_list_by_ids($users, true);
173
        }
174
175
        if (!empty($groups)) {
176
            $group_users = GroupManager::get_groups_users($groups);
177
            $group_users = UserManager::get_user_list_by_ids($group_users, true);
178
179
            if (!empty($group_users)) {
180
                $users = array_merge($users, $group_users);
181
            }
182
        }
183
184
        if (empty($users)) {
185
            $users = self::all_users();
186
        }
187
188
        // Clean users just in case
189
        $newListUsers = array();
190
        if (!empty($users)) {
191
            foreach ($users as $user) {
0 ignored issues
show
Bug introduced by
The expression $users of type array|integer is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
192
                $newListUsers[$user['user_id']] = ['user_id' => $user['user_id']];
193
            }
194
        }
195
196
        return $newListUsers;
197
    }
198
199
    /**
200
     * Sender info
201
     *
202
     * @param string $key
203
     *
204
     * @return array
205
     */
206
    public function sender($key = '',  $userId = '')
207
    {
208
        $_user = api_get_user_info($userId);
209
210
        return $key ? $_user[$key] : $_user;
211
    }
212
213
    /**
214
     * Email subject
215
     *
216
     * @return string
217
     */
218
    public function subject()
219
    {
220
        $result = $this->course('title').' - '.$this->announcement('title');
221
        $result = stripslashes($result);
222
223
        return $result;
224
    }
225
226
    /**
227
     * Email message
228
     * @param int $receiverUserId
229
     *
230
     * @return string
231
     */
232
    public function message($receiverUserId)
233
    {
234
        $content = $this->announcement('content');
235
        $session_id = $this->session_id;
236
        $courseCode = $this->course('code');
237
238
        $content = AnnouncementManager::parse_content(
239
            $receiverUserId,
240
            $content,
241
            $courseCode,
242
            $session_id
243
        );
244
245
        $user_email = $this->sender('mail');
246
        // Build the link by hand because api_get_cidreq() doesn't accept course params
247
        $course_param = 'cidReq='.$courseCode.'&id_session='.$session_id.'&gidReq='.api_get_group_id();
248
        $course_name = $this->course('title');
249
250
        $result = "<div>$content</div>";
251
252
        // Adding attachment
253
        $attachment = $this->attachment();
254
        if (!empty($attachment)) {
255
            $result .= '<br />';
256
            $result .= Display::url(
257
                $attachment['filename'],
258
                api_get_path(WEB_CODE_PATH).'announcements/download.php?file='.basename($attachment['path']).'&'.$course_param
259
            );
260
            $result .= '<br />';
261
        }
262
263
        $result .= '<hr />';
264
        $sender_name = api_get_person_name(
265
            $this->sender('firstName'),
266
            $this->sender('lastName'),
267
            PERSON_NAME_EMAIL_ADDRESS
268
        );
269
        $result .= '<a href="mailto:'.$user_email.'">'.$sender_name.'</a><br/>';
270
        $result .= '<a href="'.api_get_path(WEB_CODE_PATH).'announcements/announcements.php?'.$course_param.'">'.$course_name.'</a><br/>';
271
272
        return $result;
273
    }
274
275
    /**
276
     * Returns the one file that can be attached to an announcement.
277
     *
278
     * @return array
279
     */
280
    public function attachment()
281
    {
282
        $result = array();
283
        $table = Database::get_course_table(TABLE_ANNOUNCEMENT_ATTACHMENT);
284
        $id = $this->announcement('id');
285
        $course_id = $this->course('id');
286
        $sql = "SELECT * FROM $table 
287
                WHERE c_id = $course_id AND announcement_id = $id ";
288
        $rs = Database::query($sql);
289
        $course_path = $this->course('directory');
290
        while ($row = Database::fetch_array($rs)) {
291
            $path = api_get_path(SYS_COURSE_PATH).$course_path.'/upload/announcements/'.$row['path'];
292
            $filename = $row['filename'];
293
            $result[] = array('path' => $path, 'filename' => $filename);
294
        }
295
296
        $result = $result ? reset($result) : array();
297
298
        return $result;
299
    }
300
301
    /**
302
     * Send emails to users.
303
     * @param bool $sendToUsersInSession
304
     * @param bool $sendToDrhUsers send a copy of the message to the DRH users
305
     * related to the main user
306
     */
307
    public function send($sendToUsersInSession = false, $sendToDrhUsers = false)
308
    {
309
        $sender = $this->sender();
310
        $subject = $this->subject();
311
312
        // Send email one by one to avoid antispam
313
        $users = $this->sent_to();
314
315
        $batchSize = 20;
316
        $counter = 1;
317
        $em = Database::getManager();
318
319
        foreach ($users as $user) {
320
            $message = $this->message($user['user_id']);
321
            MessageManager::send_message_simple(
322
                $user['user_id'],
323
                $subject,
324
                $message,
325
                $sender['user_id'],
326
                $sendToDrhUsers,
327
                true
328
            );
329
330
            if (($counter % $batchSize) === 0) {
331
                $em->flush();
332
                $em->clear();
333
            }
334
            $counter++;
335
        }
336
337
        if ($sendToUsersInSession) {
338
            $sessionList = SessionManager::get_session_by_course($this->course['real_id']);
339
            if (!empty($sessionList)) {
340
                foreach ($sessionList as $sessionInfo) {
341
                    $sessionId = $sessionInfo['id'];
342
                    $message = $this->message(null);
343
                    $userList = CourseManager::get_user_list_from_course_code(
344
                        $this->course['code'],
345
                        $sessionId
346
                    );
347 View Code Duplication
                    if (!empty($userList)) {
348
                        foreach ($userList as $user) {
0 ignored issues
show
Bug introduced by
The expression $userList of type array|integer is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
349
                            MessageManager::send_message_simple(
350
                                $user['user_id'],
351
                                $subject,
352
                                $message,
353
                                $sender['user_id'],
354
                                false,
355
                                true
356
                            );
357
                        }
358
                    }
359
                }
360
            }
361
        }
362
363
        $this->log_mail_sent();
364
    }
365
366
    /**
367
     * Store that emails where sent
368
     */
369
    public function log_mail_sent()
370
    {
371
        $id = $this->announcement('id');
372
        $course_id = $this->course('id');
373
374
        $table = Database::get_course_table(TABLE_ANNOUNCEMENT);
375
        $sql = "UPDATE $table SET 
376
                email_sent = 1
377
                WHERE 
378
                    c_id = $course_id AND 
379
                    id = $id AND 
380
                    session_id = {$this->session_id} 
381
                ";
382
        Database::query($sql);
383
    }
384
}
385