Completed
Push — master ( d5b39b...ee3fd0 )
by Julito
27:10
created

AnnouncementEmail::sender()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 2
dl 0
loc 5
rs 9.4285
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
    public $logger;
16
17
    /**
18
     * @param array $courseInfo
19
     * @param int $sessionId
20
     * @param int $announcementId
21
     * @param \Monolog\Logger $logger
22
     */
23
    public function __construct($courseInfo, $sessionId, $announcementId, $logger = null)
24
    {
25
        if (empty($courseInfo)) {
26
            $courseInfo = api_get_course_info();
27
        }
28
29
        $this->course = $courseInfo;
30
        $this->session_id = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
31
32
        if (is_numeric($announcementId)) {
33
            $announcementId = AnnouncementManager::get_by_id($courseInfo['real_id'], $announcementId);
34
        }
35
        $this->announcement = $announcementId;
36
        $this->logger = $logger;
37
    }
38
39
    /**
40
     * Course info
41
     *
42
     * @param string $key
43
     *
44
     * @return string|null
45
     */
46
    public function course($key = '')
47
    {
48
        $result = $key ? $this->course[$key] : $this->course;
49
        $result = $key == 'id' ? intval($result) : $result;
50
51
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result also could return the type array which is incompatible with the documented return type null|string.
Loading history...
52
    }
53
54
    /**
55
     * Announcement info
56
     *
57
     * @param string $key
58
     * @return array
59
     */
60
    public function announcement($key = '')
61
    {
62
        $result = $key ? $this->announcement[$key] : $this->announcement;
63
        $result = $key == 'id' ? intval($result) : $result;
64
65
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result also could return the type integer which is incompatible with the documented return type array.
Loading history...
66
    }
67
68
    /**
69
     * Returns either all course users or all session users depending on whether
70
     * session is turned on or not
71
     *
72
     * @return array
73
     */
74
    public function all_users()
75
    {
76
        $courseCode = $this->course('code');
77
        if (empty($this->session_id)) {
78
            $group_id = api_get_group_id();
79
            if (empty($group_id)) {
80
                $userList = CourseManager::get_user_list_from_course_code($courseCode);
81
            } else {
82
                $userList = GroupManager::get_users($group_id);
83
                $new_user_list = [];
84
                foreach ($userList as $user) {
85
                    $new_user_list[] = ['user_id' => $user];
86
                }
87
                $userList = $new_user_list;
88
            }
89
        } else {
90
            $userList = CourseManager::get_user_list_from_course_code(
91
                $courseCode,
92
                $this->session_id
93
            );
94
        }
95
96
        return $userList;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $userList also could return the type integer which is incompatible with the documented return type array.
Loading history...
97
    }
98
99
    /**
100
     * Returns users and groups an announcement item has been sent to.
101
     *
102
     * @return array Array of users and groups to whom the element has been sent
103
     */
104
    public function sent_to_info()
105
    {
106
        $result = [];
107
        $result['groups'] = [];
108
        $result['users'] = [];
109
110
        $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
111
        $tool = TOOL_ANNOUNCEMENT;
112
        $id = $this->announcement('id');
113
        $course_id = $this->course('real_id');
114
        $sessionCondition = api_get_session_condition($this->session_id);
115
116
        $sql = "SELECT to_group_id, to_user_id
117
                FROM $table
118
                WHERE
119
                    c_id = $course_id AND
120
                    tool = '$tool' AND
121
                    ref = $id
122
                    $sessionCondition";
123
124
        $rs = Database::query($sql);
125
126
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
127
            // if to_user_id <> 0 then it is sent to a specific user
128
            $user_id = $row['to_user_id'];
129
            if (!empty($user_id)) {
130
                $result['users'][] = (int) $user_id;
131
                // If user is set then skip the group
132
                continue;
133
            }
134
135
            // if to_group_id is null then it is sent to a specific user
136
            // if to_group_id = 0 then it is sent to everybody
137
            $group_id = $row['to_group_id'];
138
            if (!empty($group_id)) {
139
                $result['groups'][] = (int) $group_id;
140
            }
141
        }
142
143
        return $result;
144
    }
145
146
    /**
147
     * Returns the list of user info to which an announcement was sent.
148
     * This function returns a list of actual users even when recipient
149
     * are groups
150
     *
151
     * @return array
152
     */
153
    public function sent_to()
154
    {
155
        $sent_to = $this->sent_to_info();
156
        $users = $sent_to['users'];
157
        $users = $users ? $users : [];
158
        $groups = $sent_to['groups'];
159
160
        if ($users) {
161
            $users = UserManager::get_user_list_by_ids($users, true);
162
        }
163
164
        if (!empty($groups)) {
165
            $groupUsers = GroupManager::get_groups_users($groups);
166
            $groupUsers = UserManager::get_user_list_by_ids($groupUsers, true);
167
168
            if (!empty($groupUsers)) {
169
                $users = array_merge($users, $groupUsers);
170
            }
171
        }
172
173
        if (empty($users)) {
174
            if (!empty($this->logger)) {
175
                $this->logger->addInfo('User list is empty. No users found. Trying all_users()');
176
            }
177
            $users = self::all_users();
0 ignored issues
show
Bug Best Practice introduced by
The method AnnouncementEmail::all_users() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

177
            /** @scrutinizer ignore-call */ 
178
            $users = self::all_users();
Loading history...
178
        }
179
180
        // Clean users just in case
181
        $newListUsers = [];
182
        if (!empty($users)) {
183
            foreach ($users as $user) {
184
                $newListUsers[$user['user_id']] = ['user_id' => $user['user_id']];
185
            }
186
        }
187
188
        return $newListUsers;
189
    }
190
191
    /**
192
     * Email subject
193
     *
194
     * @return string
195
     */
196
    public function subject()
197
    {
198
        $result = $this->course('title').' - '.$this->announcement('title');
0 ignored issues
show
Bug introduced by
Are you sure $this->announcement('title') of type array can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

198
        $result = $this->course('title').' - './** @scrutinizer ignore-type */ $this->announcement('title');
Loading history...
199
        $result = stripslashes($result);
200
201
        return $result;
202
    }
203
204
    /**
205
     * Email message
206
     * @param int $receiverUserId
207
     *
208
     * @return string
209
     */
210
    public function message($receiverUserId)
211
    {
212
        $content = $this->announcement('content');
213
        $session_id = $this->session_id;
214
        $courseCode = $this->course('code');
215
216
        $content = AnnouncementManager::parse_content(
217
            $receiverUserId,
218
            $content,
219
            $courseCode,
220
            $session_id
221
        );
222
223
        // Build the link by hand because api_get_cidreq() doesn't accept course params
224
        $course_param = 'cidReq='.$courseCode.'&id_session='.$session_id.'&gidReq='.api_get_group_id();
225
        $course_name = $this->course('title');
226
227
        $result = "<div>$content</div>";
228
229
        // Adding attachment
230
        $attachment = $this->attachment();
231
        if (!empty($attachment)) {
232
            $result .= '<br />';
233
            $result .= Display::url(
234
                $attachment['filename'],
235
                api_get_path(WEB_CODE_PATH).'announcements/download.php?file='.basename($attachment['path']).'&'.$course_param
236
            );
237
            $result .= '<br />';
238
        }
239
240
        $result .= '<hr />';
241
        $userInfo = api_get_user_info();
242
        if (!empty($userInfo)) {
243
            $result .= '<a href="mailto:'.$userInfo['mail'].'">'.$userInfo['complete_name'].'</a><br/>';
244
        }
245
        $result .= '<a href="'.api_get_path(WEB_CODE_PATH).'announcements/announcements.php?'.$course_param.'">'.$course_name.'</a><br/>';
246
247
        return $result;
248
    }
249
250
    /**
251
     * Returns the one file that can be attached to an announcement.
252
     *
253
     * @return array
254
     */
255
    public function attachment()
256
    {
257
        $result = [];
258
        $table = Database::get_course_table(TABLE_ANNOUNCEMENT_ATTACHMENT);
259
        $id = $this->announcement('id');
260
        $course_id = $this->course('real_id');
261
        $sql = "SELECT * FROM $table 
262
                WHERE c_id = $course_id AND announcement_id = $id ";
263
        $rs = Database::query($sql);
264
        $course_path = $this->course('directory');
265
        while ($row = Database::fetch_array($rs)) {
266
            $path = api_get_path(SYS_COURSE_PATH).$course_path.'/upload/announcements/'.$row['path'];
267
            $filename = $row['filename'];
268
            $result[] = ['path' => $path, 'filename' => $filename];
269
        }
270
271
        $result = $result ? reset($result) : [];
272
273
        return $result;
274
    }
275
276
    /**
277
     * Send emails to users.
278
     * @param bool $sendToUsersInSession
279
     * @param bool $sendToDrhUsers send a copy of the message to the DRH users
280
     * @param int $senderId
281
     * related to the main user
282
     */
283
    public function send($sendToUsersInSession = false, $sendToDrhUsers = false, $senderId = 0)
284
    {
285
        $senderId = empty($senderId) ? api_get_user_id() : (int) $senderId;
286
        $subject = $this->subject();
287
288
        // Send email one by one to avoid antispam
289
        $users = $this->sent_to();
290
291
        $batchSize = 20;
292
        $counter = 1;
293
        $em = Database::getManager();
294
295
        if (empty($users) && !empty($this->logger)) {
296
            $this->logger->addInfo('User list is empty. No emails will be sent.');
297
        }
298
299
        foreach ($users as $user) {
300
            if (!empty($this->logger)) {
301
                $this->logger->addInfo('Announcement: #'.$this->announcement('id').'. Send email to user: #'.$user['user_id']);
0 ignored issues
show
Bug introduced by
Are you sure $this->announcement('id') of type array can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

301
                $this->logger->addInfo('Announcement: #'./** @scrutinizer ignore-type */ $this->announcement('id').'. Send email to user: #'.$user['user_id']);
Loading history...
302
            }
303
            $message = $this->message($user['user_id']);
304
            MessageManager::send_message_simple(
305
                $user['user_id'],
306
                $subject,
307
                $message,
308
                $senderId,
309
                $sendToDrhUsers,
310
                true
311
            );
312
313
            if (($counter % $batchSize) === 0) {
314
                $em->flush();
315
                $em->clear();
316
            }
317
            $counter++;
318
        }
319
320
        if ($sendToUsersInSession) {
321
            $sessionList = SessionManager::get_session_by_course($this->course['real_id']);
322
            if (!empty($sessionList)) {
323
                foreach ($sessionList as $sessionInfo) {
324
                    $sessionId = $sessionInfo['id'];
325
                    $message = $this->message(null);
326
                    $userList = CourseManager::get_user_list_from_course_code(
327
                        $this->course['code'],
328
                        $sessionId
329
                    );
330
                    if (!empty($userList)) {
331
                        foreach ($userList as $user) {
0 ignored issues
show
Bug introduced by
The expression $userList of type integer is not traversable.
Loading history...
332
                            MessageManager::send_message_simple(
333
                                $user['user_id'],
334
                                $subject,
335
                                $message,
336
                                $senderId,
337
                                false,
338
                                true
339
                            );
340
                        }
341
                    }
342
                }
343
            }
344
        }
345
346
        $this->logMailSent();
347
    }
348
349
    /**
350
     * Store that emails where sent
351
     */
352
    public function logMailSent()
353
    {
354
        $id = $this->announcement('id');
355
        $course_id = $this->course('real_id');
356
        $table = Database::get_course_table(TABLE_ANNOUNCEMENT);
357
        $sql = "UPDATE $table SET 
358
                email_sent = 1
359
                WHERE 
360
                    c_id = $course_id AND 
361
                    id = $id AND 
362
                    session_id = {$this->session_id} 
363
                ";
364
        Database::query($sql);
365
    }
366
}
367