source: trunk/server/www/app/controllers/requests_controller.php @ 295

Last change on this file since 295 was 295, checked in by sander, 10 years ago

Link teh requested output formats to individual jobs, not the request as a whole

File size: 14.1 KB
Line 
1<?php
2/**
3 * Officeshots.org - Test your office documents in different applications
4 * Copyright (C) 2009 Stichting Lone Wolves
5 * Written by Sander Marechal <s.marechal@jejik.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21/**
22 * The Requests controller
23 */
24class RequestsController extends AppController
25{
26        /** @var array The components this controller uses */
27        public $components = array('AuthCert', 'RequestHandler');
28       
29        /** @var array The helpers that will be available on the view */
30        public $helpers = array('Html', 'Form', 'Javascript', 'RequestModel', 'ValidatorModel');
31
32        /** @var array Add Request and Worker model */
33        public $uses = array('Request', 'Worker', 'Mimetype', 'User', 'Format');
34
35        /** @var array Set default sort order for paginate */
36        public $paginate = array(
37                'order' => array('Request.created' => 'desc')
38        );
39
40        /**
41         * Set the auth permissions for this controller
42         * @return void
43         */
44        public function beforeFilter()
45        {
46                parent::beforeFilter();
47                $this->AuthCert->allow('add', 'view', 'download');
48        }
49
50        /**
51         * List all your requests
52         * @return void
53         */
54        public function index()
55        {
56                $this->set('requests', $this->paginate('Request', array('Request.user_id' => $this->AuthCert->user('id'))));
57        }
58
59        /**
60         * Get a Request by the request ID and check access control
61         *
62         * @param string $id The request ID
63         * @param $type the access type, either 'read' or 'write'
64         * @return array An array containing the request
65         */
66        private function _getRequest($id, $type = 'read')
67        {
68                if (!$id) {
69                        $this->Session->setFlash(__('Invalid Request.', true));
70                        $this->redirect(array('action'=>'add'));
71                }
72               
73                $this->Request->contain(array(
74                        'Mimetype',
75                        'Mimetype.Doctype',
76                        'Job',
77                        'Job.Platform',
78                        'Job.Application',
79                        'Job.Result',
80                        'Job.Result.Mimetype',
81                        'Job.Result.Format',
82                        'Job.Result.Validator' => array('order' => 'Validator.name ASC'),
83                        'Gallery',
84                        'Validator' => array('order' => 'Validator.name ASC'),
85                ));
86
87                $request = $this->Request->read(null, $id);
88                if (empty($request) || !$this->Request->checkAccess($this->AuthCert->user('id'), $type, $id)) {
89                        $this->Session->setFlash(__('Invalid Request.', true));
90                        $this->redirect(array('action'=>'add'));
91                }
92
93                return $request;
94        }
95
96        /**
97         * View a single request
98         *
99         * @param string $id The request ID
100         * @return void
101         */
102        public function view($id = null)
103        {
104                // Used to display the jobs associated with the Request
105                $this->helpers[] = 'JobModel';
106
107                $request = $this->_getRequest($id, 'read');
108                $this->set(array(
109                        'request' => $request,
110                        'canDeleteResults' => $this->__permitted('results', 'delete'),
111                ));
112        }
113
114
115        /**
116         * Edit a request description
117         *
118         * @param string $id The request ID
119         * @return void
120         */
121        public function edit($id = null)
122        {
123                $request = $this->_getRequest($id, 'write');
124
125                if (!empty($this->data)) {
126                        $this->data['Request']['id'] = $id;
127                        if (!$this->Request->save($this->data)) {
128                                $this->Session->setFlash(__('Unable to save the description', true));
129                        } else {
130                                $this->redirect(array('action' => 'view', $id));
131                        }
132                }
133
134                $this->set(array(
135                        'request' => $request,
136                ));
137        }
138        /**
139         * Add a new request
140         * @return void
141         */
142        public function add()
143        {
144                if (!empty($this->data)) {
145                        // Access control
146                        if (!Configure::read('Auth.allowAnonymous') && !$this->AuthCert->user()) {
147                                $this->Session->setFlash(__('You are not allowed to submit requests anonymously.', true));
148                                $this->redirect(array('action'=>'add'));
149                        }
150
151                        // Check the daily request limits
152                        if ($user = $this->AuthCert->user()) {
153                                $requestLimit = Configure::read('Request.limitRegistered');
154
155                                $user = $this->User->find(array('User.id' => $user['User']['id']));
156                                $limits = Set::extract('/Group/request_limit', $user);
157                                $limits[] = $requestLimit;
158                                $requestLimit = max($limits);
159
160                                $numRequests = $this->Request->find('count', array(
161                                        'conditions' => array(
162                                                'Request.user_id' => $user['User']['id'],
163                                                'Request.created >' => date('Y-m-d H:i:s', strtotime('-1 day'))
164                                        )
165                                ));
166
167                                if ($numRequests > $requestLimit) {
168                                        $this->Session->setFlash(sprintf(__('You have exceeded your quota of %d daily requests.', true), $requestLimit));
169                                        $this->redirect(array('action'=>'add'));
170                                }
171                        } else {
172                                $requestLimit = Configure::read('Request.limitAnonymous');
173                                $numRequests = $this->Request->find('count', array(
174                                        'conditions' => array(
175                                                'Request.ip_address' => inet_ptod($this->RequestHandler->getClientIP()),
176                                                'Request.created >' => date('Y-m-d H:i:s', strtotime('-1 day'))
177                                        )
178                                ));
179
180                                if ($numRequests > $requestLimit) {
181                                        $this->Session->setFlash(sprintf(__('You have exceeded your quota of %d daily requests.', true), $requestLimit));
182                                        $this->redirect(array('action'=>'add'));
183                                }
184                        }
185
186                        // Check that the user marked any applications
187                        if (!isset($this->data['Request']['App']) || !is_array($this->data['Request']['App']) || sizeof($this->data['Request']['App']) == 0) {
188                                $this->Session->setFlash(__('You did not mark any applications.', true));
189                                $this->redirect(array('action'=>'add'));
190                        }
191
192                        // Set some extra data
193                        $this->data['Request']['user_id']    = (string) $this->AuthCert->user('id');
194                        $this->data['Request']['ip_address'] = inet_ptod($this->RequestHandler->getClientIP());
195                        $this->data['Request']['expire']     = date('Y-m-d H:i:s', time() + Configure::read('Request.expire'));
196                        $this->data['Request']['state']      = Request::STATE_PREPROCESSOR_QUEUED;
197
198
199                        // Create the request
200                        $this->Request->create();
201                        if (!$this->Request->save($this->data)) {
202                                $this->Session->setFlash(__('The request could not be saved', true));
203                                $this->redirect(array('action'=>'add'));
204                        }
205
206                        // Set root and path based on the ID
207                        $this->Request->read();
208                        $this->Request->set(array(
209                                'root' => 'requests' . DS . $this->Request->id,
210                                'path' => 'requests' . DS . $this->Request->id . DS . 'source',
211                        ));
212                       
213                        // Add the file upload
214                        $errors = array();
215                        if (!$this->Request->addUpload($this->data, $errors)) {
216                                $this->Request->delete();
217                                $this->Session->setFlash(implode("<br />\n", $errors));
218                                $this->redirect(array('action'=>'add'));
219                        }
220
221                        // Add the jobs to the request
222                        $jobs = array();
223                        $format_id = $this->data['Request']['format_id'];
224                        foreach ($this->data['Request']['App'] as $app) {
225                                list($platform_id, $doctype_code, $application_id, $version) = explode('_', $app);
226                                $jobs[] = compact('platform_id', 'application_id', 'version', 'format_id');
227                        }
228
229                        $this->Request->read();
230                        if ($this->Request->addJobs($jobs) == 0) {
231                                $this->Request->delete();
232                                $this->Session->setFlash(__('None of the jobs could be created. The request has been cancelled.', true));
233                                $this->redirect(array('action'=>'add'));
234                        }
235
236                        // Add ODF Validators
237                        $this->Request->addValidators();
238
239                        // Queue the preprocessor
240                        if (!$this->Request->defer('run', 'Preprocessor')) {
241                                $errors[] = __('Failed to queue the request for the virus scanner. Please contact system administration.', true);
242                        }
243
244                        // All done!
245                        $this->redirect(array('action' => 'view', 'id' => $this->Request->id));
246                }
247
248                $this->set('can_have_factories', $this->__permitted('factories', 'edit'));
249                $this->set('can_submit_requests', ($this->__permitted('factories', 'edit') || $this->AuthCert->user()));
250               
251                // TODO: The result of all the below actions should really be cached for better performance
252                $workers = $this->Worker->getActive();
253
254                // Give all the active workers a unique, short ID.
255                // We need this for checking and unchecking sets of applications
256                $count = 0;
257                foreach ($workers as &$worker) {
258                        $worker['short_id'] = 'c'.$count++;
259                }
260                unset($worker); // Don't leave it assigned or bugs will occur below
261
262                // Get all the other information we need to build the front page
263                $platforms = $this->Worker->Factory->Operatingsystem->Platform->find('all');
264                $doctypes = $this->Worker->Application->Doctype->find('all');
265                $formats = $this->Format->find('list');
266                $mimetypes = $this->Mimetype->find('all');
267
268                // Build a format map which consists of sets of active applications
269                $sets = array(
270                        'platform'    => array(),
271                        'extension'   => array(),
272                        'format'      => array(),
273                        'latest'      => array(),
274                        'development' => Set::extract('/Worker[development=1]/../short_id', $workers),
275                        'all'         => Set::extract('/short_id', $workers)
276                );
277
278                foreach ($platforms as $platform) {
279                        $sets['platform'][$platform['Platform']['id']] = Set::extract('/Platform[id=' . $platform['Platform']['id'] . ']/../short_id', $workers);
280                }
281                foreach ($mimetypes as $mimetype) {
282                        if ($mimetype['Mimetype']['doctype_id']) {
283                                $sets['extension'][$mimetype['Mimetype']['extension']] = Set::extract('/Doctype[id=' . $mimetype['Mimetype']['doctype_id'] . ']/../short_id', $workers);
284                        }
285                }
286                foreach ($formats as $format_id => $format) {
287                        $sets['format'][$format_id] = Set::extract('/Format[id=' . $format_id . ']/../short_id', $workers);
288                }
289
290                // This is the tricky bit. Set the highest version for every application/platform combo as default
291                // This requires the workers array to be sorted by platform, app, version
292                $short_id = false;
293                $platform_id = '';
294                $application_id = '';
295                foreach ($workers as $worker) {
296                        if ($worker['Worker']['development']) {
297                                continue;
298                        }
299
300                        if ($worker['Application']['id'] != $application_id || $worker['Platform']['id'] != $platform_id) {
301                                if ($short_id) {
302                                        $sets['latest'][] = $short_id;
303                                }
304
305                                $platform_id = $worker['Platform']['id'];
306                                $application_id = $worker['Application']['id'];
307                        }
308
309                        $short_id = $worker['short_id'];
310                }
311                $sets['latest'][] = $short_id; // don't forget to add the last one.
312
313                $this->set(compact('workers', 'platforms', 'doctypes', 'formats', 'sets', 'mimetypes'));
314        }
315
316        /**
317         * Download a request
318         *
319         * @param string $id The request ID
320         */
321        public function download($id = null)
322        {
323                $request = $this->_getRequest($id, 'read');
324                extract($this->Request->createZip());
325               
326                $this->view = 'Media';
327                $this->set(array(
328                        'id' => $id,
329                        'name' => $filename,
330                        'download' => true,
331                        'extension' => 'zip',
332                        'path' => $directory . DS,
333                ));
334        }
335
336        /**
337         * Extend the deadline of a request
338         *
339         * @param string $id The request ID
340         */
341        public function extend($id = null)
342        {
343                $request = $this->_getRequest($id, 'write');
344
345                if (strtotime($request['Request']['expire']) < time()) {
346                        $this->Session->setFlash(__('You cannot extend a request that has expired.', true));
347                        $this->redirect(array('action' => 'view', $id));
348                }
349
350                $this->Request->saveField('expire', date('Y-m-d H:i:s', time() + Configure::read('Request.expire')));
351                $this->redirect(array('action' => 'view', $id));
352        }
353
354        /**
355         * Cancel a job by setting it's expiration time
356         *
357         * @param string $id The request ID
358         */
359        public function cancel($id = null)
360        {
361                $request = $this->_getRequest($id, 'write');
362                $this->Request->cancel();
363                $this->redirect(array('action' => 'view', $id));
364        }
365
366        /**
367         * List all requests
368         * @return void
369         */
370        public function admin_index()
371        {
372                $this->Request->recursive = 0;
373                $this->set('requests', $this->paginate());
374        }
375
376        /**
377         * View a single request
378         *
379         * @param string $id The request ID
380         * @return void
381         */
382        public function admin_view($id = null)
383        {
384                if (!$id) {
385                        $this->Session->setFlash(__('Invalid Request.', true));
386                        $this->redirect(array('action'=>'index'));
387                }
388                $this->set('request', $this->Request->read(null, $id));
389        }
390
391        /**
392         * Add a new request manually
393         * @return void
394         */
395        public function admin_add()
396        {
397                if (!empty($this->data)) {
398                        $this->data['Request']['ip_address'] = inet_ptod($this->data['Request']['ip_address']);
399                        $this->Request->create();
400                        if ($this->Request->save($this->data)) {
401                                $this->Session->setFlash(__('The Request has been saved', true));
402                                $this->redirect(array('action'=>'index'));
403                        } else {
404                                $flash = $this->Request->Behaviors->File->errors;
405                                array_unshift($flash, __('The Request could not be saved. Please, try again.', true));
406                                $this->Session->setFlash(implode('<br />', $flash));
407                        }
408                }
409                $users = $this->Request->User->find('list');
410                $mimetypes = $this->Request->Mimetype->find('list');
411                $this->set(compact('users','mimetypes','formats'));
412        }
413
414        /**
415         * Edit a request
416         *
417         * @param string $id The request ID
418         * @return void
419         */
420        public function admin_edit($id = null)
421        {
422                if (!$id && empty($this->data)) {
423                        $this->Session->setFlash(__('Invalid Request', true));
424                        $this->redirect(array('action'=>'index'));
425                }
426                if (!empty($this->data)) {
427                        $this->data['Request']['ip_address'] = inet_ptod($this->data['Request']['ip_address']);
428                        if ($this->Request->save($this->data)) {
429                                $this->Session->setFlash(__('The Request has been saved', true));
430                                $this->redirect(array('action'=>'index'));
431                        } else {
432                                $flash = $this->Request->Behaviors->File->errors;
433                                array_unshift($flash, __('The Request could not be saved. Please, try again.', true));
434                                $this->Session->setFlash(implode('<br />', $flash));
435                        }
436                }
437                if (empty($this->data)) {
438                        $this->data = $this->Request->read(null, $id);
439                        $this->data['Request']['ip_address'] = inet_dtop($this->data['Request']['ip_address']);
440                }
441                $users = $this->Request->User->find('list');
442                $mimetypes = $this->Request->Mimetype->find('list');
443                $this->set(compact('users','mimetypes','formats'));
444        }
445
446        /**
447         * Delete a request
448         *
449         * @param string $id The request ID
450         * @return void
451         */
452        public function admin_delete($id = null)
453        {
454                if (!$id) {
455                        $this->Session->setFlash(__('Invalid id for Request', true));
456                        $this->redirect(array('action'=>'index'));
457                }
458                if ($this->Request->del($id)) {
459                        $this->Session->setFlash(__('Request deleted', true));
460                        $this->redirect(array('action'=>'index'));
461                }
462        }
463}
464
465?>
Note: See TracBrowser for help on using the repository browser.