BtcPaymentController::btcPayCallback()   B
last analyzed

Complexity

Conditions 8
Paths 8

Size

Total Lines 66
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 43
dl 0
loc 66
rs 7.9875
c 0
b 0
f 0
cc 8
nc 8
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace App\Http\Controllers;
4
5
use App\Models\Payment;
6
use App\Models\User;
7
use Illuminate\Http\Request;
8
use Illuminate\Http\Response;
9
use Illuminate\Support\Facades\Log;
10
11
class BtcPaymentController extends BasePageController
12
{
13
    /**
14
     * BtcPay callback.
15
     */
16
    public function btcPayCallback(Request $request): Response
17
    {
18
        $hashCheck = 'sha256='.hash_hmac('sha256', $request->getContent(), config('nntmux.btcpay_webhook_secret'));
19
        if ($hashCheck !== $request->header('btcpay-sig')) {
20
            Log::error('BTCPay webhook hash check failed: '.$request->header('btcpay-sig'));
0 ignored issues
show
Bug introduced by
Are you sure $request->header('btcpay-sig') of type array|null|string can be used in concatenation? ( Ignorable by Annotation )

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

20
            Log::error('BTCPay webhook hash check failed: './** @scrutinizer ignore-type */ $request->header('btcpay-sig'));
Loading history...
21
22
            return response('Not Found', 404);
23
        }
24
        $payload = json_decode($request->getContent(), true);
0 ignored issues
show
Bug introduced by
It seems like $request->getContent() can also be of type resource; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

24
        $payload = json_decode(/** @scrutinizer ignore-type */ $request->getContent(), true);
Loading history...
25
        // We have received a payment for an invoice and user should be upgraded to a paid plan based on order
26
        if ($payload['type'] === 'InvoicePaymentSettled') {
27
            $user = User::query()->where('email', '=', $payload['metadata']['buyerEmail'])->first();
28
            if ($user) {
29
                $checkOrder = Payment::query()->where('invoice_id', '=', $payload['invoiceId'])->where('payment_status', '=', 'Settled')->first();
30
                if ($checkOrder !== null) {
31
                    Log::error('Duplicate BTCPay webhook: '.$payload['webhookId']);
32
33
                    return response('OK', 200);
34
                }
35
36
                Payment::create([
37
                    'email' => $payload['metadata']['buyerEmail'],
38
                    'username' => $user->username,
39
                    'item_description' => $payload['metadata']['itemDesc'],
40
                    'order_id' => $payload['metadata']['orderId'],
41
                    'payment_id' => $payload['payment']['id'],
42
                    'payment_status' => $payload['payment']['status'],
43
                    'invoice_amount' => $payload['metadata']['invoice_amount'],
44
                    'payment_method' => $payload['paymentMethodId'],
45
                    'payment_value' => $payload['payment']['value'],
46
                    'webhook_id' => $payload['webhookId'],
47
                    'invoice_id' => $payload['invoiceId'],
48
                ]);
49
50
                return response('OK', 200);
51
            }
52
53
            Log::error('User not found for BTCPay webhook: '.$payload['metadata']['buyerEmail']);
54
55
            return response('Not Found', 404);
56
        }
57
58
        if ($payload['type'] === 'InvoiceSettled') {
59
            // Check if we have the invoice_id in payments table and if we do, update the user account
60
            $checkOrder = Payment::query()->where('invoice_id', '=', $payload['invoiceId'])->where('payment_status', '=', 'Settled')->where(function ($query) {
61
                return $query->where('invoice_status', 'Pending')->orWhereNull('invoice_status');
62
            })->first();
63
            if ($checkOrder !== null) {
64
                $user = User::query()->where('email', '=', $checkOrder->email)->first();
0 ignored issues
show
Bug introduced by
The property email does not seem to exist on App\Models\Payment. 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...
65
                if ($user) {
66
                    preg_match('/(?P<role>\w+(\s\+\+)?)[\s](?P<addYears>\d+)/i', $checkOrder->item_description, $matches);
0 ignored issues
show
Bug introduced by
The property item_description does not seem to exist on App\Models\Payment. 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...
67
                    User::updateUserRole($user->id, $matches['role']);
68
                    User::updateUserRoleChangeDate($user->id, null, $matches['addYears']);
69
                    $checkOrder->update(['invoice_status' => 'Settled']);
70
                    Log::info('User: '.$user->username.' upgraded to '.$matches['role'].' for BTCPay webhook: '.$checkOrder->webhook_id);
0 ignored issues
show
Bug introduced by
The property webhook_id does not seem to exist on App\Models\Payment. 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...
71
72
                    return response('OK', 200);
73
                }
74
75
                Log::error('User not found for BTCPay webhook: '.$checkOrder->webhook_id);
76
77
                return response('Not Found', 404);
78
            }
79
        }
80
81
        return response('OK', 200);
82
    }
83
}
84