Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
AI
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 5
506
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 send_email
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
182
 isEmailValid
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 isValidHtml
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 isValidEmailSubject
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3namespace App\Http\Controllers;
4
5use Illuminate\Support\Facades\Validator;
6use Illuminate\Contracts\Routing\ResponseFactory;
7use Illuminate\Http\Request;
8use Illuminate\Http\Response;
9use Illuminate\Support\Facades\Log;
10use App\Exceptions\AppException;
11
12class AI extends Controller
13{
14    public function __construct() {}
15
16    public function send_email(Request $request): ResponseFactory|Response{
17
18        try {
19
20            $data = $request->all();
21
22            $body = '';
23            $subject = '';
24
25            $validator = Validator::make($data, [
26                'email' => ['required', 'email'],
27                'subject' => ['required'],
28                'body' => ['required'],
29            ]);
30
31            if ($validator->fails()) {
32                if ($validator->errors()->has('email')
33                    && ! $request->has('email')) {
34
35                    return response()->json([
36                        'status' => 'error',
37                        'message' => 'Missing required field: email',
38                        'code' => 'MISSING_FIELD',
39                    ], 400);
40                }
41
42                if (! $this->isEmailValid($data['email'])) {
43                    return response([
44                        'status' => 'error',
45                        'message' => 'Invalid email address format!',
46                        'code' => 'INVALID_EMAIL',
47                    ], 400);
48                }
49
50                if ($validator->errors()->has('subject')
51                    && ! $request->has('subject')) {
52
53                    return response()->json([
54                        'status' => 'error',
55                        'message' => 'Missing required field: subject',
56                        'code' => 'MISSING_FIELD',
57                    ], 400);
58                }
59
60                if (! $this->isValidEmailSubject($data['subject'])) {
61                    return response([
62                        'status' => 'error',
63                        'message' => 'Invalid email subject!',
64                        'code' => 'INVALID_SUBJECT',
65                    ], 400);
66                }
67
68                if ($validator->errors()->has('body')
69                    && ! $request->has('body')) {
70
71                    return response()->json([
72                        'status' => 'error',
73                        'message' => 'Missing required field: body',
74                        'code' => 'MISSING_FIELD',
75                    ], 400);
76                }
77
78                if (! $this->isValidHtml($data['body'])) {
79                    return response()->json([
80                        'status' => 'error',
81                        'message' => 'Invalid HTML!',
82                        'code' => 'INVALID_BODY',
83                    ], 422);
84                }
85            }
86
87            $toEmail = $data['email'];
88            $body = $data['body'];
89            $subject = $data['subject'];
90
91            $mail = new \SendGrid\Mail\Mail;
92
93            $mail->setFrom('fire@fire.es', 'Fire Service Titan');
94            $mail->addTo($toEmail);
95            $mail->setSubject($subject);
96            $mail->addContent("text/html", $body);
97            
98            $sendgrid = new \SendGrid(config('services.sendgrid.api_key'));
99
100            Log::channel('email_log')->info(print_r($data, true));
101
102            $response = $sendgrid->send($mail);
103            if ($response->statusCode() == 202) {
104                return response([
105                    'status' => 'success',
106                    'message' => 'Verification email sent successfully!',
107                    'email' => $toEmail,
108                ], 200);
109            }
110
111            return response([
112                'status' => 'error',
113                'message' => 'Failed to send email. Please try again later.',
114                'code' => 'EMAIL_DELIVERY_FAILED',
115            ], 500);
116
117        } catch (\Exception $e) {
118            report(AppException::fromException($e, 'SEND_VERIFICATION_EMAIL_EXCEPTION'));
119            return response(['message' => 'KO', 'error' => $e->getMessage()]);
120        }
121
122    }
123
124    function isEmailValid($email): bool {
125        
126        $pattern = '/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/';
127        
128        if (preg_match($pattern, (string) $email)) {
129            return true;
130        } else {
131            return false;
132        }
133
134    }
135
136    private function isValidHtml($html)
137    {
138        libxml_use_internal_errors(true);
139
140        $dom = new \DOMDocument;
141        $isValid = $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
142
143        libxml_clear_errors();
144
145        return $isValid;
146    }
147
148    public function isValidEmailSubject(string $subject): bool
149    {
150        $subject = trim($subject);
151
152        if ($subject === '' || mb_strlen($subject) < 3 || mb_strlen($subject) > 150) {
153            return false;
154        }
155
156        if (preg_match('/[\r\n]/', $subject)) {
157            return false;
158        }
159
160        return true;
161    }
162}