Passed
Pull Request — master (#36)
by
unknown
04:33
created

MagicLink::getTokenLength()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 2
nc 2
nop 0
1
<?php
2
3
namespace MagicLink;
4
5
use Carbon\Carbon;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Database\QueryException;
8
use Illuminate\Support\Facades\Event;
9
use Illuminate\Support\Str;
10
use MagicLink\Actions\ActionInterface;
11
use MagicLink\Events\MagicLinkWasCreated;
12
use MagicLink\Events\MagicLinkWasVisited;
13
14
class MagicLink extends Model
15
{
16
    public $incrementing = false;
17
18
    protected $keyType = 'string';
19
20
    protected static function boot()
21
    {
22
        parent::boot();
23
24
        static::creating(function ($model) {
25
            $model->id = Str::uuid();
26
        });
27
    }
28
29
    protected static function getTokenLength()
30
    {
31
        return config('magiclink.token.length', 64) <= 255 ? config('magiclink.token.length', 64) : 255;
32
    }
33
34
    public function getActionAttribute($value)
35
    {
36
        if ($this->getConnection()->getDriverName() === 'pgsql') {
37
            return unserialize(base64_decode($value));
38
        }
39
40
        return unserialize($value);
41
    }
42
43
    public function setActionAttribute($value)
44
    {
45
        $this->attributes['action'] = $this->getConnection()->getDriverName() === 'pgsql'
46
                                        ? base64_encode(serialize($value))
47
                                        : serialize($value);
48
    }
49
50
    public function getUrlAttribute()
51
    {
52
        return url(sprintf(
53
            '%s/%s:%s',
54
            config('magiclink.url.validate_path', 'magiclink'),
55
            $this->id,
56
            $this->token
57
        ));
58
    }
59
60
    /**
61
     * Create makiglink.
62
     *
63
     * @param ActionInterface $action
64
     * @param int|null $lifetime
65
     * @param int|null $numMaxVisits
66
     * @return self
67
     */
68
    public static function create(ActionInterface $action, ?int $lifetime = 4320, ?int $numMaxVisits = null)
69
    {
70
        self::deleteMagicLinkExpired();
71
72
        $magiclink = new static();
73
74
        $magiclink->token = Str::random(self::getTokenLength());
0 ignored issues
show
Bug introduced by
The property token does not seem to exist on MagicLink\MagicLink. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
75
        $magiclink->available_at = $lifetime
0 ignored issues
show
Bug introduced by
The property available_at does not seem to exist on MagicLink\MagicLink. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
76
                                    ? Carbon::now()->addMinute($lifetime)
0 ignored issues
show
Unused Code introduced by
The call to Carbon\Carbon::addMinute() has too many arguments starting with $lifetime. ( Ignorable by Annotation )

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

76
                                    ? Carbon::now()->/** @scrutinizer ignore-call */ addMinute($lifetime)

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
77
                                    : null;
78
        $magiclink->max_visits = $numMaxVisits;
0 ignored issues
show
Bug introduced by
The property max_visits does not seem to exist on MagicLink\MagicLink. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
79
        $magiclink->action = $action;
0 ignored issues
show
Bug introduced by
The property action does not seem to exist on MagicLink\MagicLink. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
80
81
        $magiclink->save();
82
83
        Event::dispatch(new MagicLinkWasCreated($magiclink));
84
85
        return $magiclink;
86
    }
87
88
    /**
89
     * Execute Action.
90
     *
91
     * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse
92
     */
93
    public function run()
94
    {
95
        return $this->action->run();
96
    }
97
98
    /**
99
     * Call when magiclink has been visited.
100
     *
101
     * @return void
102
     */
103
    public function visited()
104
    {
105
        try {
106
            $this->increment('num_visits');
107
        } catch (QueryException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
108
        }
109
110
        Event::dispatch(new MagicLinkWasVisited($this));
111
    }
112
113
    /**
114
     * Get valid MagicLink by token.
115
     *
116
     * @param string $token
117
     * @return null|\MagicLink\MagicLink
118
     */
119
    public static function getValidMagicLinkByToken($token)
120
    {
121
        [$tokenId, $tokenSecret] = explode(':', "{$token}:");
122
123
        if (empty($tokenSecret)) {
124
            return;
125
        }
126
127
        return self::where('id', $tokenId)
128
                    ->where('token', $tokenSecret)
129
                    ->where(function ($query) {
130
                        $query
131
                            ->whereNull('available_at')
132
                            ->orWhere('available_at', '>=', Carbon::now());
133
                    })
134
                    ->where(function ($query) {
135
                        $query
136
                            ->whereNull('max_visits')
137
                            ->orWhereRaw('max_visits > num_visits');
138
                    })
139
                    ->first();
140
    }
141
142
    /**
143
     * Get MagicLink by token.
144
     *
145
     * @param string $token
146
     * @return null|\MagicLink\MagicLink
147
     */
148
    public static function getMagicLinkByToken($token)
149
    {
150
        [$tokenId, $tokenSecret] = explode(':', "{$token}:");
151
152
        if (empty($tokenSecret)) {
153
            return;
154
        }
155
156
        return self::where('id', $tokenId)
157
                    ->where('token', $tokenSecret)
158
                    ->first();
159
    }
160
161
    /**
162
     * Delete magiclink was expired.
163
     *
164
     * @return void
165
     */
166
    public static function deleteMagicLinkExpired()
167
    {
168
        self::where(function ($query) {
169
            $query
170
                ->where('available_at', '<', Carbon::now())
171
                ->orWhere(function ($query) {
172
                    $query
173
                        ->whereNotNull('max_visits')
174
                        ->whereRaw('max_visits <= num_visits');
175
                });
176
        })
177
        ->delete();
178
    }
179
180
    /**
181
     * Delete all MagicLink.
182
     *
183
     * @return void
184
     */
185
    public static function deleteAllMagicLink()
186
    {
187
        self::truncate();
188
    }
189
}
190