ProcessCertificationRequestMailbox.php
1 <?php 2 3 namespace App\Jobs; 4 5 use App\Enums\InboxFileTypeEnum; 6 use App\Helpers\InboxFileSaver; 7 use App\Http\Requests\InboxSftpRequest; 8 use App\Http\Services\AutoRequirementService; 9 use App\Http\Services\CertificationRequestService; 10 use App\Http\Services\TaskService; 11 use App\Mail\CertificationRequestProcessed; 12 use App\Mail\CertificationRequestResponse; 13 use App\Models\User; 14 use Carbon\Carbon; 15 use Exception; 16 use Illuminate\Support\Facades\Mail; 17 use Illuminate\Support\Facades\Storage; 18 use Illuminate\Support\Facades\Validator; 19 use Webklex\IMAP\Facades\Client; 20 21 class ProcessCertificationRequestMailbox 22 { 23 public string $sender = ""; 24 public string $filename = ""; 25 public string $username = ""; 26 27 protected function rules() 28 { 29 return (new InboxSftpRequest())->rules(); 30 } 31 32 private function sendError($message, $errors) 33 { 34 $subject = $message->getSubject(); 35 $attachmentNames = []; 36 foreach ($message->getAttachments() as $attachment) { 37 $attachmentNames[] = $attachment->getName(); 38 } 39 40 $mailable = new CertificationRequestResponse($this->sender, $subject, $attachmentNames, $errors); 41 Mail::to($this->sender)->send($mailable); 42 } 43 44 public function validateMailAttachments($message) 45 { 46 $attachment = null; 47 48 try { 49 $attachments = $message->getAttachments(); 50 51 if (count($attachments) === 0) { 52 throw new Exception('No attachments were found'); 53 } 54 55 if (count($attachments) > 1) { 56 throw new Exception('Only one attachment is allowed'); 57 } 58 59 $attachment = $attachments[0]; 60 $extension = pathinfo($attachment->getName(), PATHINFO_EXTENSION); 61 if (!in_array($extension, ['zip', 'gpg', 'pgp'])) { 62 throw new Exception('Only zip files are accepted'); 63 } 64 } catch (Exception $e) { 65 $this->sendError($message, [$e->getMessage()]); 66 $attachment = null; 67 } 68 69 return $attachment; 70 } 71 72 public function processMessage($message) 73 { 74 // do not mark as seen when testing 75 if (config('app.env') === 'production') { 76 $message->setFlag('Seen'); 77 } 78 79 // get the sender 80 $this->sender = $message->getFrom()[0]->mail; 81 $user = User::where('email', $this->sender)->first(); 82 if (!$user) { 83 $this->sendError($message, ['User ' . $this->sender . ' is not enabled to perform this action']); 84 return null; 85 } 86 87 // get the attachment 88 $attachment = $this->validateMailAttachments($message); 89 if (!$attachment) { 90 return; 91 } 92 93 $path = 'inbox_files/' . $attachment->getName(); 94 $attachment->save(Storage::path('inbox_files/')); 95 96 // validate the document 97 $validator = Validator::make( 98 [ 99 'username' => $user->username, 100 'filename' => $path, 101 ], 102 $this->rules() 103 ); 104 if ($validator->fails()) { 105 $this->sendError($message, $validator->errors()->all()); 106 return; 107 } 108 109 // TODO: save the file and create the dossier if necessary 110 $dossierId = (new InboxSftpRequest)->getDossierId($path); 111 $inboxFileSaver = new InboxFileSaver($path, $user->id, $dossierId); 112 $inboxFileSaver->decrypt(); 113 114 if ($inboxFileSaver->type === InboxFileTypeEnum::certification_request() && !$dossierId) { 115 $certificationRequest = new CertificationRequestService($inboxFileSaver->path, $user->id); 116 $errors = $certificationRequest->readAndValidate(); 117 if (count($errors) > 0) { 118 $this->sendError($message, $errors); 119 return null; 120 } 121 122 $dossier = $certificationRequest->build(false); 123 $dossierId = $dossier->id; 124 } 125 126 $inboxFile = $inboxFileSaver->save($dossierId); 127 128 AutoRequirementService::run($inboxFile->validation); 129 TaskService::create( 130 [ 131 'title' => 'New validation received', 132 'description' => 'Please, assign a reviewer to validation.', 133 'start_date' => Carbon::now(), 134 'end_date' => null 135 ], 136 [ 137 'user_id' => $inboxFile->reviewer_id 138 ] 139 ); 140 141 142 Mail::to($this->sender)->send( 143 new CertificationRequestProcessed( 144 $this->sender, 145 $message->getSubject(), 146 [$attachment->getName()] 147 ) 148 ); 149 } 150 151 public function handle() 152 { 153 try { 154 $client = Client::account('default'); 155 $client->connect(); 156 } catch (Exception $e) { 157 logger()->info('Error connecting to mailbox'); 158 return; 159 } 160 161 $messages = $client->getFolderByPath('INBOX') 162 ->messages() 163 ->where(['subject' => 'Certification Request']) 164 ->unseen() 165 ->get(); 166 167 logger()->info('Found ' . count($messages) . ' messages'); 168 169 foreach ($messages as $message) { 170 $this->processMessage($message); 171 } 172 } 173 }