mirror of
https://github.com/HDInnovations/UNIT3D-Community-Edition.git
synced 2026-04-30 07:20:25 -05:00
add: helpdesk system beta
- multilingual needed - events need to be completed - creating ticket categories from staff dashboard needs to be done
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class CheckForStaleTickets extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'tickets:stale';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Checks for tickets open longer than 3 days';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
Ticket::checkForStaleTickets();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Comment;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class CommentCreated
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $comment;
|
||||
public $user;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param Comment $comment
|
||||
* @param User $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Comment $comment, User $user)
|
||||
{
|
||||
$this->comment = $comment;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class TicketAssigned
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $ticket;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class TicketClosed
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $ticket;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class TicketCreated
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $user;
|
||||
public $ticket;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
* @param User $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket, User $user)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class TicketWentStale
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $ticket;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the channels the event should broadcast on.
|
||||
*
|
||||
* @return \Illuminate\Broadcasting\Channel|array
|
||||
*/
|
||||
public function broadcastOn()
|
||||
{
|
||||
return new PrivateChannel('channel-name');
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use App\Achievements\UserMade100Comments;
|
||||
use App\Achievements\UserMade200Comments;
|
||||
use App\Achievements\UserMade300Comments;
|
||||
@@ -60,7 +61,7 @@ class CommentController extends Controller
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param $id
|
||||
*
|
||||
* @return Illuminate\Http\RedirectResponse
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function collection(Request $request, $id)
|
||||
{
|
||||
@@ -69,7 +70,7 @@ class CommentController extends Controller
|
||||
|
||||
if ($user->can_comment == 0) {
|
||||
return \redirect()->route('collection.show', ['id' => $collection->id])
|
||||
->withErros('Your Comment Rights Have Been Revoked!');
|
||||
->withErrors('Your Comment Rights Have Been Revoked!');
|
||||
}
|
||||
|
||||
$comment = new Comment();
|
||||
@@ -521,6 +522,42 @@ class CommentController extends Controller
|
||||
->withSuccess('Your Comment Has Been Added!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store A New Comment To A Request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \App\Models\TorrentRequest $id
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function ticket(Request $request, $id)
|
||||
{
|
||||
$ticket = Ticket::findOrFail($id);
|
||||
$user = $request->user();
|
||||
|
||||
$comment = new Comment();
|
||||
$comment->content = $request->input('content');
|
||||
$comment->anon = 0;
|
||||
$comment->user_id = $user->id;
|
||||
$comment->ticket_id = $ticket->id;
|
||||
|
||||
$v = \validator($comment->toArray(), [
|
||||
'content' => 'required',
|
||||
'user_id' => 'required',
|
||||
'ticket_id' => 'required',
|
||||
'anon' => 'required',
|
||||
]);
|
||||
|
||||
if ($v->fails()) {
|
||||
return \redirect()->route('request', ['id' => $tr->id])
|
||||
->withErrors($v->errors());
|
||||
}
|
||||
$comment->save();
|
||||
|
||||
return \redirect()->route('tickets.show', ['id' => $ticket->id])
|
||||
->withSuccess('Your Comment Has Been Added!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store A New Comment To A Torrent Via Quick Thanks.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\TicketAttachment;
|
||||
|
||||
class TicketAttachmentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Download a ticket attachment from storage.
|
||||
*
|
||||
* @param \App\Models\TicketAttachment $attachment
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
final public function download(TicketAttachment $attachment)
|
||||
{
|
||||
return \response()->download(\getcwd().'/files/attachments/attachments/'.$attachment->file_name)->deleteFileAfterSend(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Comment;
|
||||
use App\Events\TicketAssigned;
|
||||
use App\Events\TicketClosed;
|
||||
use App\Events\TicketCreated;
|
||||
use App\Models\Ticket;
|
||||
use App\Models\TicketCategory;
|
||||
use App\Models\TicketPriority;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\TicketAttachment;
|
||||
|
||||
class TicketController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
final public function index(Request $request): \Illuminate\Contracts\View\Factory|\Illuminate\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
{
|
||||
return \view('ticket.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
final public function create(): \Illuminate\Contracts\View\Factory|\Illuminate\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
{
|
||||
$categories = TicketCategory::all()->sortBy('position');
|
||||
$priorities = TicketPriority::all()->sortBy('position');
|
||||
|
||||
return view('ticket.create', [
|
||||
'categories' => $categories,
|
||||
'priorities' => $priorities
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
final public function store(Request $request): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
$ticket = new Ticket();
|
||||
$ticket->user_id = $user->id;
|
||||
$ticket->category_id = $request->input('category');
|
||||
$ticket->priority_id = $request->input('priority');
|
||||
$ticket->subject = $request->input('subject');
|
||||
$ticket->body = $request->input('body');
|
||||
|
||||
$v = \validator($ticket->toArray(), [
|
||||
'user_id' => 'required|exists:users,id',
|
||||
'category_id' => 'required|exists:ticket_categories,id',
|
||||
'priority_id' => 'required|exists:ticket_priorities,id',
|
||||
'subject' => 'required',
|
||||
'body' => 'required',
|
||||
]);
|
||||
|
||||
if ($v->fails()) {
|
||||
return \redirect()->route('tickets.create')
|
||||
->withInput()
|
||||
->withErrors($v->errors());
|
||||
}
|
||||
|
||||
$ticket->save();
|
||||
|
||||
return \redirect()->route('tickets.show', ['id' => $ticket->id])
|
||||
->withSuccess('Your Helpdesk Ticket Was Created Successfully!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
final public function show(Request $request, int $id): \Illuminate\Contracts\View\Factory|\Illuminate\View\View|\Illuminate\Contracts\Foundation\Application
|
||||
{
|
||||
$user = $request->user();
|
||||
$ticket = Ticket::with(['comments'])->findOrFail($id);
|
||||
|
||||
return view('ticket.show', [
|
||||
'user' => $user,
|
||||
'ticket' => $ticket,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
final public function edit(int $id): \Illuminate\Http\Response
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
final public function update(Request $request, int $id): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$ticket = Ticket::findOrFail($id);
|
||||
$user = $request->user();
|
||||
\abort_unless($user->group->is_modo || $user->id == $ticket->user_id, 403);
|
||||
|
||||
$ticket->category_id = $request->input('category');
|
||||
$ticket->priority_id = $request->input('priority');
|
||||
$ticket->subject = $request->input('subject');
|
||||
$ticket->body = $request->input('body');
|
||||
|
||||
$v = \validator($ticket->toArray(), [
|
||||
'user_id' => 'required|exists:users,id',
|
||||
'category_id' => 'required|exists:ticket_categories,id',
|
||||
'priority_id' => 'required|exists:ticket_priorities,id',
|
||||
'subject' => 'required',
|
||||
'body' => 'required',
|
||||
]);
|
||||
|
||||
if ($v->fails()) {
|
||||
return \redirect()->route('tickets.create')
|
||||
->withInput()
|
||||
->withErrors($v->errors());
|
||||
}
|
||||
|
||||
$ticket->save();
|
||||
|
||||
return \redirect()->route('tickets.show', ['id' => $ticket->id])
|
||||
->withSuccess('Your Helpdesk Ticket Was Updated Successfully!');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
final public function destroy(Request $request, int $id): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$ticket = Ticket::findOrFail($id);
|
||||
$user = $request->user();
|
||||
\abort_unless($user->group->is_modo || $user->id == $ticket->user_id, 403);
|
||||
|
||||
Comment::where('ticket_id', '=', $id)->delete();
|
||||
TicketAttachment::where('ticket_id', '=', $id)->delete();
|
||||
$ticket->delete();
|
||||
|
||||
return \redirect()->route('tickets.index')
|
||||
->withSuccess('Your Helpdesk Ticket Was Deleted Successfully!');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
final public function assign(Request $request, int $id): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$ticket = Ticket::findOrFail($id);
|
||||
$user = $request->user();
|
||||
\abort_unless($user->group->is_modo, 403);
|
||||
|
||||
$ticket->staff_id = $request->input('user_id');
|
||||
|
||||
$v = \validator($ticket->toArray(), [
|
||||
'user_id' => 'required|exists:users,id',
|
||||
]);
|
||||
|
||||
if ($v->fails()) {
|
||||
return \redirect()->route('tickets.show', ['id' => $ticket->id])
|
||||
->withErrors($v->errors());
|
||||
}
|
||||
|
||||
$ticket->save();
|
||||
|
||||
return \redirect()->route('tickets.show', ['id' => $ticket->id])
|
||||
->withSuccess('Helpdesk Ticket Was Assigned Successfully!');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
final public function unassign(Request $request, int $id): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$ticket = Ticket::findOrFail($id);
|
||||
$user = $request->user();
|
||||
\abort_unless($user->group->is_modo, 403);
|
||||
|
||||
$ticket->staff_id = null;
|
||||
$ticket->save();
|
||||
|
||||
return \redirect()->route('tickets.show', ['id' => $ticket->id])
|
||||
->withSuccess('Helpdesk Ticket Was Unassigned Successfully!');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
*
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
final public function close(Request $request, int $id): \Illuminate\Http\RedirectResponse
|
||||
{
|
||||
$ticket = Ticket::findOrFail($id);
|
||||
$user = $request->user();
|
||||
\abort_unless($user->group->is_modo || $user->id == $ticket->user_id, 403);
|
||||
|
||||
$ticket->closed_at = \now();
|
||||
$ticket->save();
|
||||
|
||||
return \redirect()->route('tickets.show', ['id' => $ticket->id])
|
||||
->withSuccess('Helpdesk Ticket Was Closed Successfully!');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use Livewire\WithFileUploads;
|
||||
use App\Models\TicketAttachment;
|
||||
use Livewire\Component;
|
||||
|
||||
class AttachmentUpload extends Component
|
||||
{
|
||||
use WithFileUploads;
|
||||
|
||||
public $user;
|
||||
public $ticket;
|
||||
public $attachment;
|
||||
public $storedImage;
|
||||
|
||||
public function mount(int $id)
|
||||
{
|
||||
$this->user = \auth()->user();
|
||||
$this->ticket = $id;
|
||||
}
|
||||
|
||||
public function upload()
|
||||
{
|
||||
$this->validate([
|
||||
'attachment' => 'image|max:1024', // 1MB Max
|
||||
]);
|
||||
|
||||
$fileName = \uniqid('', true).'.'.$this->attachment->getClientOriginalExtension();
|
||||
|
||||
$this->attachment->storeAs('attachments', $fileName, 'attachments');
|
||||
|
||||
$attachment = new TicketAttachment();
|
||||
$attachment->user_id = $this->user->id;
|
||||
$attachment->ticket_id = $this->ticket;
|
||||
$attachment->file_name = $fileName;
|
||||
$attachment->file_size = $this->attachment->getSize();
|
||||
$attachment->file_extension = $this->attachment->getMimeType();
|
||||
$attachment->save();
|
||||
|
||||
$this->dispatchBrowserEvent('success', ['type' => 'success', 'message' => 'Ticket Attachment Uploaded Successfully!']);
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return \view('livewire.attachment-upload');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Http\Livewire;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Livewire\Component;
|
||||
use Livewire\WithPagination;
|
||||
|
||||
class TicketSearch extends Component
|
||||
{
|
||||
use WithPagination;
|
||||
|
||||
public $user;
|
||||
public $perPage = 25;
|
||||
public $searchTerm = '';
|
||||
public $sortField = 'created_at';
|
||||
public $sortDirection = 'desc';
|
||||
|
||||
public function paginationView()
|
||||
{
|
||||
return 'vendor.pagination.livewire-pagination';
|
||||
}
|
||||
|
||||
public function updatingSearchTerm()
|
||||
{
|
||||
$this->resetPage();
|
||||
}
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->user = \auth()->user();
|
||||
}
|
||||
|
||||
public function getTicketsProperty()
|
||||
{
|
||||
if ($this->user->group->is_modo) {
|
||||
return Ticket::query()
|
||||
->with(['user', 'category', 'priority'])
|
||||
->when($this->searchTerm, function ($query) {
|
||||
return $query->where('subject', 'LIKE', '%'.$this->searchTerm.'%');
|
||||
})
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->paginate($this->perPage);
|
||||
} else {
|
||||
return Ticket::query()
|
||||
->with(['user', 'category', 'priority'])
|
||||
->where('user_id', '=', $this->user->id)
|
||||
->when($this->searchTerm, function ($query) {
|
||||
return $query->where('subject', 'LIKE', '%'.$this->searchTerm.'%');
|
||||
})
|
||||
->orderBy($this->sortField, $this->sortDirection)
|
||||
->paginate($this->perPage);
|
||||
}
|
||||
}
|
||||
|
||||
public function sortBy($field)
|
||||
{
|
||||
if ($this->sortField === $field) {
|
||||
$this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
|
||||
} else {
|
||||
$this->sortDirection = 'asc';
|
||||
}
|
||||
$this->sortField = $field;
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return \view('livewire.ticket-search', [
|
||||
'tickets' => $this->tickets
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Events\CommentCreated;
|
||||
use App\Notifications\StaffCommentCreated;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifyStaffCommentWasCreated
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param CommentCreated $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(CommentCreated $event)
|
||||
{
|
||||
$staff = User::where(['is_modo' => 1])->limit(1)->get();
|
||||
Notification::send($staff, new StaffCommentCreated($event->comment));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Events\TicketAssigned;
|
||||
use App\Notifications\StaffTicketAssigned;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifyStaffTicketWasAssigned
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param TicketAssigned $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(TicketAssigned $event)
|
||||
{
|
||||
$staff = User::where(['is_modo' => 1])->limit(1)->get();
|
||||
Notification::send($staff, new StaffTicketAssigned($event->ticket));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Events\TicketClosed;
|
||||
use App\Notifications\StaffTicketClosed;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
class NotifyStaffTicketWasClosed
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param TicketClosed $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle(TicketClosed $event)
|
||||
{
|
||||
$staff = User::where(['is_modo' => 1])->limit(1)->get();
|
||||
Notification::send($staff, new StaffTicketClosed($event->ticket));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Providers\TicketCreated;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class NotifyStaffTicketWasCreated
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param TicketCreated $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(TicketCreated $event)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Providers\CommentCreated;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class NotifyUserCommentWasCreated
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param CommentCreated $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(CommentCreated $event)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\TicketWentStale;
|
||||
use App\Notifications\UserTicketStale;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class NotifyUserTicketIsStale
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param TicketWentStale $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(TicketWentStale $event)
|
||||
{
|
||||
$event->ticket->user->notify(new UserTicketStale($event->ticket));
|
||||
$event->ticket->update(['reminded_at' => time()]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Providers\TicketAssigned;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class NotifyUserTicketWasAssigned
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param TicketAssigned $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(TicketAssigned $event)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Providers\TicketClosed;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class NotifyUserTicketWasClosed
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param TicketClosed $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(TicketClosed $event)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Providers\TicketCreated;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
||||
class NotifyUserTicketWasCreated
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param TicketCreated $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(TicketCreated $event)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
+35
-9
@@ -14,7 +14,6 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Helpers\Bbcode;
|
||||
use App\Helpers\Linkify;
|
||||
use App\Traits\Auditable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@@ -59,6 +58,19 @@ class Comment extends Model
|
||||
use HasFactory;
|
||||
use Auditable;
|
||||
|
||||
/**
|
||||
* Belongs To A User.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class)->withDefault([
|
||||
'username' => 'System',
|
||||
'id' => '1',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Belongs To A Torrent.
|
||||
*
|
||||
@@ -100,16 +112,13 @@ class Comment extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Belongs To A User.
|
||||
* Belongs To A Ticket.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
public function ticket()
|
||||
{
|
||||
return $this->belongsTo(User::class)->withDefault([
|
||||
'username' => 'System',
|
||||
'id' => '1',
|
||||
]);
|
||||
return $this->belongsTo(Ticket::class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,8 +141,25 @@ class Comment extends Model
|
||||
public function getContentHtml()
|
||||
{
|
||||
$bbcode = new Bbcode();
|
||||
$linkify = new Linkify();
|
||||
|
||||
return $bbcode->parse($linkify->linky($this->content), true);
|
||||
return $bbcode->parse($this->content, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nootify Staff There Is Stale Tickets.
|
||||
*
|
||||
* @param \App\Models\Ticket $ticket
|
||||
*/
|
||||
public static function checkForStale(Ticket $ticket)
|
||||
{
|
||||
if (empty($ticket->reminded_at) || strtotime($ticket->reminded_at) < strtotime('+ 3 days'))
|
||||
{
|
||||
$last_comment = $ticket->comments()->orderBy('id', 'desc')->first();
|
||||
|
||||
if (isset($last_comment->id) && ! $last_comment->user->is_modo && strtotime($last_comment->created_at) < strtotime('- 3 days'))
|
||||
{
|
||||
event(new TicketWentStale($last_comment->ticket));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Ticket extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $dates = [
|
||||
'closed_at',
|
||||
'reminded_at',
|
||||
];
|
||||
|
||||
public function scopeStatus($query, $status)
|
||||
{
|
||||
if($status === 'all')
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
else if($status === 'closed')
|
||||
{
|
||||
return $query->whereNotNull('closed_at');
|
||||
}
|
||||
else if($status === 'open')
|
||||
{
|
||||
return $query->whereNull('closed_at');
|
||||
}
|
||||
}
|
||||
|
||||
public function scopeStale($query)
|
||||
{
|
||||
return $query->with(['comments' => function ($query) {
|
||||
|
||||
$query->orderBy('id', 'desc');
|
||||
|
||||
}, 'comments.user'])
|
||||
->has('comments')
|
||||
->where('reminded_at', '<', strtotime('+ 3 days'))
|
||||
->orWhereNull('reminded_at');
|
||||
}
|
||||
|
||||
public static function checkForStaleTickets()
|
||||
{
|
||||
$open_tickets = self::status('open')
|
||||
->whereNotNull('staff_id')
|
||||
->get();
|
||||
|
||||
foreach($open_tickets as $open_ticket)
|
||||
{
|
||||
Comment::checkForStale($open_ticket);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Belongs To A User (Created).
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class)->withDefault([
|
||||
'username' => 'System',
|
||||
'id' => '1',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Belongs To A Staff User (Assigned).
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function staff()
|
||||
{
|
||||
return $this->belongsTo(User::class, 'staff_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Belongs To A Ticket Priority.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function priority()
|
||||
{
|
||||
return $this->belongsTo(TicketPriority::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Belongs To A Ticket Category.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function category()
|
||||
{
|
||||
return $this->belongsTo(TicketCategory::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has Many Ticket Attachments.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function attachments()
|
||||
{
|
||||
return $this->hasMany(TicketAttachment::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has Many Comments.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function comments()
|
||||
{
|
||||
return $this->hasMany(Comment::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TicketAttachment extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $appends = [
|
||||
'full_disk_path'
|
||||
];
|
||||
|
||||
public function getFullDiskPathAttribute()
|
||||
{
|
||||
return $this->disk_path . '' . $this->file_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Belongs To A User.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Belongs To A Ticket.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function ticket()
|
||||
{
|
||||
return $this->belongsTo(Ticket::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TicketCategory extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TicketPriority extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
}
|
||||
@@ -564,6 +564,16 @@ class User extends Authenticatable
|
||||
return $this->hasMany(Warning::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has Many Tickets.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function tickets()
|
||||
{
|
||||
return $this->hasMany(Ticket::class, 'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Users username as slug.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Comment;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class StaffCommentCreated extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private $comment;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param Comment $comment
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Comment $comment)
|
||||
{
|
||||
$this->comment = $comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
*
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('A comment was added (Staff)')
|
||||
->line('A comment was added')
|
||||
->action('View Ticket', route('tickets.show', ['id' => $this->comment->ticket->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class StaffTicketAssigned extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private $ticket;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('A ticket was assigned (Ticket # ' . $this->ticket->id . ')')
|
||||
->line('A ticket was assigned to ' . $this->ticket->staff->username)
|
||||
->action('View Ticket', route('tickets.show', ['id' => $this->ticket->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class StaffTicketClosed extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private $ticket;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
* @param Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('A ticket was closed (Staff)')
|
||||
->line('A ticket was closed')
|
||||
->action('View Ticket', route('tickets.show', ['id' => $this->ticket->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class StaffTicketCreated extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private $ticket;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('A ticket was created (Ticket # ' . $this->ticket->id . ')')
|
||||
->line('A ticket was created.')
|
||||
->action('View Ticket', route('tickets.show', ['id' => $this->ticket->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Comment;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class UserCommentCreated extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private $comment;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
* @param Comment $comment
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Comment $comment)
|
||||
{
|
||||
$this->comment = $comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('A comment was added (User)')
|
||||
->line('A comment was added')
|
||||
->action('View Ticket', route('tickets.show', ['id' => $this->comment->ticket->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class UserTicketAssigned extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private $ticket;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('Your ticket was assigned (Ticket # ' . $this->ticket->id . ')')
|
||||
->line('Your ticket was assigned to ' . $this->ticket->user->username)
|
||||
->action('View Ticket', route('tickets.show', ['id' => $this->ticket->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class UserTicketClosed extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private $ticket;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
* @param Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('Your ticket was closed (User)')
|
||||
->line('Your ticket was closed')
|
||||
->action('View Ticket', route('tickets.show', ['id' => $this->ticket->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class UserTicketCreated extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private $ticket;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->subject('Your ticket was created (Ticket # ' . $this->ticket->id . ')')
|
||||
->line('Your ticket was created.')
|
||||
->action('View Ticket', route('tickets.show', ['id' => $this->ticket->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Ticket;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class UserTicketStale extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
private $ticket;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param Ticket $ticket
|
||||
* @return mixed
|
||||
*/
|
||||
public function __construct(Ticket $ticket)
|
||||
{
|
||||
$this->ticket = $ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
return (new MailMessage)
|
||||
->cc($this->ticket->staff->email)
|
||||
->subject('Your ticket is still open')
|
||||
->line('This is a reminder that your ticket is still open')
|
||||
->action('View Ticket', route('tickets.show', ['id' => $this->ticket->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,31 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Listeners\LoginListener;
|
||||
use App\Listeners\LogoutListener;
|
||||
use Illuminate\Auth\Events\Failed;
|
||||
use Illuminate\Auth\Events\Login;
|
||||
use Illuminate\Auth\Events\Logout;
|
||||
use App\Listeners\AchievementUnlocked;
|
||||
use App\Listeners\FailedLoginListener;
|
||||
use Assada\Achievements\Event\Unlocked;
|
||||
use App\Listeners\PasswordProtectBackup;
|
||||
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||
use Spatie\Backup\Events\BackupZipWasCreated;
|
||||
use App\Events\TicketCreated;
|
||||
use App\Events\CommentCreated;
|
||||
use App\Listeners\NotifyUserTicketWasCreated;
|
||||
use App\Listeners\NotifyStaffTicketWasCreated;
|
||||
use App\Listeners\NotifyUserCommentWasCreated;
|
||||
use App\Listeners\NotifyStaffCommentWasCreated;
|
||||
use App\Events\TicketClosed;
|
||||
use App\Listeners\NotifyUserTicketWasClosed;
|
||||
use App\Listeners\NotifyStaffTicketWasClosed;
|
||||
use App\Events\TicketAssigned;
|
||||
use App\Listeners\NotifyUserTicketWasAssigned;
|
||||
use App\Listeners\NotifyStaffTicketWasAssigned;
|
||||
use App\Events\TicketWentStale;
|
||||
use App\Listeners\NotifyUserTicketIsStale;
|
||||
|
||||
class EventServiceProvider extends ServiceProvider
|
||||
{
|
||||
@@ -27,21 +47,47 @@ class EventServiceProvider extends ServiceProvider
|
||||
* @var array
|
||||
*/
|
||||
protected $listen = [
|
||||
// Auth System
|
||||
Logout::class => [
|
||||
\App\Listeners\LogoutListener::class,
|
||||
LogoutListener::class,
|
||||
],
|
||||
Login::class => [
|
||||
\App\Listeners\LoginListener::class,
|
||||
LoginListener::class,
|
||||
],
|
||||
Failed::class => [
|
||||
\App\Listeners\FailedLoginListener::class,
|
||||
FailedLoginListener::class,
|
||||
],
|
||||
'Assada\Achievements\Event\Unlocked' => [
|
||||
\App\Listeners\AchievementUnlocked::class,
|
||||
|
||||
// Achievements System
|
||||
Unlocked::class => [
|
||||
AchievementUnlocked::class,
|
||||
],
|
||||
|
||||
// Backups System
|
||||
BackupZipWasCreated::class => [
|
||||
\App\Listeners\PasswordProtectBackup::class,
|
||||
PasswordProtectBackup::class,
|
||||
],
|
||||
|
||||
// Ticket System
|
||||
TicketCreated::class => [
|
||||
NotifyUserTicketWasCreated::class,
|
||||
NotifyStaffTicketWasCreated::class,
|
||||
],
|
||||
CommentCreated::class => [
|
||||
NotifyUserCommentWasCreated::class,
|
||||
NotifyStaffCommentWasCreated::class,
|
||||
],
|
||||
TicketClosed::class => [
|
||||
NotifyUserTicketWasClosed::class,
|
||||
NotifyStaffTicketWasClosed::class,
|
||||
],
|
||||
TicketAssigned::class => [
|
||||
NotifyUserTicketWasAssigned::class,
|
||||
NotifyStaffTicketWasAssigned::class,
|
||||
],
|
||||
TicketWentStale::class => [
|
||||
NotifyUserTicketIsStale::class
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -51,7 +97,6 @@ class EventServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +80,11 @@ return [
|
||||
'root' => public_path('files/subtitles'),
|
||||
],
|
||||
|
||||
'attachments' => [
|
||||
'driver' => 'local',
|
||||
'root' => public_path('files/attachments'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateTicketsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('tickets', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->integer('user_id')->index();
|
||||
$table->integer('category_id')->index();
|
||||
$table->integer('priority_id')->index();
|
||||
$table->integer('staff_id')->nullable()->index();
|
||||
$table->string('subject');
|
||||
$table->longText('body');
|
||||
$table->timestamp('closed_at')->nullable();
|
||||
$table->timestamp('reminded_at')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('tickets');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateTicketCategoriesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('ticket_categories', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->integer('position');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('ticket_categories');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateTicketPrioritiesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('ticket_priorities', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->integer('position');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('ticket_priorities');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateTicketAttachmentsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('ticket_attachments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->integer('user_id')->index();
|
||||
$table->integer('ticket_id')->index();
|
||||
$table->string('file_name')->nullable();
|
||||
$table->string('file_size')->nullable();
|
||||
$table->string('file_extension')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('ticket_attachments');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddTicketIdToCommentsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('comments', function (Blueprint $table) {
|
||||
$table->integer('ticket_id')->nullable()->index()->after('playlist_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('comments', function (Blueprint $table) {
|
||||
$table->dropColumn('ticket_id');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,8 @@ class DatabaseSeeder extends Seeder
|
||||
BotsTableSeeder::class,
|
||||
MediaLanguagesSeeder::class,
|
||||
ResolutionsTableSeeder::class,
|
||||
TicketCategoriesTableSeeder::class,
|
||||
TicketPrioritiesTableSeeder::class
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\TicketCategory;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class TicketCategoriesTableSeeder extends Seeder
|
||||
{
|
||||
private $categories;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->categories = $this->getTicketCategories();
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto generated seed file.
|
||||
*
|
||||
* @return voids
|
||||
*/
|
||||
final public function run(): void
|
||||
{
|
||||
foreach ($this->categories as $category) {
|
||||
TicketCategory::updateOrCreate($category);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
private function getTicketCategories(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'name' => 'Accounts',
|
||||
'position' => 0
|
||||
],
|
||||
[
|
||||
'name' => 'Appeals',
|
||||
'position' => 1
|
||||
],
|
||||
[
|
||||
'name' => 'Forums',
|
||||
'position' => 2
|
||||
],
|
||||
[
|
||||
'name' => 'Requests',
|
||||
'position' => 3
|
||||
],
|
||||
[
|
||||
'name' => 'Subtitles',
|
||||
'position' => 4
|
||||
],
|
||||
[
|
||||
'name' => 'Torrents',
|
||||
'position' => 5
|
||||
],
|
||||
[
|
||||
'name' => 'MediaHub',
|
||||
'position' => 6
|
||||
],
|
||||
[
|
||||
'name' => 'Technical',
|
||||
'position' => 7
|
||||
],
|
||||
[
|
||||
'name' => 'Playlists',
|
||||
'position' => 8
|
||||
],
|
||||
[
|
||||
'name' => 'Bugs',
|
||||
'position' => 9
|
||||
],
|
||||
[
|
||||
'name' => 'Other',
|
||||
'position' => 10
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/**
|
||||
* NOTICE OF LICENSE.
|
||||
*
|
||||
* UNIT3D Community Edition is open-sourced software licensed under the GNU Affero General Public License v3.0
|
||||
* The details is bundled with this project in the file LICENSE.txt.
|
||||
*
|
||||
* @project UNIT3D Community Edition
|
||||
*
|
||||
* @author HDVinnie <hdinnovations@protonmail.com>
|
||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0
|
||||
*/
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\TicketPriority;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class TicketPrioritiesTableSeeder extends Seeder
|
||||
{
|
||||
private $priorities;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->priorities = $this->getTicketPriorities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto generated seed file.
|
||||
*
|
||||
* @return voids
|
||||
*/
|
||||
final public function run(): void
|
||||
{
|
||||
foreach ($this->priorities as $priority) {
|
||||
TicketPriority::updateOrCreate($priority);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
private function getTicketPriorities(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
'name' => 'Low',
|
||||
'position' => 0
|
||||
],
|
||||
[
|
||||
'name' => 'Medium',
|
||||
'position' => 1
|
||||
],
|
||||
[
|
||||
'name' => 'High',
|
||||
'position' => 2
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -377,10 +377,10 @@ a:focus {
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 24px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
border-top: .5px solid #797979;
|
||||
}
|
||||
|
||||
[role='button'] {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<div>
|
||||
<input type="file" wire:model="attachment">
|
||||
|
||||
@error('attachment') <span class="error">{{ $message }}</span> @enderror
|
||||
|
||||
<button wire:click="upload">Save Attachment</button>
|
||||
</div>
|
||||
@@ -275,16 +275,6 @@
|
||||
<a role="menuitem" tabindex="-1"
|
||||
href="{{ route('download', ['id' => $bookmark->id]) }}">@lang('common.download') @lang('torrent.torrent')</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<form role="menuitem" tabindex="-1"action="{{ route('bookmarks.destroy', ['id' => $bookmark->id]) }}" method="POST"
|
||||
style="display: inline;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-xxs btn-danger">
|
||||
@lang('torrent.delete-bookmark')
|
||||
</button>
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
<div>
|
||||
<div class="mb-10 form-inline pull-left">
|
||||
<a href="{{ route('tickets.create') }}" class="btn btn-success"><i class="fas fa-plus"></i> New Ticket</a>
|
||||
</div>
|
||||
<div class="mb-10 form-inline pull-right">
|
||||
<div class="form-group">
|
||||
@lang('common.quantity')
|
||||
<select wire:model="perPage" class="form-control">
|
||||
<option>25</option>
|
||||
<option>50</option>
|
||||
<option>100</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" wire:model="searchTerm" class="form-control" style="width: 275px;" placeholder="Subject"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body no-padding">
|
||||
<table class="table vertical-align table-hover">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
<div sortable wire:click="sortBy('id')" :direction="$sortField === 'id' ? $sortDirection : null" role="button">
|
||||
#
|
||||
@include('livewire.includes._sort-icon', ['field' => 'id'])
|
||||
</div>
|
||||
</th>
|
||||
<th>
|
||||
<div sortable wire:click="sortBy('subject')" :direction="$sortField === 'subject' ? $sortDirection : null" role="button">
|
||||
Subject
|
||||
@include('livewire.includes._sort-icon', ['field' => 'subject'])
|
||||
</div>
|
||||
</th>
|
||||
<th>
|
||||
<div sortable wire:click="sortBy('priority_id')" :direction="$sortField === 'priority_id' ? $sortDirection : null" role="button">
|
||||
Priority
|
||||
@include('livewire.includes._sort-icon', ['field' => 'priority_id'])
|
||||
</div>
|
||||
</th>
|
||||
<th>
|
||||
<div sortable wire:click="sortBy('user_id')" :direction="$sortField === 'user_id' ? $sortDirection : null" role="button">
|
||||
@lang('common.username')
|
||||
@include('livewire.includes._sort-icon', ['field' => 'user_id'])
|
||||
</div>
|
||||
</th>
|
||||
<th class="hidden-sm hidden-xs">
|
||||
<div sortable wire:click="sortBy('closed_at')" :direction="$sortField === 'closed_at' ? $sortDirection : null"
|
||||
role="button">
|
||||
Status
|
||||
@include('livewire.includes._sort-icon', ['field' => 'closed_at'])
|
||||
</div>
|
||||
</th>
|
||||
<th class="hidden-sm hidden-xs">
|
||||
<div sortable wire:click="sortBy('staff_id')" :direction="$sortField === 'staff_id' ? $sortDirection : null"
|
||||
role="button">
|
||||
Assigned
|
||||
@include('livewire.includes._sort-icon', ['field' => 'staff_id'])
|
||||
</div>
|
||||
</th>
|
||||
<th class="hidden-sm hidden-xs">
|
||||
<div sortable wire:click="sortBy('created_at')" :direction="$sortField === 'created_at' ? $sortDirection : null"
|
||||
role="button">
|
||||
Created
|
||||
@include('livewire.includes._sort-icon', ['field' => 'created_at'])
|
||||
</div>
|
||||
</th>
|
||||
<th>@lang('common.action')</th>
|
||||
</tr>
|
||||
@foreach ($tickets as $ticket)
|
||||
<tr>
|
||||
<td>
|
||||
<span class="badge-user text-bold">
|
||||
{{ $ticket->id }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge-user text-bold">
|
||||
<a href="{{ route('tickets.show', ['id' => $ticket->id]) }}">{{ $ticket->subject }}</a>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge-user text-bold">
|
||||
@if($ticket->priority->name === 'Low')
|
||||
<i class="fas fa-circle text-yellow"></i>
|
||||
@elseif ($ticket->priority->name === 'Medium')
|
||||
<i class="fas fa-circle text-orange"></i>
|
||||
@elseif ($ticket->priority->name === 'High')
|
||||
<i class="fas fa-circle text-red"></i>
|
||||
@endif
|
||||
{{ $ticket->priority->name }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge-user text-bold">
|
||||
{{ $ticket->user->username }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge-user text-bold">
|
||||
@if($ticket->closed_at)
|
||||
<i class="fas fa-circle text-danger"></i> Closed
|
||||
@else
|
||||
<i class="fas fa-circle text-success"></i> Open
|
||||
@endif
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge-user text-bold">
|
||||
{{ $ticket->staff->username ?? 'Unassigned' }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge-user text-bold">
|
||||
{{ $ticket->created_at->diffForHumans() }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="dropdown">
|
||||
<a class="dropdown-toggle btn btn-default btn-xs" data-toggle="dropdown" href="#" aria-expanded="true">
|
||||
@lang('common.actions')
|
||||
<i class="fas fa-caret-circle-right"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li role="presentation">
|
||||
<a role="menuitem" tabindex="-1" target="_blank"
|
||||
href="{{ route('tickets.show', ['id' => $ticket->id]) }}">View</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a role="menuitem" tabindex="-1"
|
||||
href="{{ route('tickets.close', ['id' => $ticket->id]) }}">Close</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@if (! $tickets->count())
|
||||
<div class="margin-10">
|
||||
@lang('common.no-result')
|
||||
</div>
|
||||
@endif
|
||||
<br>
|
||||
<div class="text-center">
|
||||
{{ $tickets->links() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -11,10 +11,9 @@
|
||||
<span class="hoe-sidebar-toggle"><a href="#"></a></span>
|
||||
<ul class="left-navbar">
|
||||
<li class="dropdown hoe-rheader-submenu message-notification left-min-30">
|
||||
@php $pm = DB::table('private_messages')->where('receiver_id', '=', auth()->user()->id)->where('read',
|
||||
'=', '0')->count(); @endphp
|
||||
@php $pm = DB::table('private_messages')->where('receiver_id', '=', auth()->user()->id)->where('read', '=', '0')->count(); @endphp
|
||||
<a href="{{ route('inbox') }}" class="dropdown-toggle icon-circle">
|
||||
<i class="{{ config('other.font-awesome') }} fa-envelope text-blue"></i>
|
||||
<i class="{{ config('other.font-awesome') }} fa-envelope"></i>
|
||||
@if ($pm > 0)
|
||||
<div class="notify"><span class="heartbit"></span><span class="point fa-beat"></span></div>
|
||||
@endif
|
||||
@@ -31,15 +30,27 @@
|
||||
</li>
|
||||
|
||||
<li class="dropdown hoe-rheader-submenu message-notification left-min-30">
|
||||
<a href="{{ route('achievements.index') }}" class="icon-circle">
|
||||
<i class="{{ config('other.font-awesome') }} fa-trophy text-gold"></i>
|
||||
<a href="{{ route('articles.index') }}" class="icon-circle">
|
||||
<i class="{{ config('other.font-awesome') }} fa-newspaper"></i>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="dropdown hoe-rheader-submenu message-notification left-min-65">
|
||||
<a href="{{ route('tickets.index') }}" class="icon-circle">
|
||||
<i class="{{ config('other.font-awesome') }} fa-life-ring"></i>
|
||||
@if (auth()->user()->group->is_modo)
|
||||
@php $tickets = DB::table('tickets')->whereNull('staff_id')->whereNull('closed_at')->count(); @endphp
|
||||
@if ($tickets > 0)
|
||||
<div class="notify"><span class="heartbit"></span><span class="point fa-beat"></span></div>
|
||||
@endif
|
||||
@endif
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@if (auth()->user()->group->is_modo)
|
||||
<li class="dropdown hoe-rheader-submenu message-notification left-min-65">
|
||||
<a href="{{ route('staff.moderation.index') }}" class="icon-circle">
|
||||
<i class="{{ config('other.font-awesome') }} fa-tasks text-red"></i>
|
||||
<i class="{{ config('other.font-awesome') }} fa-tasks"></i>
|
||||
@php $modder = DB::table('torrents')->where('status', '=', '0')->count(); @endphp
|
||||
@if ($modder > 0)
|
||||
<div class="notify"><span class="heartbit"></span><span class="point fa-beat"></span></div>
|
||||
@@ -83,6 +94,11 @@
|
||||
<i class="{{ config('other.font-awesome') }} fa-shield-alt"></i> @lang('user.my-security')
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('achievements.index') }}">
|
||||
<i class="{{ config('other.font-awesome') }} fa-trophy-alt"></i> My @lang('user.achievements')
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('user_uploads', ['username' => auth()->user()->username]) }}">
|
||||
<i class="{{ config('other.font-awesome') }} fa-upload"></i> @lang('user.my-uploads')
|
||||
@@ -112,6 +128,5 @@
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</div>
|
||||
</header>
|
||||
</header>
|
||||
@@ -1,6 +1,4 @@
|
||||
@php
|
||||
echo '<?xml version="1.0" encoding="UTF-8" ?>'
|
||||
@endphp
|
||||
{!! '<?xml version="1.0" encoding="UTF-8" ?>' !!}
|
||||
<rss version="2.0"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom"
|
||||
xmlns:content="http://purl.org/rss/1.0/modules/content/"
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('title')
|
||||
<title>Helpdesk - {{ config('other.title') }}</title>
|
||||
@endsection
|
||||
|
||||
@section('breadcrumb')
|
||||
<li>
|
||||
<a href="{{ route('tickets.index') }}" itemprop="url" class="l-breadcrumb-item-link">
|
||||
<span itemprop="title" class="l-breadcrumb-item-link-title">Helpdesk</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('tickets.create') }}" itemprop="url" class="l-breadcrumb-item-link">
|
||||
<span itemprop="title" class="l-breadcrumb-item-link-title">Create Ticket</span>
|
||||
</a>
|
||||
</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-10 col-sm-10 col-md-offset-1">
|
||||
<div class="panel panel-chat shoutbox">
|
||||
<div class="panel-heading"><i class="fas fa-plus"></i> Create Ticket</div>
|
||||
<div class="panel-body">
|
||||
@if(session('errors'))
|
||||
<div class="alert alert-danger">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h6><b>Please fix the following error(s) and try again:</b></h6>
|
||||
<ul class="mb-0">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
<form action="{{ route('tickets.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="form-row">
|
||||
<div class="form-group col-6">
|
||||
<label for="category">Category <span class="text-danger small">*</span></label>
|
||||
<select name="category" id="category" class="form-control">
|
||||
@foreach($categories as $category)
|
||||
<option value="{{ $category->id }}">{{ $category->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-6">
|
||||
<label for="priority">Priority <span class="text-danger small">*</span></label>
|
||||
<select name="priority" id="priority" class="form-control">
|
||||
@foreach($priorities as $priority)
|
||||
<option value="{{ $priority->id }}">{{ $priority->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-12">
|
||||
<label for="subject">Subject <span class="text-danger small">*</span></label>
|
||||
<input type="text" class="form-control" name="subject" id="subject" placeholder="Enter subject here..." autocomplete="off">
|
||||
</div>
|
||||
<div class="form-group col-12">
|
||||
<label for="body">Body <span class="text-danger small">*</span></label>
|
||||
<textarea name="body" id="body" cols="30" rows="3" class="form-control" placeholder="Enter body here..."></textarea>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button type="submit" class="btn btn-success btn-md"><i class="fas fa-save"></i> Submit Ticket</button>
|
||||
<button type="reset" class="btn btn-danger btn-md"><i class="fas fa-eraser"></i> Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,35 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('title')
|
||||
<title>Helpdesk - {{ config('other.title') }}</title>
|
||||
@endsection
|
||||
|
||||
@section('breadcrumb')
|
||||
<li>
|
||||
<a href="{{ route('tickets.index') }}" itemprop="url" class="l-breadcrumb-item-link">
|
||||
<span itemprop="title" class="l-breadcrumb-item-link-title">Helpdesk</span>
|
||||
</a>
|
||||
</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<style>
|
||||
td {
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
</style>
|
||||
<div class="container">
|
||||
<div class="block">
|
||||
<div class="header gradient silver">
|
||||
<div class="inner_content">
|
||||
<div class="page-title">
|
||||
<h1 style="margin: 0;">Helpdesk</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box container">
|
||||
@livewire('ticket-search')
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,218 @@
|
||||
@extends('layout.default')
|
||||
|
||||
@section('title')
|
||||
<title>Helpdesk - {{ config('other.title') }}</title>
|
||||
@endsection
|
||||
|
||||
@section('breadcrumb')
|
||||
<li>
|
||||
<a href="{{ route('tickets.index') }}" itemprop="url" class="l-breadcrumb-item-link">
|
||||
<span itemprop="title" class="l-breadcrumb-item-link-title">Helpdesk</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{{ route('tickets.show', ['id' => $ticket->id]) }}" itemprop="url" class="l-breadcrumb-item-link">
|
||||
<span itemprop="title" class="l-breadcrumb-item-link-title">Ticket #{{ $ticket->id }}</span>
|
||||
</a>
|
||||
</li>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div class="container well">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-12">
|
||||
@if(session('errors'))
|
||||
<div class="alert alert-danger fade show">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h6><b>Please fix the following error(s) and try again:</b></h6>
|
||||
<ul class="mb-0">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="panel panel-chat shoutbox">
|
||||
<div class="panel-heading">Ticket <i class="fas fa-hashtag"></i> {{ $ticket->id }}</div>
|
||||
<div class="panel-body">
|
||||
<span class="float-right small text-right">
|
||||
<i class="far fa-user"></i> Opened By: {{ $ticket->user->username }}
|
||||
<i class="far fa-clock"></i> {{ $ticket->created_at->format('m/d/Y') }}
|
||||
<div class="form-inline">
|
||||
<div class="form-group">
|
||||
@if(empty($ticket->closed_at))
|
||||
<form style="display: inline;" role="form" method="POST" action="{{ route('tickets.close', ['id' => $ticket->id]) }}">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-xs btn-warning"><i class="fas fa-times"></i> Close</button>
|
||||
</form>
|
||||
@endif
|
||||
@if(!empty($ticket->closed_at))
|
||||
<span style="display: inline;" class="text-danger">Closed {{ $ticket->closed_at->format('m/d/Y') }}</span>
|
||||
@endif
|
||||
<form style="display: inline;" role="form" method="POST" action="{{ route('tickets.destroy', ['id' => $ticket->id]) }}">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn btn-xs btn-danger"><i class="fas fa-times"></i> Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
@if($user->group->is_modo)
|
||||
<div class="btn-group" role="group">
|
||||
<div class="mb-10 form-inline pull-right">
|
||||
<div class="form-group">
|
||||
@if(empty($ticket->staff_id))
|
||||
<form role="form" method="POST" action="{{ route('tickets.assign', ['id' => $ticket->id]) }}">
|
||||
@csrf
|
||||
<select name="user_id" class="form-control">
|
||||
@foreach(App\Models\User::select(['id', 'username'])->whereIn('group_id', [10, 6, 4])->get() as $user)
|
||||
<option value="{{ $user->id }}">{{ $user->username }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<button type="submit" class="btn btn-sm btn-warning">Assign</button>
|
||||
</form>
|
||||
@else
|
||||
<form role="form" method="POST" action="{{ route('tickets.unassign', ['id' => $ticket->id]) }}">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-sm btn-warning">Unassign</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
<hr style="margin: 8px">
|
||||
<div class="row">
|
||||
@if(isset($ticket->staff_id))
|
||||
<div class="col-md-3">
|
||||
<label for=""><b>Assigned Staff</b></label><br>
|
||||
<i class="far fa-user"></i> {{ $ticket->staff->username }}
|
||||
</div>
|
||||
@endif
|
||||
<div class="col-md-4">
|
||||
<label for=""><b>Category</b></label><br>
|
||||
{{ $ticket->category->name }}
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label for=""><b>Priority</b></label><br>
|
||||
@if($ticket->priority->name === 'Low')
|
||||
<i class="fas fa-circle text-yellow"></i>
|
||||
@elseif ($ticket->priority->name === 'Medium')
|
||||
<i class="fas fa-circle text-orange"></i>
|
||||
@elseif ($ticket->priority->name === 'High')
|
||||
<i class="fas fa-circle text-red"></i>
|
||||
@endif
|
||||
{{ $ticket->priority->name }}
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for=""><b>Subject</b></label><br>
|
||||
{{ $ticket->subject }}
|
||||
</div>
|
||||
</div>
|
||||
<hr style="margin: 8px">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<label for=""><b>Description</b></label><br>
|
||||
{{ $ticket->body }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="panel panel-chat shoutbox">
|
||||
<div class="panel-heading"><i class="fas fa-file-pdf"></i> Attachments</div>
|
||||
<div class="panel-body">
|
||||
@livewire('attachment-upload', ['id' => $ticket->id])
|
||||
@if(count($ticket->attachments))
|
||||
<div class="table-responsive">
|
||||
<table class="table" style="margin-bottom:0">
|
||||
<tbody>
|
||||
@foreach($ticket->attachments as $attachment)
|
||||
<tr>
|
||||
<td style="width:100px">
|
||||
<form action="{{ route('tickets.attachment.download', $attachment) }}" method="POST">
|
||||
@csrf
|
||||
<button class="btn btn-success btn-sm">Download</button>
|
||||
</form>
|
||||
</td>
|
||||
<td>{{ $attachment->file_name }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
No attachments found
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 col-sm-12">
|
||||
<div class="panel panel-chat shoutbox">
|
||||
<div class="panel-heading">
|
||||
<h4>
|
||||
<i class="{{ config('other.font-awesome') }} fa-comment"></i> @lang('common.comments')
|
||||
</h4>
|
||||
</div>
|
||||
<div class="panel-body no-padding">
|
||||
<ul class="media-list comments-list">
|
||||
@if (count($ticket->comments) == 0)
|
||||
<div class="text-center">
|
||||
<h4 class="text-bold text-danger">
|
||||
<i class="{{ config('other.font-awesome') }} fa-frown"></i> @lang('common.no-comments')!
|
||||
</h4>
|
||||
</div>
|
||||
@else
|
||||
@foreach ($ticket->comments as $comment)
|
||||
<li class="media" style="border-left: 5px solid rgb(1,188,140);">
|
||||
<div class="media-body">
|
||||
<a href="{{ route('users.show', ['username' => $comment->user->username]) }}"
|
||||
class="pull-left" style="padding-right: 10px;">
|
||||
@if ($comment->user->image != null)
|
||||
<img src="{{ url('files/img/' . $comment->user->image) }}"
|
||||
alt="{{ $comment->user->username }}" class="img-avatar-48"></a>
|
||||
@else
|
||||
<img src="{{ url('img/profile.png') }}" alt="{{ $comment->user->username }}"
|
||||
class="img-avatar-48"></a>
|
||||
@endif
|
||||
<strong>
|
||||
<a href="{{ route('users.show', ['username' => $comment->user->username]) }}"
|
||||
style="color:{{ $comment->user->group->color }};">
|
||||
<span><i class="{{ $comment->user->group->icon }}"></i> {{ $comment->user->username }}</span>
|
||||
</a>
|
||||
</strong>
|
||||
<span class="text-muted"><small><em>{{ $comment->created_at->toDayDateTimeString() }} ({{ $comment->created_at->diffForHumans() }})</em></small></span>
|
||||
<div class="pt-5">
|
||||
@joypixels($comment->getContentHtml())
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endforeach
|
||||
@endif
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<form role="form" method="POST" action="{{ route('comment_ticket', ['id' => $ticket->id]) }}">
|
||||
@csrf
|
||||
<div class="form-group">
|
||||
<label for="content">@lang('common.your-comment'):</label>
|
||||
<textarea id="content" name="content" cols="30" rows="5" class="form-control"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">@lang('common.submit')</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
+18
-3
@@ -178,6 +178,7 @@ Route::group(['middleware' => 'language'], function () {
|
||||
Route::post('/request/{id}', 'CommentController@request')->name('comment_request');
|
||||
Route::post('/playlist/{id}', 'CommentController@playlist')->name('comment_playlist');
|
||||
Route::post('/collection/{id}', 'CommentController@collection')->name('comment_collection');
|
||||
Route::post('/ticket/{id}', 'CommentController@ticket')->name('comment_ticket');
|
||||
Route::post('/edit/{comment_id}', 'CommentController@editComment')->name('comment_edit');
|
||||
Route::get('/delete/{comment_id}', 'CommentController@deleteComment')->name('comment_delete');
|
||||
});
|
||||
@@ -245,7 +246,6 @@ Route::group(['middleware' => 'language'], function () {
|
||||
});
|
||||
|
||||
Route::group(['prefix' => 'torrents'], function () {
|
||||
Route::get('/feedizeTorrents/{type}', 'TorrentController@feedize')->name('feedizeTorrents')->middleware('modo');
|
||||
Route::get('/filter', 'TorrentController@faceted');
|
||||
Route::get('/filterSettings', 'TorrentController@filtered');
|
||||
Route::get('/', 'TorrentController@torrents')->name('torrents');
|
||||
@@ -437,7 +437,23 @@ Route::group(['middleware' => 'language'], function () {
|
||||
Route::post('/{id}/update', 'SubtitleController@update')->name('update');
|
||||
Route::delete('/{id}/delete', 'SubtitleController@destroy')->name('destroy');
|
||||
Route::get('/{id}/download', 'SubtitleController@download')->name('download');
|
||||
Route::get('/filter', 'SubtitleController@faceted');
|
||||
});
|
||||
});
|
||||
|
||||
// Tickets System
|
||||
Route::group(['prefix' => 'tickets'], function () {
|
||||
Route::name('tickets.')->group(function () {
|
||||
Route::get('/', 'TicketController@index')->name('index');
|
||||
Route::get('/create', 'TicketController@create')->name('create');
|
||||
Route::post('/store', 'TicketController@store')->name('store');
|
||||
Route::get('/{id}', 'TicketController@show')->where('id', '[0-9]+')->name('show');
|
||||
Route::get('/{id}/edit', 'TicketController@edit')->name('edit');
|
||||
Route::patch('/{id}/update', 'TicketController@update')->name('update');
|
||||
Route::delete('/{id}/destroy', 'TicketController@destroy')->name('destroy');
|
||||
Route::post('/{id}/assign', 'TicketController@assign')->name('assign');
|
||||
Route::post('/{id}/unassign', 'TicketController@unassign')->name('unassign');
|
||||
Route::post('/{id}/close', 'TicketController@close')->name('close');
|
||||
Route::post('/attachments/{attachment}/download', 'TicketAttachmentController@download')->name('attachment.download');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -897,7 +913,6 @@ Route::group(['middleware' => 'language'], function () {
|
||||
// User Tools TODO: Leaving since we will be refactoring users and roles
|
||||
Route::group(['prefix' => 'users'], function () {
|
||||
Route::get('/', 'UserController@index')->name('user_search');
|
||||
Route::get('/search', 'UserController@search')->name('user_results');
|
||||
Route::post('/{username}/edit', 'UserController@edit')->name('user_edit');
|
||||
Route::get('/{username}/settings', 'UserController@settings')->name('user_setting');
|
||||
Route::post('/{username}/permissions', 'UserController@permissions')->name('user_permissions');
|
||||
|
||||
Reference in New Issue
Block a user