Completed
Push — master ( fd92f5...bc11d0 )
by Nick
06:37
created

EditQueue::update_pending_count()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * EditQueue Class
4
 *
5
 * @package TheyWorkForYou
6
 */
7
8
namespace MySociety\TheyWorkForYou;
9
10
/**
11
 * Edit Queue
12
 */
13
14
/*
15
16
[From the WIKI]
17
The EDITQUEUE is a holding point for submitted content additions or modifications before they are made on the core data. It's quite a wide table, so as to hold as many different types of addition/modification as possible.
18
19
These hold details of actions waiting to be approved, such as:
20
21
    * creation or modification of glossary entries
22
    * creation or modification of attributes
23
    * associations
24
    * anything else?
25
26
Specifying which of the above is happening is down to the edit_type field.
27
28
    * edit_id is the unique id of the EDITQUEUE record
29
    * user_id is the id of the user who submitted the edit
30
    * edit_type is the kind of edit being made
31
    * epobject_id_l and epobject_id_h hold both eopbject_ids in the case of a new association, with epobject_id_l holding the single epobject_id if the edit only applies to one object. If there's a completely new object being submitted, this is left blank until the content is approved and then filled in with the new object id.
32
    * time_start and time_end are for associations
33
    * title and body are for new or changed content for a glossary entry
34
    * submitted is the datetime that the content was initially submitted by the user
35
    * editor_id is the id of the editor who made the decision on it
36
    * approved says yay or nay to the edit
37
    * decided is the datetime when the decision was made
38
39
    While we're here...
40
    Whenever a term is added to the glossary, it appears in the editqueue first.
41
    Here it sits until a moderator has approved it, then it goes on it's merry way
42
    to whichever db it be bound.
43
44
    Functions:
45
46
    add()           - pop one on the queue (should then alert moderators somehow)
47
    approve()       - say "yes!" and forward onwards
48
    decline()       - an outright "no!", in the bin you go
49
    refer()         - pass back to the user with suggested alterations
50
    get_pending()   - fetch a list of all TODOs
51
    etc...
52
*/
53
54
// [TODO] what happens when two things with the same name are in the editqueue?
55
56
class EditQueue {
57
58
    public $pending_count = '';
59
60
    public function __construct() {
61
        $this->db = new ParlDB;
0 ignored issues
show
Bug introduced by
The property db does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
62
    }
63
64
    public function add($data) {
65
        // This does the bare minimum.
66
        // The upper object should make sure it's passsing good data.
67
        // (for now!)
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
68
69
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
59% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
70
        print "<pre>";
71
        print_r ($data);
72
        print "</pre>";
73
        */
74
75
        // For editqueue in this instance we need:
76
        //      user_id INTEGER,
77
        //      edit_type INTEGER,
78
        //      (epobject_id_l),
79
        //      title VARCHAR(255),
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
80
        //      body TEXT,
81
        //      submitted DATETIME,
82
83
        global $THEUSER;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
84
85
        $q = $this->db->query("INSERT INTO editqueue
86
                        (user_id, edit_type, title, body, submitted)
87
                        VALUES
88
                        (
89
                        '" . addslashes($THEUSER->user_id()) . "',
90
                        '" . $data['edit_type'] . "',
91
                        '" . addslashes($data['title']) . "',
92
                        '" . addslashes($data['body']) . "',
93
                        '" . $data['posted'] . "'
94
                        );");
95
96
        if ($q->success()) {
97
            // Set the object variables up.
98
            $this->editqueue_id     = $q->insert_id();
99
            $this->title            = $data['title'];
100
            $this->body             = $data['body'];
101
            $this->posted           = $data['posted'];
102
103
            return $this->editqueue_id;
104
105
        } else {
106
            return false;
107
        }
108
    }
109
110
    public function approve($data) {
111
    // Approve items for inclusion
112
    // Create new epobject and update the editqueue
113
114
        global $THEUSER;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
115
116
        // We need a list of editqueue items to play with
117
        $this->get_pending();
118
        if (!isset($this->pending)) {
119
            return false;
120
        }
121
        $timestamp = date('Y-m-d H:i:s', time());
122
123
        foreach ($data['approvals'] as $approval_id) {
124
            // create a new epobject
125
            //      title VARCHAR(255),
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
126
            //      body TEXT,
127
            //      type INTEGER,
128
            //      created DATETIME,
129
            //      modified DATETIME,
130
            /*print "<pre>";
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
131
            print_r($data);
132
            print "</pre>";*/
133
            // Check to see that we actually have something to approve
134
            if (!isset($this->pending[$approval_id])) {
135
                break;
136
            }
137
            $q = $this->db->query("INSERT INTO epobject
138
                            (title, body, type, created)
139
                            VALUES
140
                            ('" . addslashes($this->pending[$approval_id]['title']) . "',
141
                            '" . addslashes($this->pending[$approval_id]['body']) . "',
142
                            '" . $data['epobject_type'] . "',
143
                            '" . $timestamp . "');");
144
145
            // If that didn't work we can't go any further...
146
            if (!$q->success()) {
147
                print "epobject trouble";
148
                return false;
149
            }
150
            $this->current_epobject_id = $q->insert_id();
151
152
            // depending on the epobject type, we'll need to make
153
            // entries in different tables.
154
            switch ($data['epobject_type']) {
155
156
                // glossary item
157
                case 2:
158
                    $previous_insert_id = $q->insert_id();
159
                    $q = $this->db->query("INSERT INTO glossary
160
                                    (epobject_id, type, visible)
161
                                    VALUES
162
                                    ('" . $q->insert_id() . "',
163
                                    '2',
164
                                    '1');");
165
                    // Again, no point carrying on if this fails,
166
                    // so remove the previous entry
167
                    if (!$q->success()) {
168
                        print "glossary trouble!";
169
                        $q = $this->db->query("delete from epobject where epobject_id=" . $previous_insert_id . "");
170
                        return false;
171
                    }
172
                    break;
173
174
            }
175
            $this->current_subclass_id = $q->insert_id();
176
177
            // Then finally update the editqueue with
178
            // the new epobject id and approval details.
179
            $q = $this->db->query("UPDATE editqueue
180
                            SET
181
                            epobject_id_l='" .  $this->current_epobject_id. "',
182
                            editor_id='" . addslashes($THEUSER->user_id()) . "',
183
                            approved='1',
184
                            decided='" . $timestamp . "'
185
                            WHERE edit_id=" . $approval_id . ";");
186
            if (!$q->success()) {
187
                break;
188
            }
189
            else {
190
                // Now send them an email telling them they've been approved
191
192
193
                // Scrub that one from the list of pending items
194
                unset ($this->pending[$approval_id]);
195
            }
196
        }
197
198
        $this->update_pending_count();
199
200
        return true;
201
    }
202
203
    public function decline($data) {
204
    // Decline a list of term submissions from users
205
206
        global $THEUSER;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
207
208
        // We need a list of editqueue items to play with
209
        $this->get_pending();
210
        if (!isset($this->pending)) {
211
            return false;
212
        }
213
        $timestamp = date('Y-m-d H:i:s', time());
214
215
        foreach ($data['declines'] as $decline_id) {
216
            // Check to see that we actually have something to decline
217
            if (!isset($this->pending[$decline_id])) {
218
                break;
219
            }
220
221
            // Update the editqueue with setting approved=0
222
            $q = $this->db->query("UPDATE editqueue
223
                            SET
224
                            editor_id='" . addslashes($THEUSER->user_id()) . "',
225
                            approved='0',
226
                            decided='" . $timestamp . "'
227
                            WHERE edit_id=" . $decline_id . ";");
228
            if (!$q->success()) {
229
                break;
230
            }
231
            else {
232
                // Scrub that one from the list of pending items
233
                unset ($this->pending[$decline_id]);
234
            }
235
        }
236
237
        $this->update_pending_count();
238
239
        return true;
240
241
    }
242
243
    public function modify($args) {
0 ignored issues
show
Unused Code introduced by
The parameter $args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
244
    // Moderate a post,
245
    // log it in editqueue,
246
    // update glossary_id
247
248
        // 1. Add the new item into the queue
249
        $q = $this->db->query();
250
251
    // 2. if successful, set the previous editqueue item to approved=0;
252
253
    }
254
255
    public function get_pending() {
256
    // Fetch all pending editqueue items.
257
    // Sets $this->pending and returns a body count.
258
    // Return organised by type? - maybe not for the moment
259
260
        $q = $this->db->query("SELECT eq.edit_id, eq.user_id, u.firstname, u.lastname, eq.glossary_id, eq.title, eq.body, eq.submitted FROM editqueue AS eq, users AS u WHERE eq.user_id = u.user_id AND eq.approved IS NULL ORDER BY eq.submitted DESC;");
261
        if ($q->success() && $q->rows()) {
262
            for ($i = 0; $i < ($q->rows()); $i++) {
263
                $this->pending[ $q->field($i,"edit_id") ] = $q->row($i);
264
            }
265
266
            $this->update_pending_count();
267
268
            return true;
269
        }
270
        else {
271
            return false;
272
        }
273
    }
274
275
    public function display() {
276
    // Print all our pending items out in a nice list or something
277
    // Add links later for "approve, decline, refer"
278
    // Just get the fucker working for now
279
280
            $URL = new Url('admin_glossary_pending');
281
            $URL->reset();
282
            $form_link = $URL->generate('url');
283
284
        ?><form action="<?php echo $form_link ?>" method="post"><?php
285
        foreach ($this->pending as $editqueue_id => $pender) {
286
287
            $URL = new Url('admin_glossary_pending');
288
            $URL->insert(array('approve' => $editqueue_id));
289
            $approve_link = $URL->generate('url');
290
291
            $URL = new Url('admin_glossary_pending');
292
            $URL->insert(array('modify' => $editqueue_id));
293
            $modify_link = $URL->generate('url');
294
295
            $URL = new Url('admin_glossary_pending');
296
            $URL->insert(array('decline' => $editqueue_id));
297
            $decline_link = $URL->generate('url');
298
299
            ?><div class="pending-item"><label for="<?php echo $editqueue_id; ?>"><input type="checkbox" name="approve[]" value="<?php echo $editqueue_id; ?>" id="<?php echo $editqueue_id; ?>"><strong><?php echo $pender['title']; ?></strong></label>
300
            <p><?php echo $pender['body']; ?><br>
301
            <small>
302
                <a href="<?php echo $approve_link; ?>">approve</a>
303
                &nbsp;|&nbsp;
304
                <a href="<?php echo $modify_link; ?>">modify</a>
305
                &nbsp;|&nbsp;
306
                <a href="<?php echo $decline_link; ?>">decline</a>
307
                <br>Submitted by: <em><?php echo $pender['firstname']; ?>&nbsp;<?php echo $pender['lastname']; ?></em>
308
            </small></p></div>
309
        <?php
310
        }
311
        ?><input type="submit" value="Approve checked items">
312
        </form><?php
313
    }
314
315
    protected function update_pending_count() {
316
        // Just makes sure we're showing the right number of pending items
317
        $this->pending_count = count($this->pending);
318
    }
319
320
}
321