Completed
Push — master ( 254925...5d79ce )
by Lhalaa
14s queued 10s
created

PartialFormSubmission   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 278
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 16

Test Coverage

Coverage 97.33%

Importance

Changes 0
Metric Value
wmc 18
lcom 2
cbo 16
dl 0
loc 278
ccs 73
cts 75
cp 0.9733
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A getCMSFields() 0 49 1
A getPartialLink() 0 15 2
A generateKey() 0 4 1
A onBeforeWrite() 0 8 2
A getPartialToken() 0 9 2
A generateToken() 0 6 1
A generatePassword() 0 12 1
A getParent() 0 4 1
A canCreate() 0 4 1
A canView() 0 8 2
A canEdit() 0 8 2
A canDelete() 0 8 2
1
<?php
2
3
namespace Firesphere\PartialUserforms\Models;
4
5
use Exception;
6
use Firesphere\PartialUserforms\Controllers\PartialUserFormVerifyController;
7
use SilverStripe\Control\Controller;
8
use SilverStripe\Control\Director;
9
use SilverStripe\Forms\FieldList;
10
use SilverStripe\Forms\GridField\GridField;
11
use SilverStripe\Forms\GridField\GridFieldButtonRow;
12
use SilverStripe\Forms\GridField\GridFieldConfig;
13
use SilverStripe\Forms\GridField\GridFieldDataColumns;
14
use SilverStripe\Forms\GridField\GridFieldExportButton;
15
use SilverStripe\Forms\GridField\GridFieldPrintButton;
16
use SilverStripe\Forms\ReadonlyField;
17
use SilverStripe\ORM\ArrayList;
18
use SilverStripe\ORM\DataList;
19
use SilverStripe\ORM\DataObject;
20
use SilverStripe\Security\Member;
21
use SilverStripe\Security\RandomGenerator;
22
use SilverStripe\UserForms\Model\Submission\SubmittedForm;
23
use SilverStripe\UserForms\Model\UserDefinedForm;
24
25
/**
26
 * Class \Firesphere\PartialUserforms\Models\PartialFormSubmission
27
 *
28
 * @property boolean $IsSend
29
 * @property string $TokenSalt
30
 * @property string $Token
31
 * @property string $Password
32
 * @property int $UserDefinedFormID
33
 * @method DataObject UserDefinedForm()
34
 * @method DataList|PartialFieldSubmission[] PartialFields()
35
 * @method DataList|PartialFileFieldSubmission[] PartialUploads()
36
 */
37
class PartialFormSubmission extends SubmittedForm
38
{
39
40
    /**
41
     * @var string
42
     */
43
    private static $table_name = 'PartialFormSubmission';
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
44
45
    /**
46
     * @var array
47
     */
48
    private static $db = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
49
        'IsSend'    => 'Boolean(false)',
50
        'TokenSalt' => 'Varchar(16)',
51
        'Token'     => 'Varchar(16)',
52
        'Password'  => 'Varchar(64)',
53
    ];
54
55
    /**
56
     * @var array
57
     */
58
    private static $has_one = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
59
        'UserDefinedForm' => DataObject::class
60
    ];
61
62
    /**
63
     * @var array
64
     */
65
    private static $has_many = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
66
        'PartialFields'  => PartialFieldSubmission::class,
67
        'PartialUploads' => PartialFileFieldSubmission::class
68
    ];
69
70
    private static $cascade_deletes = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
71
        'PartialFields'
72
    ];
73
74
    /**
75
     * @var array
76
     */
77
    private static $summary_fields = [
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
78
        'ID'          => 'ID',
79
        'PartialLink' => 'Link',
80
        'Created'     => 'Created',
81
        'LastEdited'  => 'Last Edited',
82
    ];
83
84
    private static $special_characters = [
85
        '!',
86
        '@',
87
        '#',
88
        '$',
89
        '%',
90
        '^',
91
        '&',
92
        '*',
93
        '(',
94
        ')',
95
        '_',
96
        '-',
97
        '=',
98
        '+',
99
        ';',
100
        ':',
101
        ',',
102
        '.',
103
        '?'
104
    ];
105
106
    /**
107
     * @return FieldList
108
     * @throws Exception
109
     */
110 1
    public function getCMSFields()
111
    {
112
        /** @var FieldList $fields */
113 1
        $fields = parent::getCMSFields();
114 1
        $fields->removeByName([
115 1
            'Values',
116
            'IsSend',
117
            'PartialFields',
118
            'TokenSalt',
119
            'Token',
120
            'UserDefinedFormID',
121
            'Submitter',
122
            'PartialUploads'
123
        ]);
124
125 1
        $partialFields = $this->PartialFields();
126 1
        $fileFields = $this->PartialUploads();
127 1
        $list = ArrayList::create();
128 1
        $list->merge($partialFields);
129 1
        $list->merge($fileFields);
130
131 1
        $partialFields = GridField::create(
132 1
            'PartialFields',
133 1
            _t(static::class . '.PARTIALFIELDS', 'Partial fields'),
134 1
            $list->sort('Created', 'ASC')
135
        );
136
137
        $exportColumns = [
138 1
            'Title'       => 'Title',
139
            'ExportValue' => 'Value'
140
        ];
141
142 1
        $config = new GridFieldConfig();
143 1
        $config->addComponent(new GridFieldDataColumns());
144 1
        $config->addComponent(new GridFieldButtonRow('after'));
145 1
        $config->addComponent(new GridFieldExportButton('buttons-after-left', $exportColumns));
146 1
        $config->addComponent(new GridFieldPrintButton('buttons-after-left'));
147 1
        $partialFields->setConfig($config);
148
149 1
        $fields->addFieldsToTab(
150 1
            'Root.Main',
151
            [
152 1
                ReadonlyField::create('ReadonlyPartialLink', 'Partial Link', $this->getPartialLink()),
153 1
                $partialFields
154
            ]
155
        );
156
157 1
        return $fields;
158
    }
159
160
    /**
161
     * Get the share link of the form
162
     *
163
     * @return string
164
     * @throws Exception
165
     */
166 3
    public function getPartialLink()
167
    {
168 3
        if (!$this->isInDB()) {
169 1
            return '(none)';
170
        }
171
172 3
        $token = $this->Token;
173
174 3
        return Controller::join_links(
175 3
            Director::absoluteBaseURL(),
176 3
            'partial',
177 3
            $this->generateKey($token),
0 ignored issues
show
Bug introduced by
It seems like $token defined by $this->Token on line 172 can also be of type boolean; however, Firesphere\PartialUserfo...bmission::generateKey() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
178 3
            $token
179
        );
180
    }
181
182
    /**
183
     * Generate a key based on the share token salt
184
     *
185
     * @param string $token
186
     * @return mixed
187
     */
188 6
    public function generateKey($token)
189
    {
190 6
        return hash_pbkdf2('sha256', $token, $this->TokenSalt, 1000, 16);
191
    }
192
193
    /**
194
     * Generate the partial tokens
195
     * If the submission is password protected, generate a password.
196
     * @throws Exception
197
     */
198 43
    public function onBeforeWrite()
199
    {
200 43
        parent::onBeforeWrite();
201 43
        $this->getPartialToken();
202 43
        if (!$this->Password) {
203 33
            $this->Password = $this->generatePassword();
204
        }
205 43
    }
206
207
    /**
208
     * Get the unique token for the share link
209
     *
210
     * @return bool|string|null
211
     * @throws Exception
212
     */
213 43
    protected function getPartialToken()
214
    {
215 43
        if (!$this->TokenSalt) {
216 29
            $this->TokenSalt = $this->generateToken();
217 29
            $this->Token = $this->generateToken();
218
        }
219
220 43
        return $this->Token;
221
    }
222
223
    /**
224
     * Generate a new token
225
     *
226
     * @return bool|string
227
     * @throws Exception
228
     */
229 29
    protected function generateToken()
230
    {
231 29
        $generator = new RandomGenerator();
232
233 29
        return substr($generator->randomToken('sha256'), 0, 16);
234
    }
235
236
    /**
237
     * @return string
238
     * @throws Exception
239
     */
240 33
    protected function generatePassword()
241
    {
242 33
        $chars = range('A', 'Z');
243 33
        $chars = array_merge($chars, range('a', 'z'));
244 33
        $chars = array_merge($chars, range(0, 9));
245 33
        $chars = array_merge($chars, self::$special_characters);
246 33
        shuffle($chars);
247 33
        $pwd = implode(array_slice($chars, 0, 10));
248 33
        Controller::curr()->getRequest()->getSession()->set(PartialUserFormVerifyController::PASSWORD_KEY, $pwd);
249
250 33
        return hash_pbkdf2('SHA256', $pwd, $this->TokenSalt, 1000);
251
    }
252
253
    /**
254
     * @return DataObject|UserDefinedForm
255
     */
256 46
    public function getParent()
257
    {
258 46
        return $this->UserDefinedForm();
259
    }
260
261
    /**
262
     * @param Member
263
     *
264
     * @return bool|string|null
265
     * @throws Exception
266
     */
267 1
    public function canCreate($member = null, $context = [])
268
    {
269 1
        return false;
270
    }
271
272
    /**
273
     * @param Member $member
274
     *
275
     * @return boolean|string
276
     */
277 43
    public function canView($member = null)
278
    {
279 43
        if ($this->UserDefinedForm()) {
280 40
            return $this->UserDefinedForm()->canView($member);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->UserDefinedForm()->canView($member); of type boolean|string adds the type string to the return on line 280 which is incompatible with the return type of the parent method SilverStripe\UserForms\M...\SubmittedForm::canView of type boolean.
Loading history...
281
        }
282
283 20
        return parent::canView($member);
284
    }
285
286
    /**
287
     * @param Member $member
288
     *
289
     * @throws Exception
290
     * @return boolean|string
291
     */
292 3
    public function canEdit($member = null)
293
    {
294 3
        if ($this->UserDefinedForm()) {
295 3
            return $this->UserDefinedForm()->canEdit($member);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->UserDefinedForm()->canEdit($member); of type boolean|string adds the type string to the return on line 295 which is incompatible with the return type of the parent method SilverStripe\UserForms\M...\SubmittedForm::canEdit of type boolean.
Loading history...
296
        }
297
298
        return parent::canEdit($member);
299
    }
300
301
    /**
302
     * @param Member $member
303
     *
304
     * @return boolean|string
305
     */
306 3
    public function canDelete($member = null)
307
    {
308 3
        if ($this->UserDefinedForm()) {
309 3
            return $this->UserDefinedForm()->canDelete($member);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->UserDefinedForm()->canDelete($member); of type boolean|string adds the type string to the return on line 309 which is incompatible with the return type of the parent method SilverStripe\UserForms\M...ubmittedForm::canDelete of type boolean.
Loading history...
310
        }
311
312
        return parent::canDelete($member);
313
    }
314
}
315