• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Freegle / iznik-server / a4cc767e-c60d-43a5-a517-3235bba39197

pending completion
a4cc767e-c60d-43a5-a517-3235bba39197

push

circleci

edwh
Fix LoveJunk test on Circle.

1 of 1 new or added line in 1 file covered. (100.0%)

19645 of 20679 relevant lines covered (95.0%)

32.41 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.4
/http/api/message.php
1
<?php
2
namespace Freegle\Iznik;
3

4
function message() {
5
    global $dbhr, $dbhm;
6

7
    $myid = Session::whoAmId($dbhr, $dbhm);
65✔
8

9
    $id = (Utils::presint('id', $_REQUEST, NULL));
65✔
10
    $tnpostid = (Utils::presint('tnpostid', $_REQUEST, NULL));
65✔
11
    $ret = [ 'ret' => 100, 'status' => 'Unknown verb' ];
65✔
12

13
    $ids = [ NULL ];
65✔
14

15
    if ($tnpostid && !$id) {
65✔
16
        # Get the (potentially multiple) messages which have this TN id.
17
        $m = new Message($dbhr, $dbhm);
1✔
18
        $ids = $m->findByTnPostId($tnpostid);
1✔
19
    } else if ($id) {
64✔
20
        $ids = [ $id ];
63✔
21
    }
22

23
    # Normally we have just one id, but if we are (for example) doing an edit from TN, we should apply it to all messages.
24
    foreach ($ids as $id) {
65✔
25
        $collection = Utils::presdef('collection', $_REQUEST, MessageCollection::APPROVED);
65✔
26
        $groupid = (Utils::presint('groupid', $_REQUEST, NULL));
65✔
27
        $reason = Utils::presdef('reason', $_REQUEST, NULL);
65✔
28
        $action = Utils::presdef('action', $_REQUEST, NULL);
65✔
29
        $subject = Utils::presdef('subject', $_REQUEST, NULL);
65✔
30
        $body = Utils::presdef('body', $_REQUEST, NULL);
65✔
31
        $stdmsgid = (Utils::presint('stdmsgid', $_REQUEST, NULL));
65✔
32
        $messagehistory = array_key_exists('messagehistory', $_REQUEST) ? filter_var($_REQUEST['messagehistory'], FILTER_VALIDATE_BOOLEAN) : FALSE;
65✔
33
        $localonly = array_key_exists('localonly', $_REQUEST) ? filter_var($_REQUEST['localonly'], FILTER_VALIDATE_BOOLEAN) : FALSE;
65✔
34
        $userid = (Utils::presint('userid', $_REQUEST, NULL));
65✔
35
        $userid = $userid ? $userid : NULL;
65✔
36
        $summary = array_key_exists('summary', $_REQUEST) ? filter_var($_REQUEST['summary'], FILTER_VALIDATE_BOOLEAN) : FALSE;
65✔
37

38
        $ret = [ 'ret' => 100, 'status' => 'Unknown verb' ];
65✔
39
        $ischat = FALSE;
65✔
40

41
        switch ($_REQUEST['type']) {
65✔
42
            case 'GET':
65✔
43
            case 'PUT':
54✔
44
            case 'DELETE': {
53✔
45
                $m = new Message($dbhr, $dbhm, $id);
47✔
46

47
                if ((!$m->getID() && $collection != MessageCollection::DRAFT) || $m->getDeleted()) {
47✔
48
                    $ret = ['ret' => 3, 'status' => 'Message does not exist'];
1✔
49
                    $m = NULL;
1✔
50
                } else {
51
                    switch ($collection) {
52
                        case MessageCollection::APPROVED:
53
                        case MessageCollection::DRAFT:
54
                            # No special checks for approved or draft - we could even be logged out.
55
                            break;
44✔
56
                        case MessageCollection::PENDING:
57
                        case MessageCollection::REJECTED:
58
                            if (!$myid) {
4✔
59
                                $ret = ['ret' => 1, 'status' => 'Not logged in'];
2✔
60
                                $m = NULL;
2✔
61
                            } else {
62
                                $groups = $m->getGroups();
4✔
63
                                $me = Session::whoAmI($dbhr, $dbhm);
4✔
64

65
                                if (count($groups) == 0 || !$groupid || ($me && !$me->isModOrOwner($groups[0]))) {
4✔
66
                                    $ret = ['ret' => 2, 'status' => 'Permission denied 1'];
2✔
67
                                    $m = NULL;
2✔
68
                                }
69
                            }
70
                            break;
4✔
71
                        case MessageCollection::CHAT:
72
                            # We can see the original message for a chat if we're a mod.  This is used in chat
73
                            # message review when we want to show the source.
74
                            $me = Session::whoAmI($dbhr, $dbhm);
1✔
75

76
                            if (!$myid || !$me->isModerator() || !$m->isChatByEmail()) {
1✔
77
                                $ret = ['ret' => 2, 'status' => 'Permission denied 3'];
1✔
78
                                $m = NULL;
1✔
79
                            } else {
80
                                $ischat = TRUE;
1✔
81
                            }
82
                            break;
1✔
83
                        default:
84
                            # If they don't say what they're doing properly, they can't do it.
85
                            $m = NULL;
1✔
86
                            $ret = [ 'ret' => 101, 'status' => 'Bad collection' ];
1✔
87
                            break;
1✔
88
                    }
89
                }
90

91
                if ($m) {
47✔
92
                    if ($_REQUEST['type'] == 'GET') {
46✔
93
                        $userlist = [];
30✔
94
                        $locationlist = [];
30✔
95
                        $atts = $m->getPublic($messagehistory, FALSE, FALSE, $userlist, $locationlist, $summary);
30✔
96
                        $me = Session::whoAmI($dbhr, $dbhm);
30✔
97
                        $mod = $me && $me->isModerator();
30✔
98

99
                        if ($mod && count($atts['groups']) == 0) {
30✔
100
                            $atts['message'] = $m->getPrivate('message');
1✔
101
                        }
102

103
                        $cansee = $summary || $m->canSee($atts) || $ischat;
30✔
104

105
                        # We want to return the groups info even if we can't see the message, so that we can tell them
106
                        # which group to join.
107
                        $ret = [
30✔
108
                            'ret' => 2,
109
                            'status' => 'Permission denied 4',
110
                            'groups' => []
111
                        ];
112

113
                        foreach ($atts['groups'] as &$group) {
30✔
114
                            # The groups info returned in the message is not enough - doesn't include settings, for
115
                            # example.
116
                            $g = Group::get($dbhr, $dbhm, $group['groupid']);
28✔
117
                            $ret['groups'][$group['groupid']] = $g->getPublic();
28✔
118
                        }
119

120
                        if ($cansee) {
30✔
121
                            $ret['ret'] = 0;
30✔
122
                            $ret['status'] = 'Success';
30✔
123
                            $ret['message'] = $atts;
30✔
124
                        }
125
                    } else if ($_REQUEST['type'] == 'PUT') {
23✔
126
                        if ($collection == MessageCollection::DRAFT) {
22✔
127
                            # Draft messages are created by users, rather than parsed out from emails.  We might be
128
                            # creating one, or updating one.
129
                            $locationid = (Utils::presint('locationid', $_REQUEST, NULL));
22✔
130

131
                            $ret = [ 'ret' => 3, 'status' => 'Missing location - client error' ];
22✔
132

133
                            $email = Utils::presdef('email', $_REQUEST, NULL);
22✔
134
                            $sourceheader = Utils::pres('app', $_REQUEST) ? Message::FREEGLE_APP : Message::PLATFORM;
22✔
135
                            $uid = NULL;
22✔
136

137
                            if ($email) {
22✔
138
                                # We're queueing a draft so we need to save the user it.
139
                                $u = new User($dbhr, $dbhm);
×
140
                                $uid = $u->findByEmail($email);
×
141
                            }
142

143
                            if ($locationid) {
22✔
144
                                # We check the ID on the message object to handle the case where the client passes
145
                                # an ID which is not valid on the server.
146
                                if (!$m->getID()) {
22✔
147
                                    $id = $m->createDraft($uid, $sourceheader);
22✔
148

149
                                    # Use the master to avoid any replication windows.
150
                                    $m = new Message($dbhm, $dbhm, $id);
22✔
151

152
                                    # Record the last message we created in our session.  We use this to give access to
153
                                    # this message even if we're not logged in - for example when setting the FOP after
154
                                    # message submission.
155
                                    $_SESSION['lastmessage'] = $id;
22✔
156
                                } else {
157
                                    # The message should be ours.
158
                                    $sql = "SELECT * FROM messages_drafts WHERE msgid = ? AND session = ? OR (userid IS NOT NULL AND userid = ?);";
1✔
159
                                    $drafts = $dbhr->preQuery($sql, [ $id, session_id(), $myid ]);
1✔
160
                                    $m = NULL;
1✔
161
                                    foreach ($drafts as $draft) {
1✔
162
                                        $m = new Message($dbhr, $dbhm, $draft['msgid']);
1✔
163

164
                                        # Update the arrival time so that it doesn't appear to be expired.
165
                                        $m->setPrivate('arrival', date("Y-m-d H:i:s", time()));
1✔
166
                                    }
167

168
                                    # The message is not in drafts.  This can happen if someone creates a draft on one
169
                                    # device, then completes it on another, then goes back to the first and edits the
170
                                    # draft into a new post.  In this case create a new draft message, which will
171
                                    # override the one on the client.
172
                                    if (!$m) {
1✔
173
                                        $m = new Message($dbhr, $dbhm);
1✔
174
                                        $id = $m->createDraft(NULL, $sourceheader);
1✔
175
                                        $m = new Message($dbhm, $dbhm, $id);
1✔
176
                                        $_SESSION['lastmessage'] = $id;
1✔
177
                                    }
178
                                }
179

180
                                if ($m) {
22✔
181
                                    # Drafts have:
182
                                    # - a locationid
183
                                    # - a groupid (optional)
184
                                    # - a type
185
                                    # - an item
186
                                    # - a number available
187
                                    # - a subject constructed from the type, item and location.
188
                                    # - a fromuser if known (we might not have logged in yet)
189
                                    # - a textbody
190
                                    # - zero or more attachments
191
                                    if ($groupid) {
22✔
192
                                        $dbhm->preExec("UPDATE messages_drafts SET groupid = ? WHERE msgid = ?;", [$groupid, $m->getID()]);
22✔
193
                                    }
194

195
                                    $type = Utils::presdef('messagetype', $_REQUEST, NULL);
22✔
196

197
                                    # Associated the item with the message.  Use the master to avoid replication windows.
198
                                    $item = Utils::presdef('item', $_REQUEST, NULL);
22✔
199
                                    $i = new Item($dbhm, $dbhm);
22✔
200
                                    $itemid = $i->create($item);
22✔
201
                                    $m->deleteItems();
22✔
202
                                    $m->addItem($itemid);
22✔
203

204
                                    $fromuser = $myid;
22✔
205

206
                                    if (!$fromuser) {
22✔
207
                                        # Creating a draft - use the supplied email.
208
                                        $fromuser = $uid;
7✔
209
                                    }
210

211
                                    $textbody = Utils::presdef('textbody', $_REQUEST, NULL);
22✔
212
                                    $attachments = Utils::presdef('attachments', $_REQUEST, []);
22✔
213
                                    $m->setPrivate('locationid', $locationid);
22✔
214
                                    $m->setPrivate('type', $type);
22✔
215
                                    $m->setPrivate('subject', $item);
22✔
216
                                    $m->setPrivate('fromuser', $fromuser);
22✔
217
                                    $m->setPrivate('textbody', $textbody);
22✔
218
                                    $m->setPrivate('fromip', Utils::presdef('REMOTE_ADDR', $_SERVER, NULL));
22✔
219

220
                                    $availablenow = Utils::presint('availablenow', $_REQUEST, 1);
22✔
221
                                    $m->setPrivate('availableinitially', $availablenow);
22✔
222
                                    $m->setPrivate('availablenow', $availablenow);
22✔
223

224
                                    $m->replaceAttachments($attachments);
22✔
225

226
                                    $ret = [
22✔
227
                                        'ret' => 0,
228
                                        'status' => 'Success',
229
                                        'id' => $id
230
                                    ];
231
                                }
232
                            }
233
                        }
234
                    } else if ($_REQUEST['type'] == 'DELETE') {
1✔
235
                        $role = $m->getRoleForMessage()[0];
1✔
236
                        if ($role != User::ROLE_OWNER && $role != User::ROLE_MODERATOR) {
1✔
237
                            $ret = ['ret' => 2, 'status' => 'Permission denied 5'];
1✔
238
                        } else {
239
                            $m->delete($reason, NULL, NULL, NULL, NULL, $localonly);
1✔
240
                            $ret = [
1✔
241
                                'ret' => 0,
242
                                'status' => 'Success'
243
                            ];
244
                        }
245
                    }
246
                }
247
            }
248
                break;
47✔
249

250
            case 'PATCH': {
52✔
251
                $m = new Message($dbhr, $dbhm, $id);
11✔
252
                $ret = ['ret' => 3, 'status' => 'Message does not exist'];
11✔
253

254
                if ($m->getID()) {
11✔
255
                    # See if we can modify.
256
                    $canmod = $myid == $m->getFromuser();
11✔
257

258
                    if (!$canmod) {
11✔
259
                        $role = $m->getRoleForMessage()[0];
3✔
260
                        $canmod = $role == User::ROLE_MODERATOR || $role == User::ROLE_OWNER;
3✔
261

262
                        if ($role == User::ROLE_OWNER && Utils::pres('partner', $_SESSION)) {
3✔
263
                            # We have acquired owner rights by virtue of being a partner.  Pretend to be that user for the
264
                            # rest of the call.
265
                            $_SESSION['id'] = $m->getFromuser();
1✔
266
                        }
267
                    }
268

269
                    if ($canmod) {
11✔
270
                        # Ignore the canedit flag here - the client will either show or not show the edit button on this
271
                        # basis but editing is part of the repost flow and therefore needs to work.
272
                        $subject = Utils::presdef('subject', $_REQUEST, NULL);
10✔
273
                        $msgtype = Utils::presdef('msgtype', $_REQUEST, NULL);
10✔
274
                        $item = Utils::presdef('item', $_REQUEST, NULL);
10✔
275
                        $locationid = Utils::presint('locationid', $_REQUEST, NULL);
10✔
276
                        $location = Utils::presdef('location', $_REQUEST, NULL);
10✔
277
                        $lat = Utils::presfloat('lat', $_REQUEST, NULL);
10✔
278
                        $lng = Utils::presfloat('lng', $_REQUEST, NULL);
10✔
279
                        $textbody = Utils::presdef('textbody', $_REQUEST, NULL);
10✔
280
                        $fop = array_key_exists('FOP', $_REQUEST) ? $_REQUEST['FOP'] : NULL;
10✔
281
                        $availableinitially = Utils::presint('availableinitially', $_REQUEST, NULL);
10✔
282
                        $availablenow = Utils::presint('availablenow', $_REQUEST, NULL);
10✔
283
                        $attachments = array_key_exists('attachments', $_REQUEST) ? $_REQUEST['attachments'] : NULL;
10✔
284

285
                        $ret = [
10✔
286
                            'ret' => 0,
287
                            'status' => 'Success'
288
                        ];
289

290
                        if (!is_null($availablenow)) {
10✔
291
                            $m->setPrivate('availablenow', $availablenow);
5✔
292
                        }
293

294
                        if (!is_null($availableinitially)) {
10✔
295
                            $m->setPrivate('availableinitially', $availableinitially);
4✔
296
                        }
297

298
                        if ($location && !$locationid) {
10✔
299
                            $l = new Location($dbhr, $dbhm);
4✔
300
                            $locationid = $l->findByName($location);
4✔
301
                        }
302

303
                        if ($subject || $textbody || $msgtype || $item || $locationid || !is_null($attachments) || $lat || $lng) {
10✔
304
                            $partner = Utils::pres('partner', $_SESSION);
9✔
305

306
                            if ($partner) {
9✔
307
                                # Photos might have changed.
308
                                $m->deleteAllAttachments();
1✔
309
                                $textbody = $m->scrapePhotos($textbody);
1✔
310
                                $m->saveAttachments($id);
1✔
311

312
                                # Lat/lng might have changed
313
                                if ($lat || $lng) {
1✔
314
                                    $m->setPrivate('lat', $lat);
1✔
315
                                    $m->setPrivate('lng', $lng);
1✔
316
                                }
317
                            }
318

319
                            $me = Session::whoAmI($dbhr, $dbhm);
9✔
320

321
                            $rc = $m->edit($subject,
9✔
322
                                           $textbody,
323
                                           $msgtype,
324
                                           $item,
325
                                           $locationid,
326
                                           $attachments,
327
                                           TRUE,
328
                                           ($partner || ($me && $me->isApprovedMember($groupid))) ? $groupid : NULL);
9✔
329

330
                            $ret = $rc ? $ret : ['ret' => 2, 'status' => 'Edit failed'];
9✔
331

332
                            if ($rc) {
9✔
333
                                $ret = [
9✔
334
                                    'ret' => 0,
335
                                    'status' => 'Success'
336
                                ];
337
                            }
338
                        }
339

340
                        if (!is_null($fop)) {
10✔
341
                            $m->setFOP($fop);
1✔
342
                        }
343

344
                        if ($groupid) {
10✔
345
                            $dbhm->preExec("UPDATE messages_drafts SET groupid = ? WHERE msgid = ?;", [$groupid, $m->getID()]);
10✔
346
                        }
347
                    } else {
348
                        $ret = ['ret' => 2,
2✔
349
                            'status' => 'Permission denied 6',
350
                            'fromuser' => $m->getFromuser()
2✔
351
                        ];
352
                    }
353
                }
354
            }
355
                break;
11✔
356

357
            case 'POST': {
50✔
358
                $m = new Message($dbhr, $dbhm, $id);
50✔
359
                $ret = $m && $id && $m->getId() == $id ? ['ret' => 2, 'status' => 'Permission denied 7 '] : ['ret' => 10, 'status' => 'Message does not exist'];
50✔
360

361
                $role = $m && $id && $m->getId() == $id ? $m->getRoleForMessage()[0] : User::ROLE_NONMEMBER;
50✔
362

363
                if ($id && $m->getID() == $id) {
50✔
364
                    # These actions don't require permission, but they do need to be logged in as they record the userid.
365
                    if ($myid) {
49✔
366
                        if ($action =='Love') {
39✔
367
                            $m->like($myid, Message::LIKE_LOVE);
1✔
368
                            $ret = [ 'ret' => 0, 'status' => 'Success' ];
1✔
369
                        } else if ($action == 'Unlove') {
39✔
370
                            $m->unlike($myid, Message::LIKE_LOVE);
1✔
371
                            $ret = [ 'ret' => 0, 'status' => 'Success' ];
1✔
372
                        } else if ($action == 'Laugh') {
39✔
373
                            $m->like($myid, Message::LIKE_LAUGH);
1✔
374
                            $ret = [ 'ret' => 0, 'status' => 'Success' ];
1✔
375
                        } else if ($action == 'Unlaugh') {
39✔
376
                            $m->unlike($myid, Message::LIKE_LAUGH);
1✔
377
                            $ret = [ 'ret' => 0, 'status' => 'Success' ];
1✔
378
                        } else if ($action == 'View') {
39✔
379
                            $m->like($myid, Message::LIKE_VIEW);
1✔
380
                            $ret = ['ret' => 0, 'status' => 'Success'];
39✔
381
                        }
382
                    } else if ($action == 'View') {
19✔
383
                        // We don't currently record logged out views.
384
                        $ret = ['ret' => 0, 'status' => 'Success'];
1✔
385
                    }
386
                }
387

388
                if ($role == User::ROLE_MODERATOR || $role == User::ROLE_OWNER) {
50✔
389
                    $ret = [ 'ret' => 0, 'status' => 'Success' ];
48✔
390

391
                    switch ($action) {
392
                        case 'Delete':
48✔
393
                            # The delete call will handle any rejection on Yahoo if required.
394
                            $m->delete($reason, NULL, $subject, $body, $stdmsgid);
1✔
395
                            break;
1✔
396
                        case 'Reject':
48✔
397
                            # Ignore requests for messages which aren't pending.  Legitimate timing window when there
398
                            # are multiple mods.
399
                            if ($m->isPending($groupid)) {
3✔
400
                                $m->reject($groupid, $subject, $body, $stdmsgid);
2✔
401
                            }
402
                            break;
3✔
403
                        case 'Approve':
47✔
404
                            # Ignore requests for messages which aren't pending.  Legitimate timing window when there
405
                            # are multiple mods.
406
                            if ($m->isPending($groupid)) {
8✔
407
                                $m->approve($groupid, $subject, $body, $stdmsgid);
8✔
408
                            }
409
                            break;
8✔
410
                        case 'Reply':
43✔
411
                            $m->reply($groupid, $subject, $body, $stdmsgid);
1✔
412
                            break;
1✔
413
                        case 'Hold':
42✔
414
                            $m->hold();
1✔
415
                            break;
1✔
416
                        case 'Release':
42✔
417
                            $m->release();
1✔
418
                            break;
1✔
419
                        case 'Move':
41✔
420
                            $ret = $m->move($groupid);
1✔
421
                            break;
1✔
422
                        case 'Spam':
40✔
423
                            # Record for training.
424
                            $m->spam();
1✔
425
                            break;
1✔
426
                        case 'JoinAndPost':
40✔
427
                            # This is the mainline case for someone posting a message.  We find the nearest group, sign
428
                            # them up if need be, and then post the message.  We do this without being logged in, because
429
                            # that reduces friction.  If there is abuse of this, then we will find other ways to block the
430
                            # abuse.
431
                            $ret = ['ret' => 3, 'status' => 'Not our message'];
21✔
432
                            $sql = "SELECT * FROM messages_drafts WHERE msgid = ?;";
21✔
433
                            $drafts = $dbhr->preQuery($sql, [$id]);
21✔
434
                            $newuser = NULL;
21✔
435
                            $pw = NULL;
21✔
436
                            $hitwindow = FALSE;
21✔
437
                            #error_log("$sql, $id, " . session_id() . ", $myid");
438

439
                            foreach ($drafts as $draft) {
21✔
440
                                $m = new Message($dbhr, $dbhm, $draft['msgid']);
21✔
441

442
                                if (!$draft['groupid']) {
21✔
443
                                    # No group specified.  Find the group nearest the location.
444
                                    $l = new Location($dbhr, $dbhm, $m->getPrivate('locationid'));
×
445
                                    $ret = ['ret' => 4, 'status' => 'No nearby groups found'];
×
446
                                    $nears = $l->groupsNear(200);
×
447
                                } else {
448
                                    # A preferred group for this message.
449
                                    $nears = [ $draft['groupid'] ];
21✔
450
                                }
451

452
                                // @codeCoverageIgnoreStart
453
                                if (defined('USER_GROUP_OVERRIDE') && !Utils::pres('ignoregroupoverride', $_REQUEST)) {
454
                                    # We're in testing mode
455
                                    $g = new Group($dbhr, $dbhm);
456
                                    $nears = [ $g->findByShortName(USER_GROUP_OVERRIDE) ];
457
                                }
458
                                // @codeCoverageIgnoreEnd
459

460
                                if (count($nears) > 0) {
21✔
461
                                    $groupid = $nears[0];
21✔
462

463
                                    # Now we know which group we'd like to post on.  Make sure we have a user set up.
464
                                    $email = Utils::presdef('email', $_REQUEST, NULL);
21✔
465

466
                                    $u = User::get($dbhr, $dbhm);
21✔
467

468
                                    $ret = ['ret' => 5, 'status' => 'Failed to create user or email'];
21✔
469
                                    $unvalidated = FALSE;
21✔
470

471
                                    if (!$email) {
21✔
472
                                        # The client ought to provide one.  But if they don't and we're logged in
473
                                        # then we can use ours.
474
                                        $me = Session::whoAmI($dbhr, $dbhm);
1✔
475

476
                                        if ($me) {
1✔
477
                                            $uid = $me->getId();
1✔
478
                                            $email = $me->getEmailPreferred();
1✔
479
                                        }
480
                                    } else {
481
                                        list ($uid, $unvalidated) = $u->findByEmailIncludingUnvalidated($email);
20✔
482

483
                                        if ($unvalidated) {
20✔
484
                                            // They have tried to submit with an email which has not yet been validated
485
                                            // by them.
486
                                            $ret = ['ret' => 11, 'status' => 'Unvalidated email'];
1✔
487
                                        }
488
                                    }
489

490
                                    if (!$unvalidated) {
21✔
491
                                        if (!$uid) {
20✔
492
                                            # We don't yet know this user.  Create them.
493
                                            $name = substr($email, 0, strpos($email, '@'));
4✔
494
                                            $newuser = $u->create(null, null, $name, 'Created to allow post');
4✔
495

496
                                            # Create a password and mail it to them.  Also log them in and return it.  This
497
                                            # avoids us having to ask the user for a password, though they can change it if
498
                                            # they like.  Less friction.
499
                                            $pw = $u->inventPassword();
4✔
500
                                            $u->addLogin(User::LOGIN_NATIVE, $newuser, $pw);
4✔
501
                                            $eid = $u->addEmail($email, 1);
4✔
502

503
                                            if (!$eid) {
4✔
504
                                                # There's a timing window where a parallel request could have added this
505
                                                # email.  Check.
506
                                                $uid2 = $u->findByEmail($email);
×
507

508
                                                if ($uid2) {
×
509
                                                    # That has happened.  Delete the user we created and use the other.
510
                                                    $u->delete();
×
511
                                                    $newuser = null;
×
512
                                                    $pw = null;
×
513
                                                    $hitwindow = true;
×
514

515
                                                    $u = User::get($dbhr, $dbhm, $uid2);
×
516
                                                    $eid = $u->getIdForEmail($email)['id'];
×
517

518
                                                    if ($u->getEmailPreferred() != $email) {
×
519
                                                        # The email specified is the one they currently want to use - make sure it's
520
                                                        $u->addEmail($email, 1, true);
×
521
                                                    }
522
                                                }
523
                                            } else {
524
                                                $u->login($pw);
4✔
525
                                                $u->welcome($email, $pw);
4✔
526
                                            }
527
                                        } else if ($myid && $myid != $uid) {
16✔
528
                                            # We know the user, but it's not the one we're logged in as.  It's most likely
529
                                            # that the user is just confused about multiple email addresses.  We will reject
530
                                            # the message - the client is supposed to detect this case earlier on.
531
                                            $ret = ['ret' => 6, 'status' => 'That email address is in use for a different user.'];
1✔
532
                                        } else {
533
                                            $u = User::get($dbhr, $dbhm, $uid);
15✔
534
                                            $eid = $u->getIdForEmail($email)['id'];
15✔
535

536
                                            if ($u->getEmailPreferred() != $email) {
15✔
537
                                                # The email specified is the one they currently want to use - make sure it's
538
                                                # in there.
539
                                                $u->addEmail($email, 1, TRUE);
11✔
540
                                            }
541
                                        }
542

543
                                        if ($u->getId() && $eid) {
20✔
544
                                            # Now we have a user and an email.  We need to make sure they're a member of the
545
                                            # group in question.
546
                                            $g = Group::get($dbhr, $dbhm, $groupid);
19✔
547
                                            $fromemail = NULL;
19✔
548
                                            $cont = TRUE;
19✔
549

550
                                            # Check the message for worry words.
551
                                            $w = new WorryWords($dbhr, $dbhm, $groupid);
19✔
552
                                            $worry = $w->checkMessage($m->getID(), $m->getFromuser(), $m->getSubject(), $m->getTextbody());
19✔
553

554
                                            # Assume this post is moderated unless we decide otherwise below.
555
                                            $me = Session::whoAmI($dbhr, $dbhm);
19✔
556

557
                                            if ($u->isBanned($groupid)) {
19✔
558
                                                # We're not allowed to post.
559
                                                $cont = FALSE;
1✔
560
                                                $ret = ['ret' => 9, 'status' => 'Banned from this group'];
1✔
561
                                            } else if (!$u->isApprovedMember($groupid)) {
18✔
562
                                                # We're not yet a member.  Join the group.
563
                                                $addworked = $u->addMembership($groupid);
6✔
564

565
                                                # This is now a member, and we always moderate posts from new members,
566
                                                # so this goes to pending.
567
                                                $postcoll = MessageCollection::PENDING;
6✔
568

569
                                                if ($addworked === FALSE) {
6✔
570
                                                    # We couldn't join - we're banned.  Suppress the message below.
571
                                                    $cont = FALSE;
×
572

573
                                                    # Pretend it worked, if we suppressed a banned message.
574
                                                    $ret = ['ret' => 0, 'status' => 'Success', 'groupid' => $groupid, 'id' => $id];
6✔
575
                                                }
576
                                            } else if ($me && $me->getMembershipAtt($groupid, 'ourPostingStatus') == Group::POSTING_PROHIBITED) {
13✔
577
                                                # We're not allowed to post.
578
                                                $cont = FALSE;
1✔
579
                                                $ret = ['ret' => 8, 'status' => 'Not allowed to post on this group'];
1✔
580
                                            } else {
581
                                                # They're already a member, so we might be able to put this straight
582
                                                # to approved.
583
                                                #
584
                                                # The entire group might be moderated, or the member might be, in which
585
                                                # case the message goes to pending, otherwise approved.
586
                                                #
587
                                                # Worrying messages always go to Pending.
588
                                                if ($worry || $g->getPrivate('overridemoderation') ==  Group::OVERRIDE_MODERATION_ALL) {
12✔
589
                                                    $postcoll = MessageCollection::PENDING;
2✔
590
                                                } else {
591
                                                    $postcoll = ($g->getSetting('moderated', 0) || $g->getSetting('close', 0)) ? MessageCollection::PENDING : $u->postToCollection($groupid);
10✔
592
                                                }
593
                                            }
594

595
                                            # Check if it's spam
596
                                            $s = new Spam($dbhr, $dbhm);
19✔
597
                                            list ($rc, $reason) = $s->checkMessage($m);
19✔
598

599
                                            if ($rc) {
19✔
600
                                                # It is.  Put in pending for review.
601
                                                $postcoll = MessageCollection::PENDING;
1✔
602
                                            }
603

604
                                            if ($worry) {
19✔
605
                                                $m->setPrivate('spamtype', Spam::REASON_WORRY_WORD);
1✔
606
                                                $m->setPrivate('spamreason','Referred to worry word ' . $worry[0]['worryword']['keyword']);
1✔
607
                                            }
608

609
                                            # We want the message to come from one of our emails rather than theirs, so
610
                                            # that replies come back to us and privacy is maintained.
611
                                            $fromemail = $u->inventEmail();
19✔
612

613
                                            # Make sure this email is attached to the user so that we don't invent
614
                                            # another next time.
615
                                            $u->addEmail($fromemail, 0, FALSE);
19✔
616

617
                                            $m->constructSubject($groupid);
19✔
618

619
                                            if ($cont) {
19✔
620
                                                if ($fromemail) {
17✔
621
                                                    $dbhm->preExec("INSERT IGNORE INTO messages_groups (msgid, groupid, collection,arrival, msgtype) VALUES (?,?,?,NOW(),?);", [
17✔
622
                                                        $draft['msgid'],
17✔
623
                                                        $groupid,
624
                                                        $postcoll,
625
                                                        $m->getType()
17✔
626
                                                    ]);
627

628
                                                    $ret = ['ret' => 7, 'status' => 'Failed to submit'];
17✔
629

630
                                                    if ($m->submit($u, $fromemail, $groupid)) {
17✔
631
                                                        # We sent it.
632
                                                        $ret = ['ret' => 0, 'status' => 'Success', 'groupid' => $groupid];
17✔
633

634
                                                        if ($postcoll == MessageCollection::APPROVED) {
17✔
635
                                                            # We index now; for pending messages we index when they are approved.
636
                                                            $m->addToSpatialIndex();
2✔
637
                                                            $m->index();
2✔
638
                                                        }
639
                                                    }
640
                                                }
641
                                            }
642

643
                                            # This user has been active recently.
644
                                            $dbhm->background("UPDATE users SET lastaccess = NOW() WHERE id = " . $u->getId() . ";");
19✔
645
                                        }
646
                                    }
647
                                }
648
                            }
649

650
                            $ret['newuser'] = $newuser;
21✔
651
                            $ret['newpassword'] = $pw;
21✔
652
                            $ret['hitwindow'] = $hitwindow;
21✔
653

654
                            break;
21✔
655
                        case 'BackToDraft':
25✔
656
                        case 'RejectToDraft':
25✔
657
                            # This is a message which has been rejected or reposted, which we are now going to edit.
658
                            $ret = ['ret' => 3, 'status' => 'Message does not exist'];
1✔
659
                            $sql = "SELECT * FROM messages WHERE id = ?;";
1✔
660
                            $msgs = $dbhr->preQuery($sql, [ $id ]);
1✔
661

662
                            foreach ($msgs as $msg) {
1✔
663
                                $m = new Message($dbhr, $dbhm, $id);
1✔
664
                                $ret = ['ret' => 4, 'status' => 'Failed to edit message'];
1✔
665

666
                                $role = $m->getRoleForMessage()[0];
1✔
667

668
                                if ($role == User::ROLE_MODERATOR || $role = User::ROLE_OWNER) {
1✔
669
                                    $rc = $m->backToDraft();
1✔
670

671
                                    if ($rc) {
1✔
672
                                        $ret = ['ret' => 0, 'status' => 'Success', 'messagetype' => $m->getType() ];
1✔
673
                                    }
674
                                }
675
                            }
676
                            break;
1✔
677
                        case 'RevertEdits':
24✔
678
                            $editid = (Utils::presint('editid', $_REQUEST, 0));
2✔
679
                            $role = $m->getRoleForMessage()[0];
2✔
680

681
                            if ($role ==  User::ROLE_OWNER || $role ==  User::ROLE_MODERATOR) {
2✔
682
                                $m->revertEdit($editid);
2✔
683
                                $ret = ['ret' => 0, 'status' => 'Success' ];
2✔
684
                            }
685
                            break;
2✔
686
                        case 'ApproveEdits':
24✔
687
                            $editid = (Utils::presint('editid', $_REQUEST, 0));
2✔
688
                            $role = $m->getRoleForMessage()[0];
2✔
689

690
                            if ($role ==  User::ROLE_OWNER || $role ==  User::ROLE_MODERATOR) {
2✔
691
                                $m->approveEdit($editid);
2✔
692
                                $ret = ['ret' => 0, 'status' => 'Success' ];
2✔
693
                            }
694
                            break;
2✔
695
                        case 'PartnerConsent':
24✔
696
                            $partner = Utils::presdef('partner', $_REQUEST, NULL);
1✔
697
                            $ret = ['ret' => 5, 'status' => 'Invalid parameters' ];
1✔
698

699
                            $role = $m->getRoleForMessage()[0];
1✔
700

701
                            if ($partner && ($role ==  User::ROLE_OWNER || $role ==  User::ROLE_MODERATOR)) {
1✔
702
                                if ($m->partnerConsent($partner)) {
1✔
703
                                    $ret = ['ret' => 0, 'status' => 'Success' ];
1✔
704
                                }
705
                            }
706
                            break;
1✔
707
                    }
708
                }
709

710
                if ($id && $id == $m->getId()) {
50✔
711
                    # Other actions which we can do on our own messages.
712
                    $canmod = $myid == $m->getFromuser();
49✔
713

714
                    if (!$canmod) {
49✔
715
                        $role = $m->getRoleForMessage()[0];
25✔
716
                        $canmod = $role == User::ROLE_MODERATOR || $role == User::ROLE_OWNER;
25✔
717

718
                        if ($role == User::ROLE_OWNER && Utils::pres('partner', $_SESSION)) {
25✔
719
                            # We have acquired owner rights by virtue of being a partner.  Pretend to be that user for the
720
                            # rest of the call.
721
                            $_SESSION['id'] = $m->getFromuser();
5✔
722
                            $myid = $m->getFromuser();
5✔
723
                        }
724
                    }
725

726
                    if ($canmod) {
49✔
727
                        if ($userid > 0) {
47✔
728
                            $r = new ChatRoom($dbhr, $dbhm);
7✔
729
                            list ($rid, $blocked) = $r->createConversation($myid, $userid);
7✔
730
                            $cm = new ChatMessage($dbhr, $dbhm);
7✔
731
                        }
732

733
                        switch ($action) {
734
                            case 'Promise':
47✔
735
                                if ($userid) {
3✔
736
                                    # Userid is optional - TN can promise without a userid.
737
                                    $m->promise($userid);
3✔
738
                                    list ($mid, $banned) = $cm->create($rid, $myid, NULL, ChatMessage::TYPE_PROMISED, $id);
3✔
739
                                    $ret = ['ret' => 0, 'status' => 'Success', 'id' => $mid];
3✔
740
                                } else {
741
                                    $m->promise($m->getFromuser());
1✔
742
                                    $ret = ['ret' => 0, 'status' => 'Success'];
1✔
743
                                }
744
                                break;
3✔
745
                            case 'Renege':
47✔
746
                                # Userid is optional - TN doesn't use it.
747
                                if ($userid > 0) {
2✔
748
                                    $m->renege($userid);
2✔
749
                                    list ($mid, $banned) = $cm->create($rid, $myid, NULL, ChatMessage::TYPE_RENEGED, $id);
2✔
750
                                    $ret = ['ret' => 0, 'status' => 'Success', 'id' => $mid];
2✔
751
                                } else {
752
                                    $m->renege($m->getFromuser());
1✔
753
                                    $ret = ['ret' => 0, 'status' => 'Success'];
1✔
754
                                }
755

756
                                break;
2✔
757
                            case 'OutcomeIntended':
45✔
758
                                # Ignore duplicate attempts by user to supply an outcome.
759
                                if (!$m->hasOutcome()) {
6✔
760
                                    $outcome = Utils::presdef('outcome', $_REQUEST, NULL);
6✔
761
                                    $m->intendedOutcome($outcome);
6✔
762
                                }
763
                                $ret = ['ret' => 0, 'status' => 'Success'];
6✔
764
                                break;
6✔
765
                            case 'AddBy':
40✔
766
                                $count = Utils::presint('count', $_REQUEST, NULL);
5✔
767

768
                                if (!is_null($count)) {
5✔
769
                                    $m->addBy($userid, $count);
5✔
770
                                    $ret = ['ret' => 0, 'status' => 'Success'];
5✔
771
                                }
772
                                break;
5✔
773
                            case 'RemoveBy':
40✔
774
                                $m->removeBy($userid);
4✔
775
                                $ret = ['ret' => 0, 'status' => 'Success'];
4✔
776
                                break;
4✔
777
                            case 'Outcome':
40✔
778
                                # Ignore duplicate attempts by user to supply an outcome.
779
                                if (!$m->hasOutcome()) {
10✔
780
                                    $outcome = Utils::presdef('outcome', $_REQUEST, NULL);
10✔
781
                                    $h = Utils::presdef('happiness', $_REQUEST, NULL);
10✔
782
                                    $happiness = NULL;
10✔
783

784
                                    switch ($h) {
785
                                        case User::HAPPY:
786
                                        case User::FINE:
787
                                        case User::UNHAPPY:
788
                                            $happiness = $h;
2✔
789
                                            break;
2✔
790
                                    }
791

792
                                    $comment = Utils::presdef('comment', $_REQUEST, NULL);
10✔
793

794
                                    $ret = ['ret' => 1, 'status' => 'Odd action'];
10✔
795

796
                                    switch ($outcome) {
797
                                        case Message::OUTCOME_TAKEN: {
798
                                            if ($m->getType() == Message::TYPE_OFFER) {
6✔
799
                                                $m->mark($outcome, $comment, $happiness, $userid);
6✔
800
                                                $ret = ['ret' => 0, 'status' => 'Success'];
6✔
801
                                            };
802
                                            break;
6✔
803
                                        }
804
                                        case Message::OUTCOME_RECEIVED: {
805
                                            if ($m->getType() == Message::TYPE_WANTED) {
2✔
806
                                                $m->mark($outcome, $comment, $happiness, $userid);
2✔
807
                                                $ret = ['ret' => 0, 'status' => 'Success'];
2✔
808
                                            };
809
                                            break;
2✔
810
                                        }
811
                                        case Message::OUTCOME_WITHDRAWN: {
812
                                            $ret = ['ret' => 0, 'status' => 'Success'];
3✔
813

814
                                            # The message might still be pending.
815
                                            $groups = $m->getGroups(FALSE, TRUE);
3✔
816

817
                                            foreach ($groups as $gid) {
3✔
818
                                                if ($m->isPending($gid)) {
3✔
819
                                                    $g = Group::get($dbhr, $dbhm, $gid);
1✔
820

821
                                                    # If a message is withdrawn while it's pending we might as well delete it.
822
                                                    $m->delete("Withdrawn pending");
1✔
823
                                                    $ret['deleted'] = TRUE;
1✔
824
                                                } else {
825
                                                    $m->withdraw($comment, $happiness, $userid);
2✔
826
                                                }
827
                                            }
828

829
                                            break;
10✔
830
                                        }
831
                                    }
832
                                } else {
833
                                    $ret = ['ret' => 0, 'status' => 'Success'];
1✔
834
                                }
835
                                break;
10✔
836
                        }
837
                    }
838
                }
839
            }
840
        }
841
    }
842

843
    return($ret);
65✔
844
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc