added cpanel api
This commit is contained in:
parent
804e880331
commit
1760c7e0aa
|
|
@ -6,6 +6,50 @@
|
||||||
use App\Models\Response;
|
use App\Models\Response;
|
||||||
use App\Models\TicketNote;
|
use App\Models\TicketNote;
|
||||||
use Illuminate\Support\Facades\Session;
|
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) {
|
function getResponse($company_id, $key, $type) {
|
||||||
$meta = CompanyMeta::where('company_id', $company_id)->where('key', $key)->where('type', $type)->first();
|
$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() {
|
function getSelectedCompany() {
|
||||||
$company = Session::get('selected_company');
|
$company = Session::get('selected_company');
|
||||||
if (!$company) {
|
if (!$company) {
|
||||||
return response()->json(['message' => 'Company not found'], 404);
|
return false;
|
||||||
}
|
}
|
||||||
return $company;
|
return $company;
|
||||||
}
|
}
|
||||||
|
|
@ -110,3 +154,44 @@ function containsHtml($string) {
|
||||||
return $string != strip_tags($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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,19 +13,15 @@ class DashboardController extends Controller
|
||||||
{
|
{
|
||||||
public function dashboard()
|
public function dashboard()
|
||||||
{
|
{
|
||||||
$companyId = Session::get('selected_company');
|
|
||||||
$company = Company::find($companyId);
|
$tickets = get_current_company_tickets(['type' => 'inbox']);
|
||||||
$tickets = Ticket::where('type', 'inbox')
|
|
||||||
->where('to_email', 'LIKE', '%' . $company->domain)
|
|
||||||
->get();
|
|
||||||
return view('index', ['tickets' => $tickets]);
|
return view('index', ['tickets' => $tickets]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function waiting()
|
public function waiting()
|
||||||
{
|
{
|
||||||
$companyId = Session::get('selected_company');
|
|
||||||
$company = Company::find($companyId);
|
$tickets = get_current_company_tickets(['status' => 'waiting']);
|
||||||
$tickets = Ticket::where('status', 'waiting')->where('type', 'chat')->where('to_email', 'LIKE', '%' . $company->domain)->get();
|
|
||||||
return view('waiting', ['tickets' => $tickets]);
|
return view('waiting', ['tickets' => $tickets]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -309,8 +309,18 @@ public function deleteSpamHandling($index)
|
||||||
|
|
||||||
public function inbox()
|
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 = [];
|
$messages = [];
|
||||||
|
|
||||||
return view('inbox', ['tickets' => $tickets, 'messages' => $messages]);
|
return view('inbox', ['tickets' => $tickets, 'messages' => $messages]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,32 +4,56 @@
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class EmailController extends Controller
|
class EmailController extends Controller
|
||||||
{
|
{
|
||||||
public function saveEmail(Request $request){
|
public function saveEmail(Request $request){
|
||||||
|
|
||||||
$token = $request->input('token');
|
DB::beginTransaction();
|
||||||
$timestamp = $request->input('timestamp');
|
|
||||||
$signature = $request->input('signature');
|
|
||||||
|
|
||||||
// if (!verifyMailgunSignature($token, $timestamp, $signature)) {
|
try {
|
||||||
// abort(403, 'Invalid signature.');
|
|
||||||
// }
|
$token = $request->input('token');
|
||||||
|
$timestamp = $request->input('timestamp');
|
||||||
|
$signature = $request->input('signature');
|
||||||
|
|
||||||
$data = $this->extractMailgunData($request->all());
|
if (!verifyMailgunSignature($token, $timestamp, $signature)) {
|
||||||
|
update_setting('aw_test','Invalid signature.');
|
||||||
insertTicket($data['from_email'], $data['to_email'], $data['subject'], $data['message'] );
|
abort(403, 'Invalid signature.');
|
||||||
|
}
|
||||||
update_setting('aw_test',json_encode($request->all()));
|
|
||||||
|
$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) {
|
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
|
// Prepare an array to hold the extracted data
|
||||||
$extractedData = [
|
$extractedData = [
|
||||||
'from_email' => $data['from'],
|
'from_email' => $data['from'],
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Services\MailgunService;
|
use App\Services\MailgunService;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use App\Services\CPanelApiService;
|
||||||
|
|
||||||
class MailgunController extends Controller
|
class MailgunController extends Controller
|
||||||
{
|
{
|
||||||
|
|
@ -69,6 +71,18 @@ public function verifyDomain(Request $request)
|
||||||
}elseif($state == 'active'){
|
}elseif($state == 'active'){
|
||||||
$this->createRoute($request);
|
$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');
|
return redirect('/dashboard');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -81,6 +95,23 @@ public function createRoute(Request $request)
|
||||||
$response = $this->mailgunService->createRoute($domain, $forwardUrl);
|
$response = $this->mailgunService->createRoute($domain, $forwardUrl);
|
||||||
return $response;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,22 +6,27 @@
|
||||||
use App\Models\Ticket;
|
use App\Models\Ticket;
|
||||||
use App\Models\Comment;
|
use App\Models\Comment;
|
||||||
use App\Models\Response;
|
use App\Models\Response;
|
||||||
|
use App\Models\Company;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
class TicketController extends Controller
|
class TicketController extends Controller
|
||||||
{
|
{
|
||||||
public function allTickets()
|
public function allTickets()
|
||||||
{
|
{
|
||||||
$tickets = Ticket::all();
|
$tickets = get_current_company_tickets();
|
||||||
return view('all-tickets', ['tickets' => $tickets]);
|
return view('all-tickets', ['tickets' => $tickets]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function storeResponse(Request $request)
|
public function storeResponse(Request $request)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'message' => 'required'
|
'message' => 'required' ,
|
||||||
|
'ticket_id' => 'required' ,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$ticket_id = $request->ticket_id;
|
||||||
|
|
||||||
// Load the HTML content into DOMDocument
|
// Load the HTML content into DOMDocument
|
||||||
$dom = new \DOMDocument();
|
$dom = new \DOMDocument();
|
||||||
libxml_use_internal_errors(true); // Prevents HTML errors from being thrown as exceptions
|
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
|
// Save the modified HTML
|
||||||
$messageWithClasses = $dom->saveHTML($dom->documentElement);
|
$messageWithClasses = $dom->saveHTML($dom->documentElement);
|
||||||
|
|
||||||
$response = new Response;
|
// create response
|
||||||
$response->message = $messageWithClasses;
|
$response = createResponse($ticket_id,$messageWithClasses,1);
|
||||||
$response->ticket_id = $request->ticket_id;
|
|
||||||
$response->user_id = 1;
|
$ticket = Ticket::find($ticket_id);
|
||||||
$response->save();
|
$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 the updated response and time
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
|
@ -85,4 +100,12 @@ public function storeComment(Request $request)
|
||||||
|
|
||||||
return $comment;
|
return $comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deleteComment($commentId)
|
||||||
|
{
|
||||||
|
$comment = Comment::findOrFail($commentId);
|
||||||
|
$comment->delete();
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Comment Deleted Successfully']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
// app/Services/CPanelApiService.php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\GuzzleException;
|
||||||
|
|
||||||
|
class CPanelApiService
|
||||||
|
{
|
||||||
|
protected $client;
|
||||||
|
protected $cpanelUrl;
|
||||||
|
protected $cpanelUsername;
|
||||||
|
protected $cpanelToken;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->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()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.1",
|
"php": "^8.1",
|
||||||
"guzzlehttp/guzzle": "^7.2",
|
"guzzlehttp/guzzle": "^7.8",
|
||||||
"laravel/framework": "^10.10",
|
"laravel/framework": "^10.10",
|
||||||
"laravel/sanctum": "^3.3",
|
"laravel/sanctum": "^3.3",
|
||||||
"laravel/tinker": "^2.8",
|
"laravel/tinker": "^2.8",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "e3f9f69a248021a08a4b420d64573db7",
|
"content-hash": "3427d1f055fffcf2c0867d5d8137c3f3",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('companies', function (Blueprint $table) {
|
||||||
|
$table->string('internal_email')->default('');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('companies', function (Blueprint $table) {
|
||||||
|
//
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -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 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: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
|
[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
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="dev-toggle-sidebar">
|
<div class="dev-toggle-sidebar">
|
||||||
<img src="{{ asset('images/icons/blocks-icon.svg') }}">
|
<img src="{{ asset('images/icons/blocks-icon.svg') }}">
|
||||||
</div>
|
</div>
|
||||||
<h2 class="d-flex align-items-center">Hello Maxwell <span>👋🏼</span>,</h2>
|
<h2 class="d-flex align-items-center">Hello {{auth()->user()->name}} <span>👋🏼</span>,</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-8 d-flex justify-content-end align-items-center">
|
<div class="col-sm-8 d-flex justify-content-end align-items-center">
|
||||||
<div class="search-box d-flex align-items-center">
|
<div class="search-box d-flex align-items-center">
|
||||||
|
|
|
||||||
|
|
@ -186,9 +186,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
|
||||||
title.</span>
|
title.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if(Auth::user()->role_id == 2)
|
|
||||||
<button type="submit" class="dev-form-submit-btn">Save</button>
|
<button type="submit" class="dev-form-submit-btn">Save</button>
|
||||||
@endif
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -420,9 +418,7 @@ class="form-control input-reply-textarea" required>{!! $email_signature->value ?
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@if(Auth::user()->role_id == 2)
|
|
||||||
<button type="submit" class="dev-form-submit-btn">Save</button>
|
<button type="submit" class="dev-form-submit-btn">Save</button>
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -471,15 +467,13 @@ function toggleClosed(day) {
|
||||||
@csrf
|
@csrf
|
||||||
<div class="dev-input-group dev-input-group-input-info">
|
<div class="dev-input-group dev-input-group-input-info">
|
||||||
<label>Name</label>
|
<label>Name</label>
|
||||||
<input name="name" type="text" placeholder="Type here" value="{{ $canned_response[0]['value'] ?? '' }}" required>
|
<input name="name" type="text" placeholder="Type here" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="dev-input-group dev-input-group-input-info">
|
<div class="dev-input-group dev-input-group-input-info">
|
||||||
<label>Text</label>
|
<label>Text</label>
|
||||||
<textarea name="text" required rows="6">{{ $canned_response[1]['value'] ?? '' }}</textarea>
|
<textarea name="text" required rows="6"></textarea>
|
||||||
</div>
|
</div>
|
||||||
@if(Auth::user()->role_id == 2)
|
|
||||||
<button type="submit" class="dev-form-submit-btn">Save</button>
|
<button type="submit" class="dev-form-submit-btn">Save</button>
|
||||||
@endif
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -487,6 +481,7 @@ function toggleClosed(day) {
|
||||||
<div class="dev-title-row">
|
<div class="dev-title-row">
|
||||||
<h2>Canned responses</h2>
|
<h2>Canned responses</h2>
|
||||||
<div class="dev-users-boxs">
|
<div class="dev-users-boxs">
|
||||||
|
@if(!is_null($canned_response))
|
||||||
@foreach(json_decode($canned_response->value) as $index => $values)
|
@foreach(json_decode($canned_response->value) as $index => $values)
|
||||||
<div class="dev-users-box">
|
<div class="dev-users-box">
|
||||||
<div class="dev-box">
|
<div class="dev-box">
|
||||||
|
|
@ -497,10 +492,11 @@ function toggleClosed(day) {
|
||||||
<img src="{{ asset('images/settingss.svg') }}" alt="">
|
<img src="{{ asset('images/settingss.svg') }}" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div class="dev-icon">
|
<div class="dev-icon">
|
||||||
<a href="{{ route('delete.canned.response', $index) }}" class="delete-user"><img src="{{ asset('images/binn.svg') }}" alt=""></a>
|
<a style="cursor:pointer;" href="{{ route('delete.canned.response', $index) }}" class="delete-user"><img src="{{ asset('images/binn.svg') }}" alt=""></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -865,6 +861,7 @@ class="form-control input-reply-textarea">{!! $automatic_reply_text->value ?? ''
|
||||||
<h2>Email addresses that never should be marked as spam<br>
|
<h2>Email addresses that never should be marked as spam<br>
|
||||||
Blocked email addresses</h2>
|
Blocked email addresses</h2>
|
||||||
<div class="dev-users-boxs">
|
<div class="dev-users-boxs">
|
||||||
|
@if(!is_null($spam_handling))
|
||||||
@foreach(json_decode($spam_handling->value) as $index => $values)
|
@foreach(json_decode($spam_handling->value) as $index => $values)
|
||||||
<div class="dev-users-box">
|
<div class="dev-users-box">
|
||||||
<div class="dev-box">
|
<div class="dev-box">
|
||||||
|
|
@ -875,14 +872,46 @@ class="form-control input-reply-textarea">{!! $automatic_reply_text->value ?? ''
|
||||||
<img src="{{ asset('images/settingss.svg') }}" alt="">
|
<img src="{{ asset('images/settingss.svg') }}" alt="">
|
||||||
</div>
|
</div>
|
||||||
<div class="dev-icon">
|
<div class="dev-icon">
|
||||||
<a href="{{ route('delete.spam.handling', $index) }}" class="delete-user"><img src="{{ asset('images/binn.svg') }}" alt=""></a>
|
<a href="{{ route('delete.spam.handling', $index) }}" style="cursor:pointer;" class="delete-user"><img src="{{ asset('images/binn.svg') }}" alt=""></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@10"></script>
|
||||||
|
<script defer>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const deleteLinks = document.querySelectorAll('.delete-user');
|
||||||
|
|
||||||
|
deleteLinks.forEach(function (link) {
|
||||||
|
link.addEventListener('click', function (event) {
|
||||||
|
event.preventDefault(); // Prevent the default link click behavior
|
||||||
|
|
||||||
|
const url = this.href;
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Are you sure?',
|
||||||
|
text: "You won't be able to revert this!",
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: '#3085d6',
|
||||||
|
cancelButtonColor: '#d33',
|
||||||
|
confirmButtonText: 'Yes, delete it!'
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
// If the user confirms, redirect to the delete URL
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<!-- -->
|
<!-- -->
|
||||||
<div class="dev-tabcontent dev-tabcontent-tags">
|
<div class="dev-tabcontent dev-tabcontent-tags">
|
||||||
<div class="dev-tabcontent-outers">
|
<div class="dev-tabcontent-outers">
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ class="side-bar-link bg-light-color d-flex align-items-center justify-content-be
|
||||||
<div class="dev-toggle-sidebar">
|
<div class="dev-toggle-sidebar">
|
||||||
<img src="{{ asset('images/icons/blocks-icon.svg') }}">
|
<img src="{{ asset('images/icons/blocks-icon.svg') }}">
|
||||||
</div>
|
</div>
|
||||||
<h2 class="d-flex align-items-center">Hello Maxwell <span>👋🏼</span>,</h2>
|
<h2 class="d-flex align-items-center">Hello {{auth()->user()->name}} <span>👋🏼</span>,</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-8 d-flex justify-content-end align-items-center">
|
<div class="col-sm-8 d-flex justify-content-end align-items-center">
|
||||||
<div class="search-box d-flex align-items-center">
|
<div class="search-box d-flex align-items-center">
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ class="ui button comment--btn bg-dark-green-color color-light comment-edit-btn "
|
||||||
<i class="edit outline icon"></i>
|
<i class="edit outline icon"></i>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="ui button comment--btn bg-light-green-color color-light comment-delete-btn">
|
class="ui button comment--btn bg-light-green-color color-light comment-delete-btn" data-comment-id="{{ $comment->id }}">
|
||||||
<i class="trash alternate outline icon"></i>
|
<i class="trash alternate outline icon"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -80,6 +80,50 @@ class="ui button comment--btn bg-light-green-color color-light comment-delete-bt
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!--delete Comment-->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('.comment-delete-btn').on('click', function() {
|
||||||
|
var commentId = $(this).data('comment-id');
|
||||||
|
var commentElement = $(this).closest('.response-comment');
|
||||||
|
|
||||||
|
// SweetAlert confirmation dialog
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Are you sure?',
|
||||||
|
text: "You won't be able to revert this!",
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonColor: '#3085d6',
|
||||||
|
cancelButtonColor: '#d33',
|
||||||
|
confirmButtonText: 'Yes, delete it!'
|
||||||
|
}).then((result) => {
|
||||||
|
if (result.isConfirmed) {
|
||||||
|
$.ajax({
|
||||||
|
url: '/delete-comment/' + commentId,
|
||||||
|
method: 'GET',
|
||||||
|
data: {
|
||||||
|
_token: '{{ csrf_token() }}'
|
||||||
|
},
|
||||||
|
success: function(response) {
|
||||||
|
toastr.success("Comment Deleted Successfully");
|
||||||
|
commentElement.remove();
|
||||||
|
},
|
||||||
|
error: function(error) {
|
||||||
|
console.error('Error deleting comment:', error);
|
||||||
|
Swal.fire(
|
||||||
|
'Error!',
|
||||||
|
'An error occurred while deleting the comment.',
|
||||||
|
'error'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
<!--store comment-->
|
<!--store comment-->
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
@ -101,9 +145,18 @@ class="ui button comment--btn bg-light-green-color color-light comment-delete-bt
|
||||||
_token: '{{ csrf_token() }}'
|
_token: '{{ csrf_token() }}'
|
||||||
},
|
},
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
$('.accordion-body--custom').prepend(response);
|
|
||||||
toastr.success("Comment Added Successfully");
|
toastr.success("Comment Added Successfully");
|
||||||
$('.input-comment-textarea').val('');
|
$('.input-comment-textarea').val('');
|
||||||
|
$.ajax({
|
||||||
|
url: '/fetch-action-box/' + ticketId,
|
||||||
|
method: 'GET',
|
||||||
|
success: function(response) {
|
||||||
|
$('.action-box').html(response);
|
||||||
|
},
|
||||||
|
error: function(error) {
|
||||||
|
console.log('Error fetching action box content:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
error: function(error) {
|
error: function(error) {
|
||||||
console.error('Error adding comment:', error);
|
console.error('Error adding comment:', error);
|
||||||
|
|
@ -116,35 +169,27 @@ class="ui button comment--btn bg-light-green-color color-light comment-delete-bt
|
||||||
<!--change ticket status-->
|
<!--change ticket status-->
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
// Click event for status buttons
|
|
||||||
$('.status-btn').on('click', function() {
|
$('.status-btn').on('click', function() {
|
||||||
var newStatus = $(this).data('status');
|
var newStatus = $(this).data('status');
|
||||||
|
|
||||||
// Update UI immediately
|
|
||||||
$('.status-btn').removeClass('active');
|
$('.status-btn').removeClass('active');
|
||||||
$(this).addClass('active');
|
$(this).addClass('active');
|
||||||
|
|
||||||
// Optionally, update backend via AJAX
|
|
||||||
updateTicketStatus(newStatus);
|
updateTicketStatus(newStatus);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Function to update ticket status via AJAX
|
|
||||||
function updateTicketStatus(newStatus) {
|
function updateTicketStatus(newStatus) {
|
||||||
// Example AJAX request
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'update-ticket-status/{{ $ticket->id }}', // Replace with your route
|
url: 'update-ticket-status/{{ $ticket->id }}',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data: {
|
data: {
|
||||||
status: newStatus,
|
status: newStatus,
|
||||||
_token: '{{ csrf_token() }}'
|
_token: '{{ csrf_token() }}'
|
||||||
},
|
},
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
// Handle success response if needed
|
|
||||||
toastr.success(response.message);
|
toastr.success(response.message);
|
||||||
},
|
},
|
||||||
error: function(error) {
|
error: function(error) {
|
||||||
console.error('Error updating ticket status:', error);
|
console.error('Error updating ticket status:', error);
|
||||||
// Optionally handle error response
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@
|
||||||
Route::get('/inbox-setting', [InboxController::class, 'inboxSetting'])->name('inbox.setting');
|
Route::get('/inbox-setting', [InboxController::class, 'inboxSetting'])->name('inbox.setting');
|
||||||
Route::post('update-ticket-status/{ticketId}', [TicketController::class, 'updateStatus']);
|
Route::post('update-ticket-status/{ticketId}', [TicketController::class, 'updateStatus']);
|
||||||
Route::post('store-comment', [TicketController::class, 'storeComment']);
|
Route::post('store-comment', [TicketController::class, 'storeComment']);
|
||||||
|
Route::get('delete-comment/{commentId}', [TicketController::class, 'deleteComment']);
|
||||||
Route::post('store/response', [TicketController::class, 'storeResponse'])->name('store.response');
|
Route::post('store/response', [TicketController::class, 'storeResponse'])->name('store.response');
|
||||||
//Basic Setting Route
|
//Basic Setting Route
|
||||||
Route::post('inbox/basic-setting', [InboxController::class, 'basicSetting'])->name('inbox.basic.setting');
|
Route::post('inbox/basic-setting', [InboxController::class, 'basicSetting'])->name('inbox.basic.setting');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue