├── src ├── views │ ├── errors │ │ └── form_error.blade.php │ ├── partials │ │ └── common-header.blade.php │ ├── user_tickets.blade.php │ ├── create.blade.php │ ├── options.blade.php │ ├── layouts │ │ └── master.blade.php │ └── view.blade.php ├── Models │ ├── TicketComment.php │ ├── TicketOption.php │ └── Ticket.php ├── Traits │ └── UserTicket.php ├── migrations │ ├── 2018_10_23_115912_add_laraticket_admin_to_users.php │ ├── 2018_02_11_104552_create_ticket_comments_table.php │ ├── 2018_02_09_154337_create_ticket_options_table.php │ └── 2018_02_09_155151_create_tickets_table.php ├── LaraTicketServiceProvider.php ├── routes.php ├── Events │ ├── TicketClosed.php │ ├── TicketDeleted.php │ ├── TicketSubmitted.php │ └── TicketReplied.php ├── Controllers │ ├── TicketOptionController.php │ └── TicketController.php ├── config │ └── laraticket.php └── Notifications │ └── TicketNotification.php ├── composer.json └── README.md /src/views/errors/form_error.blade.php: -------------------------------------------------------------------------------- 1 | @if ($errors->any()) 2 |
3 | 8 |
9 | @endif -------------------------------------------------------------------------------- /src/Models/TicketComment.php: -------------------------------------------------------------------------------- 1 | belongsTo(Ticket::class); 11 | } 12 | 13 | public function user(){ 14 | return $this->belongsTo(config('laraticket.user_model_namespace')); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Models/TicketOption.php: -------------------------------------------------------------------------------- 1 | where('key', 'categories')->first(); 12 | $categories = $first ? explode(",", $first->values) : []; 13 | return $categories; 14 | } 15 | 16 | public function getPriorities(){ 17 | $first = $this->where('key', 'priorities')->first(); 18 | $priorities = $first ? explode(",", $first->values) : []; 19 | return $priorities; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Traits/UserTicket.php: -------------------------------------------------------------------------------- 1 | laraticket_admin; 10 | } 11 | 12 | public function tickets(){ 13 | return $this->hasMany(Ticket::class)->latest(); 14 | } 15 | 16 | public function countTickets($status="all"){ 17 | if ($status === "all"){ 18 | return $this->hasMany(Ticket::class)->count(); 19 | } 20 | return $this->hasMany(Ticket::class)->where('status', $status)->count(); 21 | } 22 | 23 | public function getTicketAdmins(){ 24 | return $this->where('laraticket_admin', true)->get(); 25 | } 26 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "sdkcodes/lara-ticket", 3 | "description" : "A laravel 5 package to handle 'support ticket'", 4 | "type" : "laravel-package", 5 | "keywords" : ["laravel support ticket", "Laravel ticket support", "ticket laravel", "laravel-5-package"], 6 | "require": { 7 | "laravel/framework": "^5.1", 8 | "illuminate/support": "^5.1" 9 | }, 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Sdkcodes", 14 | "email": "sdkcodes@gmail.com" 15 | } 16 | ], 17 | "autoload": { 18 | "psr-4": { 19 | "Sdkcodes\\LaraTicket\\": "src/" 20 | } 21 | }, 22 | "extra" : { 23 | "laravel" : { 24 | "providers" : [ 25 | "Sdkcodes\\LaraTicket\\LaraTicketServiceProvider" 26 | ] 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Models/Ticket.php: -------------------------------------------------------------------------------- 1 | count(); 15 | } 16 | 17 | public function comments(){ 18 | return $this->hasMany(TicketComment::class); 19 | } 20 | 21 | public function isOpen(){ 22 | return $this->status === "open"; 23 | } 24 | 25 | public function isClosed(){ 26 | return $this->status === "closed"; 27 | } 28 | 29 | public function owner(){ 30 | 31 | return $this->belongsTo(config('laraticket.user_model_namespace'), 'user_id'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/migrations/2018_10_23_115912_add_laraticket_admin_to_users.php: -------------------------------------------------------------------------------- 1 | tinyInteger('laraticket_admin')->default(0); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function down() 27 | { 28 | Schema::table('users', function (Blueprint $table) { 29 | // 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/LaraTicketServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 16 | __DIR__.'/config/laraticket.php' => config_path('laraticket.php'), 17 | ], 'config'); 18 | 19 | $this->mergeConfigFrom( 20 | __DIR__.'/config/laraticket.php', 'laraticket' 21 | ); 22 | 23 | $this->loadRoutesFrom(__DIR__.'/routes.php'); 24 | $this->loadMigrationsFrom(__DIR__.'/migrations'); 25 | $this->loadViewsFrom(__DIR__.'/views', 'laraticket'); 26 | 27 | $this->publishes([ 28 | __DIR__.'/views' => resource_path('views/vendor/laraticket'), 29 | ], 'views'); 30 | } 31 | 32 | public function register(){ 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /src/migrations/2018_02_11_104552_create_ticket_comments_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->integer('user_id')->unsigned(); 19 | $table->integer('ticket_id')->unsigned(); 20 | $table->text('body'); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | * 28 | * @return void 29 | */ 30 | public function down() 31 | { 32 | Schema::dropIfExists('ticket_comments'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/routes.php: -------------------------------------------------------------------------------- 1 | middleware('web', 'auth')->group(function(){ 4 | 5 | Route::get('admin/tickets', "TicketController@index"); 6 | Route::get('tickets/create', "TicketController@create"); 7 | Route::get('tickets/{status?}', "TicketController@index"); 8 | Route::get('tickets/show/{ticket}', "TicketController@show"); 9 | Route::get('tickets/{ticket}/update', "TicketController@changestatus"); 10 | Route::post('tickets/store', "TicketController@store"); 11 | Route::put('tickets/{ticket}', "TicketController@update"); 12 | Route::delete('tickets/{ticket}', "TicketController@delete"); 13 | 14 | Route::post('tickets/comments/store/{ticket}', "TicketController@reply"); 15 | 16 | Route::get('admin/tickets/options/settings', "TicketOptionController@options"); 17 | Route::post('admin/tickets/options/settings', "TicketOptionController@store"); 18 | Route::put('admin/tickets/options/settings', "TicketOptionController@update"); 19 | }); 20 | -------------------------------------------------------------------------------- /src/Events/TicketClosed.php: -------------------------------------------------------------------------------- 1 | ticket; 28 | 29 | } 30 | 31 | /** 32 | * Get the channels the event should broadcast on. 33 | * 34 | * @return \Illuminate\Broadcasting\Channel|array 35 | */ 36 | public function broadcastOn() 37 | { 38 | return new PrivateChannel('channel-name'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Events/TicketDeleted.php: -------------------------------------------------------------------------------- 1 | ticket; 28 | 29 | } 30 | 31 | /** 32 | * Get the channels the event should broadcast on. 33 | * 34 | * @return \Illuminate\Broadcasting\Channel|array 35 | */ 36 | public function broadcastOn() 37 | { 38 | return new PrivateChannel('channel-name'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Events/TicketSubmitted.php: -------------------------------------------------------------------------------- 1 | ticket = $ticket; 29 | } 30 | 31 | /** 32 | * Get the channels the event should broadcast on. 33 | * 34 | * @return \Illuminate\Broadcasting\Channel|array 35 | */ 36 | public function broadcastOn() 37 | { 38 | return new PrivateChannel('channel-name'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Events/TicketReplied.php: -------------------------------------------------------------------------------- 1 | comment = $comment; 28 | 29 | } 30 | 31 | /** 32 | * Get the channels the event should broadcast on. 33 | * 34 | * @return \Illuminate\Broadcasting\Channel|array 35 | */ 36 | public function broadcastOn() 37 | { 38 | return new PrivateChannel('channel-name'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Controllers/TicketOptionController.php: -------------------------------------------------------------------------------- 1 | categories){ 16 | $categories = array_filter($request->categories); 17 | TicketOption::updateOrCreate(['key' => 'categories'], ['values' => collect($categories)->implode(",")]); 18 | 19 | } 20 | elseif ($request->priorities) { 21 | $priorities = array_filter($request->priorities); 22 | TicketOption::updateOrCreate(['key' => 'priorities'], ['values' => collect($priorities)->implode(",")]); 23 | } 24 | 25 | return back()->with(['status' => 'success', 'message' => "Ticket options updated successfully"]); 26 | 27 | } 28 | 29 | public function options(TicketOption $option){ 30 | $data['categories'] = $option->getCategories(); 31 | $data['priorities'] = $option->getPriorities(); 32 | return view('laraticket::options', $data); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/migrations/2018_02_09_154337_create_ticket_options_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 19 | $table->string('key'); 20 | $table->string('values')->nullable(); 21 | // $table->string('categories')->default("one,two,three")->nullable(); 22 | // $table->string('priorities')->default("high,medium,low")->nullable(); 23 | $table->timestamps(); 24 | }); 25 | TicketOption::create(['key' => 'Categories']); 26 | TicketOption::create(['key' => 'Priorities']); 27 | } 28 | 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('ticket_options'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/migrations/2018_02_09_155151_create_tickets_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('slug')->unique(); 19 | $table->string('title')->nullable(); 20 | $table->longText('body')->nullable(); 21 | $table->integer('user_id')->unsigned(); 22 | $table->string('user_name')->nullable(); 23 | $table->text('replies')->nullable(); 24 | $table->string('category')->nullable(); 25 | $table->string('priority')->nullable(); 26 | $table->string('status')->comment('open, close')->default('open')->nullable(); 27 | $table->dateTime('date_closed')->nullable(); 28 | $table->timestamps(); 29 | }); 30 | } 31 | 32 | /** 33 | * Reverse the migrations. 34 | * 35 | * @return void 36 | */ 37 | public function down() 38 | { 39 | Schema::dropIfExists('tickets'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/views/partials/common-header.blade.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/config/laraticket.php: -------------------------------------------------------------------------------- 1 | 'laraticket::layouts.master', 5 | /* 6 | |-------------------------- 7 | | If you probably need to use a different template layout for the admin part of the ticket 8 | | you can make change this value to match 9 | |-------------------------- 10 | */ 11 | 'admin_layout' => 'laraticket::layouts.master', 12 | /* 13 | |------------------------------------------ 14 | | Set this value to yes to allow admin be able to create tickets too 15 | | ------------------------------------------ 16 | */ 17 | 'can_admin_create_ticket' => 'no', 18 | 19 | /** 20 | * In case your default users tablename is not users 21 | * You can change this value to reflect your table name 22 | * This will have an effect in migrations 23 | * 24 | * * 25 | * */ 26 | 27 | 'user_table_name' => 'users', 28 | 29 | /** 30 | * Change this value if your user model is not located in the laravel's default App directory 31 | * 32 | * */ 33 | 'user_model_namespace' => 'App\User', 34 | 35 | /**@internal Where should users be taken to when they click on navbar brand 36 | **/ 37 | 'return_url' => 'dashboard', 38 | /* 39 | |----------------------------------------------------------------------- 40 | |Use this to set the number of items returned when retrieving from database 41 | |For pagination purpose 42 | |----------------------------------------------------------------------- 43 | */ 44 | 'per_page' => 20, 45 | /* 46 | |-------------------------------------------------------- 47 | |If you have a customised pagination template to use, 48 | |set it's value here 49 | | 50 | */ 51 | 'pagination_view_name' => 'pagination::bootstrap-4' 52 | 53 | ]; -------------------------------------------------------------------------------- /src/Notifications/TicketNotification.php: -------------------------------------------------------------------------------- 1 | ticket = $ticket; 26 | $this->data = $data; 27 | } 28 | 29 | /** 30 | * Get the notification's delivery channels. 31 | * 32 | * @param mixed $notifiable 33 | * @return array 34 | */ 35 | public function via($notifiable) 36 | { 37 | return ['database']; 38 | } 39 | 40 | /** 41 | * Get the mail representation of the notification. 42 | * 43 | * @param mixed $notifiable 44 | * @return \Illuminate\Notifications\Messages\MailMessage 45 | */ 46 | public function toMail($notifiable) 47 | { 48 | return (new MailMessage) 49 | ->line('The introduction to the notification.') 50 | ->action('Notification Action', url('/')) 51 | ->line('Thank you for using our application!'); 52 | } 53 | 54 | /** 55 | * Get the array representation of the notification. 56 | * 57 | * @param mixed $notifiable 58 | * @return array 59 | */ 60 | public function toArray($notifiable) 61 | { 62 | return [ 63 | 'message' => $this->data['message'], 64 | 'action' => $this->data['url'] 65 | ]; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/views/user_tickets.blade.php: -------------------------------------------------------------------------------- 1 | @extends(config('laraticket.layout')) 2 | 3 | @section('content') 4 | @include('laraticket::partials.common-header') 5 |
6 | 11 |
12 |
13 |
Tickets 14 |
15 | Create new ticket 16 |
17 | 18 |
19 |
20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | @forelse($tickets as $ticket) 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | @empty 45 | @endforelse 46 | 47 |
SubjectStatusCreatedLast updatedPriorityOwnerCategory
{{ $ticket->title }}{{ $ticket->status }}{{ $ticket->created_at->diffForHumans() }}{{ $ticket->updated_at->diffForHumans() }}{{ $ticket->priority }}{{ $ticket->user_name }}{{ $ticket->category }}
48 |
49 | {{ $tickets->links() }} 50 |
51 |
52 |
53 |
54 | @endsection -------------------------------------------------------------------------------- /src/views/create.blade.php: -------------------------------------------------------------------------------- 1 | @extends(config('laraticket.layout')) 2 | @section('after_styles') 3 | 4 | 5 | @endsection 6 | @section('content') 7 | @include('laraticket::partials.common-header') 8 |
9 |
10 |
11 | @include('laraticket::errors.form_error') 12 |
13 | {{ csrf_field() }} 14 |
15 |
16 |
17 | 18 | 25 |
26 |
27 | 28 | 35 |
36 |
37 | 38 |
39 |
40 | 41 | 42 |
43 |
44 | 45 | 46 |
47 |
48 | 49 |
50 |
51 |
52 |
53 |
54 | 55 | @endsection 56 | @section('after_scripts') 57 | 58 | 67 | @endsection -------------------------------------------------------------------------------- /src/views/options.blade.php: -------------------------------------------------------------------------------- 1 | @extends(config('laraticket.layout')) 2 | 3 | @section('content') 4 | @include('laraticket::partials.common-header') 5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 |
13 |
14 | {{ csrf_field() }} 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | @forelse($categories as $category) 23 | 24 | 27 | 28 | @empty 29 | @endforelse 30 | 31 | 36 | 37 | 38 |
Categories
25 | 26 |
32 |
33 | 34 |
35 |
39 | 40 |
41 |
42 |
43 |
44 |
45 | {{ csrf_field() }} 46 |
47 | 48 | 49 | 50 | 51 | 52 | @forelse($priorities as $priority) 53 | 54 | 57 | 58 | @empty 59 | @endforelse 60 | 61 | 67 | 68 | 69 | 70 |
Priorities
55 | 56 |
62 |
63 | 64 |
65 | 66 |
71 | 72 |
73 |
74 |
75 |
76 | 77 |
78 |
79 |
80 |
81 |
82 | 83 | @endsection -------------------------------------------------------------------------------- /src/views/layouts/master.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ $title ?? 'Title' }} 5 | @yield('before_styles') 6 | 7 | 8 | @yield('after_styles') 9 | 10 | 11 | {{-- --}} 38 | @yield('content') 39 | @yield('before_scripts') 40 | 41 | 42 | 43 | @yield('after_scripts') 44 | 45 | -------------------------------------------------------------------------------- /src/views/view.blade.php: -------------------------------------------------------------------------------- 1 | @extends(config('laraticket.layout')) 2 | 3 | @section('content') 4 | @include('laraticket::partials.common-header') 5 |
6 |
7 |
8 |
9 | {{-- {{ $ticket->title }} --}} 10 |
11 | Create new ticket 12 |
13 | 14 |
15 |
16 |
17 | {{ $ticket->title }} 18 |
19 |
20 |
21 |
22 | 23 | Ticket by: {{ $ticket->user_name }} 24 |
25 | Status: {{ $ticket->status }} 26 |
27 | Category: {{ $ticket->category }} 28 |
29 | Priority: {{ $ticket->priority }} 30 |
31 | Opened: {{ $ticket->created_at->diffForHumans() }} 32 |
33 |
34 |
35 |
36 |

Description

37 | {!! $ticket->body !!} 38 |
39 |
40 |
41 |
42 | 43 |
44 | 45 |

Comments

46 |
47 | @forelse($ticket->comments as $comment) 48 |
  • {{ $comment->body }} 49 | {{ $comment->created_at->diffForHumans() }} 50 |
    51 | 52 | {{ $comment->user->name }} 53 | 54 |
  • 55 | @empty 56 | 57 | @endforelse 58 |
    59 |
    60 |
    61 | @if ($ticket->isOpen()) 62 | Close 63 | 64 | @elseif ($ticket->isClosed()) 65 | Reopen 66 | @endif 67 |
    68 |
    69 | 76 |
    77 |
    78 |
    79 | 99 | @endsection -------------------------------------------------------------------------------- /src/Controllers/TicketController.php: -------------------------------------------------------------------------------- 1 | perPage = config('laraticket.per_page'); 27 | } 28 | 29 | public function index($status="open"){ 30 | 31 | if (!auth()->user()->isTicketAdmin()){ 32 | $tickets = auth()->user()->tickets()->where('status', $status)->paginate($this->perPage); 33 | $data['title'] = $data['breadcrumb'] = "Tickets"; 34 | $data['tickets'] = $tickets; 35 | $data['open_count'] = auth()->user()->countTickets("open"); 36 | $data['closed_count'] = auth()->user()->countTickets("closed"); 37 | return view('laraticket::user_tickets', $data); 38 | } 39 | elseif (auth()->user()->isTicketAdmin()) { 40 | $tickets = Ticket::where('status', $status)->latest()->paginate($this->perPage); 41 | $data['title'] = $data['breadcrumb'] = "Tickets"; 42 | $data['tickets'] = $tickets; 43 | $data['open_count'] = Ticket::countTickets("open"); 44 | $data['closed_count'] = Ticket::countTickets("closed"); 45 | return view('laraticket::user_tickets', $data); 46 | } 47 | } 48 | 49 | public function show($slug){ 50 | $ticket = Ticket::where('slug', $slug)->firstOrFail(); 51 | $data['title'] = $ticket->title; 52 | $data['breadcrumb'] = "View Ticket"; 53 | $data['ticket'] = $ticket; 54 | return view('laraticket::view', $data); 55 | } 56 | 57 | public function create(){ 58 | $ticket_options = new TicketOption; 59 | $data['categories'] = $ticket_options->getCategories(); 60 | $data['priorities'] = $ticket_options->getPriorities(); 61 | $data['breadcrumb'] = $data['title'] = "Create new ticket"; 62 | 63 | return view('laraticket::create', $data); 64 | } 65 | public function store(Request $request){ 66 | $this->validate($request, 67 | ['title' => 'required|string|max:255', 68 | 'body' => 'required', 69 | 'priority' => 'required|string|max:30', 70 | 'category' => 'required|string|max:30']); 71 | $ticket = new Ticket; 72 | $ticket->user_id = auth()->id(); 73 | $ticket->user_name = auth()->user()->name; 74 | $ticket->title = $request->title; 75 | $ticket->slug = str_slug($request->title) . str_random(4); 76 | $ticket->body = $request->body; 77 | $ticket->priority = $request->priority; 78 | $ticket->category = $request->category; 79 | $ticket->status = "open"; 80 | $ticket->save(); 81 | $notification_data = ['message' => auth()->user()->name . " submitted a ticket", 82 | "url" => url("tickets/show/$ticket->slug")]; 83 | // Notification::send( (new User)->getTicketAdmins(), new TicketNotification($ticket, $notification_data)); 84 | event(new TicketSubmitted($ticket)); 85 | return redirect(url('tickets'))->with(['status' => 'success', 'message' => 'Ticket created, you will be notified when there\'s a reply']); 86 | 87 | } 88 | 89 | public function reply(Request $request, $id){ 90 | $this->validate($request, [ 91 | 'content' => 'required']); 92 | $ticket = Ticket::findOrFail($id); 93 | if (auth()->user()->isTicketAdmin() OR $ticket->user_id === auth()->id()){ 94 | $comment = new TicketComment; 95 | $comment->user_id = auth()->id(); 96 | $comment->ticket_id = $id; 97 | $comment->body = $request->content; 98 | $comment->save(); 99 | event(new TicketReplied($comment)); 100 | return back()->with(['status' => 'success', 'message' => "Comment submitted successfully"]); 101 | } 102 | else{ 103 | return back()->with(['status' => 'info', 'message' => "You do not have permission to update this ticket"]); 104 | } 105 | } 106 | 107 | public function changeStatus(Request $request, $id){ 108 | $this->validate($request, [ 109 | 'action' => 'required']); //set array rule to check if action is correct 110 | $ticket = Ticket::findOrFail($id); 111 | $action = $request->action; 112 | 113 | if (auth()->user()->isTicketAdmin() OR $ticket->user_id === auth()->id()){ 114 | switch ($action) { 115 | case 'open': 116 | $ticket->status = "open"; 117 | break; 118 | case 'close': 119 | $ticket->status = "closed"; 120 | $ticket->date_closed = Carbon::now(); 121 | break; 122 | default: 123 | $ticket->status = "close"; 124 | $ticket->date_closed = Carbon::now(); 125 | break; 126 | } 127 | $ticket->save(); 128 | event(new TicketClosed($ticket)); 129 | return back()->with(['status' => 'success', 'message' => "Ticket status updated successfully"]); 130 | } 131 | else{ 132 | return back()->with(['status' => 'success', 'message' => "You do not have permission to update this ticket"]); 133 | } 134 | return back(); 135 | } 136 | 137 | public function delete($ticket){ 138 | $ticket = Ticket::findOrFail($ticket); 139 | if (auth()->user()->isTicketAdmin() OR $ticket->user_id === auth()->id()){ 140 | event(new TicketDeleted($ticket)); 141 | $ticket->delete(); 142 | return redirect(url('tickets'))->with(['status' => 'info', 'message' => 'Ticket deleted']); 143 | } 144 | else{ 145 | return redirect(url('tickets'))->with(['status' => 'info', "message" => "You do not have permission to delete this ticket"]); 146 | } 147 | return redirect(url('tickets')); 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LaraTicket 2 | ## A Laravel 5 package to handle ticket support system within your project 3 | ### About 4 |
    5 | A Laravel 5 package to handle ticket support system within your project. LaraTicket integerates nicely with the existing users database and authentication system. You are also at liberty to configure a number of options to make it match your project more closely. 6 | You can use LaraTicket straight out of the box without extra efforts or configurations 7 | 8 | ### Features 9 | 1. Two main user roles (admin and user) 10 | 2. Users can create tickets, add comments, open and close tickets 11 | 3. Feature rich text editor with image and video embeding 12 | 4. Uses bootstrap 4 13 | 5. An easy to use admin panel 14 | 6. Custom views, so you do not need to write your own views 15 | 7. Custom predefined routes 16 | 17 | ### Installation 18 | - To install LaraTicket, in your existing project root directory, run 19 | `composer require sdkcodes/lara-ticket 0.0.3` 20 | - If you're using Laravel < 5.4, copy and add this line to the `providers` array in your `config/app.php` file 21 | `Sdkcodes\LaraTicket\LaraTicketServiceProvider::class,` 22 | 23 | ``` 24 | = 5.5 auto-discovers the package, so you do not need to add it manually. 37 | - Publish the views, config and migrations with the command 38 | `php artisan vendor:publish` 39 | - Add this trait to your user model `use UserTicket;` 40 | Don't forget to import the trait `use Sdkcodes\LaraTicket\Traits\UserTicket;` 41 | - ### Configuration 42 | ``` 43 | return[ 44 | 'layout' => 'layouts.front', 45 | /* 46 | |-------------------------- 47 | | If you probably need to use a different template layout for the admin part of the ticket 48 | | you can make change this value to match 49 | |-------------------------- 50 | */ 51 | 'admin_layout' => 'layouts.master', 52 | 53 | /** 54 | * In case your default users tablename is not users 55 | * You can change this value to reflect your table name 56 | * This will have an effect in migrations 57 | * 58 | * * 59 | * */ 60 | 61 | 'user_table_name' => 'users', 62 | 63 | /** 64 | * Change this value if your user model is not located in the laravel's default App directory 65 | * 66 | * */ 67 | 'user_model_namespace' => 'App\User', 68 | 69 | /**@internal Where should users be taken to when they click on navbar brand 70 | **/ 71 | 'return_url' => 'dashboard' 72 | ]; 73 | ``` 74 | You can change the configuration values as needed 75 | - Run `php artisan migrate ` to do the necessary migrations 76 | - LaraTicket alters your users table to add a new column to it `laraticket_admin`. 77 | - Change the value of this column to true (or 1) to set any user as a ticket admin 78 | - Visit your project url `/tickets` to begin usage. 79 | - Admin can (should) add categories and priorities as needed 80 | 81 | ### Events 82 | ` version 0.0.2 upwards` 83 | 84 | This package emits 4 different actions that you can listen for in your app to perform related and necessary actions. These events are: 85 | ``` 86 | * Sdkcodes\LaraTicket\TicketSubmitted ($ticket object becomes available to your listener) 87 | * Sdkcodes\LaraTicket\TicketReplied ($comment object becomes available to your listener) 88 | * Sdkcodes\LaraTicket\TicketClosed ($ticket object becomes available to your listener) 89 | * Sdkcodes\LaraTicket\TicketDeleted ($ticket object becomes available to your listener) 90 | ``` 91 | With your own listeners, you can decide to do different things like send notifications to concerned parties etc. 92 | 93 | E.g 94 | To listen for a `TicketSubmitted` event, add this to your `EventServiceProvider.php` 95 | ``` 96 | [ 116 | SendEmailVerificationNotification::class, 117 | ], 118 | 119 | TicketSubmitted::class => [ 120 | SendTicketSubmissionNotification::class 121 | ], 122 | 'Sdkcodes\LaraTicket\Events\TicketDeleted' => [ 123 | 'App\Listeners\SendTicketDeletionNotification' 124 | ], 125 | 'Sdkcodes\LaraTicket\Events\TicketReplied' => [ 126 | 'App\Listeners\SendTicketRepliedNotifcation' 127 | ], 128 | 'Sdkcodes\LaraTicket\Events\TicketClosed' => [ 129 | 'App\Listeners\SendTicketClosedNotifcation' 130 | ] 131 | ]; 132 | 133 | /** 134 | * Register any events for your application. 135 | * 136 | * @return void 137 | */ 138 | public function boot() 139 | { 140 | parent::boot(); 141 | 142 | } 143 | } 144 | 145 | ``` 146 | Your event listener code 147 | ``` 148 | ticket; 178 | Log::info("Ticket has been submitted, we can send mail now or anything else"); 179 | } 180 | } 181 | 182 | ``` 183 | ### Routes 184 | * Route::get('admin/tickets', "TicketController@index"); 185 | * Route::get('tickets/create', "TicketController@create"); 186 | * Route::get('tickets/{status?}', "TicketController@index"); 187 | * Route::get('tickets/show/{ticket}', "TicketController@show"); 188 | * Route::get('tickets/{ticket}/update', "TicketController@changestatus"); 189 | * Route::post('tickets/store', "TicketController@store"); 190 | * Route::put('tickets/{ticket}', "TicketController@update"); 191 | * Route::delete('tickets/{ticket}', "TicketController@delete"); 192 | * Route::post('tickets/comments/store/{ticket}', "TicketController@reply"); 193 | * Route::get('admin/tickets/options/settings', "TicketOptionController@options"); 194 | * Route::post('admin/tickets/options/settings', "TicketOptionController@store"); 195 | * Route::put('admin/tickets/options/settings', "TicketOptionController@update"); 196 | 197 | ### Licence 198 | LaraTicket is MIT Licensed. Use and enjoy as you like! --------------------------------------------------------------------------------