diff --git a/app/Helper/helpers.php b/app/Helper/helpers.php index 2c5b639..82e0831 100644 --- a/app/Helper/helpers.php +++ b/app/Helper/helpers.php @@ -6,6 +6,50 @@ use App\Models\Response; use App\Models\TicketNote; use Illuminate\Support\Facades\Session; +use Mailgun\Mailgun; +use App\Models\Company; + + +function get_company($key,$value){ + return Company::where($key,$value)->first(); +} + +function get_current_company_tickets($args = []){ + + $companyId = getSelectedCompany(); + + if(!$companyId){ + return false; + } + + $company = get_company('id',$companyId); + + if(!$company){ + return false; + } + + $tickets = Ticket::where('to_email', $company->email); + + if(isset($args['type'])){ + $tickets->where('type',$args['type']); + } + + if(isset($args['status'])){ + $tickets->where('status',$args['status']); + } + + if(isset($args['orderby'])){ + $tickets->orderBy($args['orderby'],$args['order']??'asc'); + } + + if(isset($args['with'])){ + $tickets->with($args['with']); + } + + $tickets = $tickets->get(); + + return $tickets; +} function getResponse($company_id, $key, $type) { $meta = CompanyMeta::where('company_id', $company_id)->where('key', $key)->where('type', $type)->first(); @@ -70,7 +114,7 @@ function insertTicket($from_email, $to_email, $subject, $content, $type, $sender function getSelectedCompany() { $company = Session::get('selected_company'); if (!$company) { - return response()->json(['message' => 'Company not found'], 404); + return false; } return $company; } @@ -110,3 +154,44 @@ function containsHtml($string) { return $string != strip_tags($string); } } + +if (!function_exists('sendEmailViaMailgun')) { + function sendEmailViaMailgun( $domain, $from, $to, $subject, $html) { + + $apiKey = env('MAILGUN_SECRET'); + + // Create a new Mailgun instance with API credentials + $mg = Mailgun::create($apiKey); + + // Prepare the message parameters + $params = [ + 'from' => $from, + 'to' => $to, + 'subject' => $subject, + 'html' => $html + ]; + + // Send the email + $response = $mg->messages()->send($domain, $params); + + // Return the response from Mailgun + return $response; + } + + function createResponse($ticket_id, $message, $user_id = 0) + { + // Create a new Response instance + $response = new Response; + + // Set the properties of the Response + $response->message = $message; + $response->ticket_id = $ticket_id; + $response->user_id = $user_id; // You may want to dynamically set the user_id based on the authenticated user + + // Save the response to the database + $response->save(); + + // Return the created response + return $response; + } +} diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 0c36387..a5b5086 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -13,19 +13,15 @@ class DashboardController extends Controller { public function dashboard() { - $companyId = Session::get('selected_company'); - $company = Company::find($companyId); - $tickets = Ticket::where('type', 'inbox') - ->where('to_email', 'LIKE', '%' . $company->domain) - ->get(); + + $tickets = get_current_company_tickets(['type' => 'inbox']); return view('index', ['tickets' => $tickets]); } public function waiting() { - $companyId = Session::get('selected_company'); - $company = Company::find($companyId); - $tickets = Ticket::where('status', 'waiting')->where('type', 'chat')->where('to_email', 'LIKE', '%' . $company->domain)->get(); + + $tickets = get_current_company_tickets(['status' => 'waiting']); return view('waiting', ['tickets' => $tickets]); } diff --git a/app/Http/Controllers/InboxController.php b/app/Http/Controllers/InboxController.php index 4ecd6e8..9066531 100644 --- a/app/Http/Controllers/InboxController.php +++ b/app/Http/Controllers/InboxController.php @@ -309,8 +309,18 @@ public function deleteSpamHandling($index) public function inbox() { - $tickets = Ticket::orderBy('id', 'desc')->with('lastResponse')->get(); + $tickets = get_current_company_tickets([ + + 'type' => 'inbox', + 'orderby' => 'id', + 'order' => 'desc', + 'with' => 'lastResponse' + + ]); + + $messages = []; + return view('inbox', ['tickets' => $tickets, 'messages' => $messages]); } diff --git a/app/Http/Controllers/Mailgun/EmailController.php b/app/Http/Controllers/Mailgun/EmailController.php index fa120af..74ef269 100644 --- a/app/Http/Controllers/Mailgun/EmailController.php +++ b/app/Http/Controllers/Mailgun/EmailController.php @@ -4,32 +4,56 @@ use App\Http\Controllers\Controller; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; class EmailController extends Controller { public function saveEmail(Request $request){ - $token = $request->input('token'); - $timestamp = $request->input('timestamp'); - $signature = $request->input('signature'); + DB::beginTransaction(); - // if (!verifyMailgunSignature($token, $timestamp, $signature)) { - // abort(403, 'Invalid signature.'); - // } + try { + + $token = $request->input('token'); + $timestamp = $request->input('timestamp'); + $signature = $request->input('signature'); - $data = $this->extractMailgunData($request->all()); - - insertTicket($data['from_email'], $data['to_email'], $data['subject'], $data['message'] ); - - update_setting('aw_test',json_encode($request->all())); + if (!verifyMailgunSignature($token, $timestamp, $signature)) { + update_setting('aw_test','Invalid signature.'); + abort(403, 'Invalid signature.'); + } + + $data = $this->extractMailgunData($request->all()); + + + + $to_email = $data['to_email']; + $message = $data['message']; + + update_setting('aw_test',$to_email); + + $company = get_company('email',$to_email); + + if($company){ + $ticket = insertTicket($data['from_email'], $data['to_email'], $data['subject'], $message,'inbox',$data['from_name'] ); + if($ticket) + $response = createResponse($ticket->id,$message); + }else{} + + // update_setting('aw_test',json_encode($request->all())); + + DB::commit(); + } catch (\Exception $e) { + update_setting('aw_test',$e->getMessage()); + DB::rollBack(); + // Handle the exception + } } public function extractMailgunData($data) { - // Decode the JSON payload into an associative array - // $data = json_decode($jsonPayload, true); - + // Prepare an array to hold the extracted data $extractedData = [ 'from_email' => $data['from'], diff --git a/app/Http/Controllers/Mailgun/MailgunController.php b/app/Http/Controllers/Mailgun/MailgunController.php index 0ed3a6b..72a5b49 100644 --- a/app/Http/Controllers/Mailgun/MailgunController.php +++ b/app/Http/Controllers/Mailgun/MailgunController.php @@ -5,6 +5,8 @@ use App\Http\Controllers\Controller; use Illuminate\Http\Request; use App\Services\MailgunService; +use Illuminate\Support\Str; +use App\Services\CPanelApiService; class MailgunController extends Controller { @@ -69,6 +71,18 @@ public function verifyDomain(Request $request) }elseif($state == 'active'){ $this->createRoute($request); + $email = "kundesone.$domain@kundesone.no"; + $this->createEmail($domain,$email); + + $company = get_company('domain',$domain); + + if($company){ + $company->internal_email = $email; + $company->save(); + } + + return $email; + return redirect('/dashboard'); } @@ -81,6 +95,23 @@ public function createRoute(Request $request) $response = $this->mailgunService->createRoute($domain, $forwardUrl); return $response; } + + public function createEmail($domain,$email){ + + + $password = Str::random(12); + $quota = 0; + + $response = $this->cpanelApiService->createEmailAccount($domain, $email, $password, $quota); + + if (isset($response['error'])) { + return false; + } + + return $email; + } + + } diff --git a/app/Http/Controllers/TicketController.php b/app/Http/Controllers/TicketController.php index 9053be0..5241da8 100644 --- a/app/Http/Controllers/TicketController.php +++ b/app/Http/Controllers/TicketController.php @@ -6,22 +6,27 @@ use App\Models\Ticket; use App\Models\Comment; use App\Models\Response; +use App\Models\Company; use Carbon\Carbon; +use Illuminate\Support\Facades\Session; class TicketController extends Controller { public function allTickets() { - $tickets = Ticket::all(); + $tickets = get_current_company_tickets(); return view('all-tickets', ['tickets' => $tickets]); } public function storeResponse(Request $request) { $this->validate($request, [ - 'message' => 'required' + 'message' => 'required' , + 'ticket_id' => 'required' , ]); + $ticket_id = $request->ticket_id; + // Load the HTML content into DOMDocument $dom = new \DOMDocument(); libxml_use_internal_errors(true); // Prevents HTML errors from being thrown as exceptions @@ -40,11 +45,21 @@ public function storeResponse(Request $request) // Save the modified HTML $messageWithClasses = $dom->saveHTML($dom->documentElement); - $response = new Response; - $response->message = $messageWithClasses; - $response->ticket_id = $request->ticket_id; - $response->user_id = 1; - $response->save(); + // create response + $response = createResponse($ticket_id,$messageWithClasses,1); + + $ticket = Ticket::find($ticket_id); + $companyId = Session::get('selected_company'); + $company = get_company('id',$companyId); + //Send mail to mailgun + + $domain = $company->domain; + $from = $company->email; + $to = $ticket->from_email; + $subject = $ticket->subject; + $html = $request->message; + + sendEmailViaMailgun($domain, $from, $to, $subject, $html); // Return the updated response and time return response()->json([ @@ -85,4 +100,12 @@ public function storeComment(Request $request) return $comment; } + + public function deleteComment($commentId) + { + $comment = Comment::findOrFail($commentId); + $comment->delete(); + + return response()->json(['message' => 'Comment Deleted Successfully']); + } } diff --git a/app/Services/CPanelApiService.php b/app/Services/CPanelApiService.php new file mode 100644 index 0000000..30192e3 --- /dev/null +++ b/app/Services/CPanelApiService.php @@ -0,0 +1,50 @@ +cpanelUrl = env('CPANEL_URL'); + $this->cpanelUsername = env('CPANEL_USERNAME'); + $this->cpanelToken = env('CPANEL_TOKEN'); + + $this->client = new Client([ + 'base_uri' => $this->cpanelUrl, + 'headers' => [ + 'Authorization' => 'cpanel ' . $this->cpanelUsername . ':' . $this->cpanelToken + ] + ]); + } + + public function createEmailAccount($domain, $email, $password, $quota) + { + $query = [ + 'cpanel_jsonapi_user' => $this->cpanelUsername, + 'cpanel_jsonapi_apiversion' => '2', + 'cpanel_jsonapi_module' => 'Email', + 'cpanel_jsonapi_func' => 'addpop', + 'domain' => $domain, + 'email' => $email, + 'password' => $password, + 'quota' => $quota + ]; + + try { + $response = $this->client->request('GET', '/json-api/cpanel', ['query' => $query]); + return json_decode($response->getBody(), true); + } catch (GuzzleException $e) { + return ['error' => $e->getMessage()]; + } + } +} diff --git a/composer.json b/composer.json index 480a997..44c8b9f 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "license": "MIT", "require": { "php": "^8.1", - "guzzlehttp/guzzle": "^7.2", + "guzzlehttp/guzzle": "^7.8", "laravel/framework": "^10.10", "laravel/sanctum": "^3.3", "laravel/tinker": "^2.8", diff --git a/composer.lock b/composer.lock index 761cd8a..d1777ee 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e3f9f69a248021a08a4b420d64573db7", + "content-hash": "3427d1f055fffcf2c0867d5d8137c3f3", "packages": [ { "name": "brick/math", diff --git a/database/migrations/2024_06_28_061929_add_internal_email_to_companies.php b/database/migrations/2024_06_28_061929_add_internal_email_to_companies.php new file mode 100644 index 0000000..9877f07 --- /dev/null +++ b/database/migrations/2024_06_28_061929_add_internal_email_to_companies.php @@ -0,0 +1,28 @@ +string('internal_email')->default(''); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('companies', function (Blueprint $table) { + // + }); + } +}; diff --git a/error_log b/error_log index 93f1793..b27f7d8 100644 --- a/error_log +++ b/error_log @@ -30,3 +30,8 @@ [26-Jun-2024 04:05:49 UTC] PHP Warning: Module "fileinfo" is already loaded in Unknown on line 0 [26-Jun-2024 11:15:17 UTC] PHP Warning: Module "fileinfo" is already loaded in Unknown on line 0 [26-Jun-2024 11:31:01 UTC] PHP Warning: Module "fileinfo" is already loaded in Unknown on line 0 +[28-Jun-2024 06:04:29 UTC] PHP Warning: Module "fileinfo" is already loaded in Unknown on line 0 +[28-Jun-2024 06:04:33 UTC] PHP Warning: Module "fileinfo" is already loaded in Unknown on line 0 +[28-Jun-2024 06:04:34 UTC] PHP Warning: Module "fileinfo" is already loaded in Unknown on line 0 +[28-Jun-2024 06:18:54 UTC] PHP Warning: Module "fileinfo" is already loaded in Unknown on line 0 +[28-Jun-2024 06:20:52 UTC] PHP Warning: Module "fileinfo" is already loaded in Unknown on line 0 diff --git a/resources/views/components/header.blade.php b/resources/views/components/header.blade.php index 8d776a2..566b10f 100644 --- a/resources/views/components/header.blade.php +++ b/resources/views/components/header.blade.php @@ -4,7 +4,7 @@
-

Hello Maxwell 👋🏼,

+

Hello {{auth()->user()->name}} 👋🏼,

- @if(Auth::user()->role_id == 2) - @endif @@ -420,9 +418,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ? - @if(Auth::user()->role_id == 2) - @endif @@ -471,15 +467,13 @@ function toggleClosed(day) { @csrf
- +
- +
- @if(Auth::user()->role_id == 2) - @endif @@ -487,6 +481,7 @@ function toggleClosed(day) {

Canned responses

+ @if(!is_null($canned_response)) @foreach(json_decode($canned_response->value) as $index => $values)
@@ -497,10 +492,11 @@ function toggleClosed(day) {
- +
@endforeach + @endif
@@ -865,6 +861,7 @@ class="form-control input-reply-textarea">{!! $automatic_reply_text->value ?? ''

Email addresses that never should be marked as spam
Blocked email addresses

+ @if(!is_null($spam_handling)) @foreach(json_decode($spam_handling->value) as $index => $values)
@@ -875,14 +872,46 @@ class="form-control input-reply-textarea">{!! $automatic_reply_text->value ?? ''
- +
@endforeach + @endif
+ + + +
diff --git a/resources/views/layouts/setting.blade.php b/resources/views/layouts/setting.blade.php index 2f7261e..35e30fb 100644 --- a/resources/views/layouts/setting.blade.php +++ b/resources/views/layouts/setting.blade.php @@ -103,7 +103,7 @@ class="side-bar-link bg-light-color d-flex align-items-center justify-content-be
-

Hello Maxwell 👋🏼,

+

Hello {{auth()->user()->name}} 👋🏼,

@@ -80,6 +80,50 @@ class="ui button comment--btn bg-light-green-color color-light comment-delete-bt
+ + + +