Passed
Push — master ( 09fe79...7f4a11 )
by George
04:52
created

handleSubscriptionConfirmation()   A

Complexity

Conditions 6
Paths 11

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 7.3329

Importance

Changes 0
Metric Value
cc 6
eloc 16
nc 11
nop 1
dl 0
loc 24
ccs 10
cts 15
cp 0.6667
crap 7.3329
rs 9.1111
c 0
b 0
f 0
1
<?php
2
3
namespace ag84ark\AwsSesBounceComplaintHandler;
4
5
use ag84ark\AwsSesBounceComplaintHandler\Models\WrongEmail;
6
use GuzzleHttp\Client;
7
use Illuminate\Http\JsonResponse;
8
use Illuminate\Http\Request;
9
use Illuminate\Support\Collection;
10
use Illuminate\Support\Facades\Response;
11
use Log;
12
13
class AwsSesBounceComplaintHandler
14
{
15 2
    public static function canSendToEmail(string $email): bool
16
    {
17
        /** @var WrongEmail[]|Collection $emails */
18 2
        $emails = WrongEmail::active()
19 2
            ->bounced()
20 2
            ->where('email', '=', $email)
21 2
            ->get();
22
23 2
        foreach ($emails as $wrongEmail) {
24 1
            if (! $wrongEmail->canBouncedSend()) {
25 1
                return false;
26
            }
27
        }
28
29 1
        return true;
30
    }
31
32 8
    public function handleBounceOrComplaint(Request $request): JsonResponse
33
    {
34 8
        if (! $request->json()) {
35
            return Response::json(['status' => 422, 'message' => 'error'], 422);
36
        }
37
38 8
        if (! $this->canPass($request)) {
39 1
            return Response::json(['status' => 403, 'message' => 'error'], 403);
40
        }
41
42 7
        $data = $request->json()->all() ?? [];
43
44 7
        $this->handleLoggingData($data);
45
46 7
        if ($info = $this->handleSubscriptionConfirmation($data)) {
47 1
            return Response::json(['status' => 200, 'message' => $info]);
48
        }
49
50 6
        $message = $this->getMessageData($request, $data);
51
52 6
        if (! count($message)) {
53
            return Response::json(['status' => 422, 'data' => $data], 422);
54
        }
55
56 6
        if (! isset($message['notificationType'])) {
57 1
            return Response::json(['status' => 200, 'message' => 'no data']);
58
        }
59
60 5
        $this->storeEmailToDB($message);
61
62 5
        return Response::json(['status' => 200, 'message' => 'success']);
63
    }
64
65 8
    private function canPass(Request $request): bool
66
    {
67 8
        if (config('aws-ses-bounce-complaint-handler.via_sqs')) {
68 1
            return true;
69
        }
70
71 7
        $secret = config('aws-ses-bounce-complaint-handler.route_secret');
72 7
        if (! $secret) {
73 5
            return true;
74
        }
75
76 2
        if ($secret !== $request->get('secret')) {
77 1
            return false;
78
        }
79
80 1
        return true;
81
    }
82
83 7
    private function handleLoggingData(array $data): void
84
    {
85 7
        if (config('aws-ses-bounce-complaint-handler.log_requests')) {
86 1
            $dataCollection = collect($data);
87 1
            Log::info('Logging AWS SES DATA');
88 1
            Log::info($dataCollection->toJson());
89
        }
90 7
    }
91
92 7
    public function handleSubscriptionConfirmation(array $data): ?string
93
    {
94
        try {
95 7
            if (! isset($data['Type']) || 'SubscriptionConfirmation' !== $data['Type'] || ! config('aws-ses-bounce-complaint-handler.auto_subscribe')) {
96 6
                return null;
97
            }
98 1
            Log::info('SubscriptionConfirmation came at: '.$data['Timestamp']);
99
100 1
            $client = new Client();
101
102 1
            $res = $client->get($data['SubscribeURL']);
103
104 1
            if (200 === $res->getStatusCode()) {
105 1
                $message = 'SubscriptionConfirmation was auto confirmed!';
106 1
                Log::info($message);
107
            } else {
108
                $message = 'SubscriptionConfirmation could not be auto confirmed!';
109
                Log::warning($message);
110
                Log::info($data['SubscribeURL']);
111
            }
112
113 1
            return $message;
114
        } catch (\Exception $exception) {
115
            return  $exception->getMessage();
116
        }
117
    }
118
119
    /**
120
     * @return array|mixed|\Symfony\Component\HttpFoundation\ParameterBag|null
121
     */
122 6
    private function getMessageData(Request $request, array $data)
123
    {
124 6
        $message = [];
125
126 6
        if (config('aws-ses-bounce-complaint-handler.via_sqs')) {
127 1
            if ('Notification' === $request->json('Type')) {
128 1
                $message = $request->json('Message');
129
            }
130
        } else {
131 5
            $message = $data;
132
        }
133
134 6
        return $message;
135
    }
136
137
    /**
138
     * @param $message
139
     */
140 5
    private function storeEmailToDB($message): void
141
    {
142 5
        switch ($message['notificationType']) {
143 5
            case 'Bounce':
144 4
                $bounce = $message['bounce'];
145 4
                $this->saveBouncedEmailsToDB($bounce);
146
147 4
                break;
148
149 1
            case 'Complaint':
150 1
                $complaint = $message['complaint'];
151 1
                $this->saveComplainedEmailsToDB($complaint);
152
153 1
                break;
154
155
            default:
156
                // Do Nothing
157
                break;
158
        }
159 5
    }
160
161
    /**
162
     * @param $bounce
163
     */
164 4
    private function saveBouncedEmailsToDB($bounce): void
165
    {
166 4
        $subtype = $bounce['bounceType'];
167 4
        foreach ($bounce['bouncedRecipients'] as $bouncedRecipient) {
168 4
            $emailAddress = $bouncedRecipient['emailAddress'];
169
170 4
            $emailRecord = WrongEmail::firstOrCreate(['email' => $emailAddress, 'problem_type' => 'Bounce', 'problem_subtype' => $subtype]);
171 4
            if ($emailRecord) {
172 4
                $emailRecord->increment('repeated_attempts', 1);
173
            }
174
        }
175 4
    }
176
177
    /**
178
     * @param $complaint
179
     */
180 1
    private function saveComplainedEmailsToDB($complaint): void
181
    {
182 1
        $subtype = $complaint['complaintFeedbackType'] ?? '';
183 1
        foreach ($complaint['complainedRecipients'] as $complainedRecipient) {
184 1
            $emailAddress = $complainedRecipient['emailAddress'];
185 1
            $emailRecord = WrongEmail::firstOrCreate(['email' => $emailAddress, 'problem_type' => 'Complaint', 'problem_subtype' => $subtype]);
186 1
            if ($emailRecord) {
187 1
                $emailRecord->increment('repeated_attempts', 1);
188
            }
189
        }
190 1
    }
191
}
192