Add all files

This commit is contained in:
root
2025-11-30 11:57:22 +01:00
parent 2ee51cac4f
commit 044271db3d
1476 changed files with 142544 additions and 0 deletions

View File

@@ -0,0 +1,90 @@
<?php
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Api\ApiController;
use App\Http\Requests\Api\Admin\Invoices\CreateInvoiceRequest;
use App\Http\Requests\Api\Admin\Invoices\DeleteInvoiceRequest;
use App\Http\Requests\Api\Admin\Invoices\GetInvoiceRequest;
use App\Http\Requests\Api\Admin\Invoices\GetInvoicesRequest;
use App\Http\Requests\Api\Admin\Invoices\UpdateInvoiceRequest;
use App\Http\Resources\InvoiceResource;
use App\Models\Invoice;
use Dedoc\Scramble\Attributes\Group;
use Dedoc\Scramble\Attributes\QueryParameter;
use Spatie\QueryBuilder\QueryBuilder;
#[Group(name: 'Invoices', weight: 4)]
class InvoiceController extends ApiController
{
protected const INCLUDES = [
'items',
'user',
];
/**
* List Invoices
*/
#[QueryParameter('per_page', 'How many items to show per page.', type: 'int', default: 15, example: 20)]
#[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)]
public function index(GetInvoicesRequest $request)
{
// Fetch invoices with pagination
$invoices = QueryBuilder::for(Invoice::class)
->allowedFilters(['id', 'currency_code', 'user_id', 'status'])
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->allowedSorts(['id', 'created_at', 'updated_at', 'currency_code'])
->simplePaginate(request('per_page', 15));
// Return the invoices as a JSON response
return InvoiceResource::collection($invoices);
}
/**
* Create a new invoice
*/
public function store(CreateInvoiceRequest $request)
{
// Validate and create the invoice
$invoice = Invoice::create($request->validated());
// Return the created invoice as a JSON response
return new InvoiceResource($invoice);
}
/**
* Show a specific invoice
*/
public function show(GetInvoiceRequest $request, Invoice $invoice)
{
$invoice = QueryBuilder::for(Invoice::class)
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->findOrFail($invoice->id);
// Return the invoice as a JSON response
return new InvoiceResource($invoice);
}
/**
* Update a specific invoice
*/
public function update(UpdateInvoiceRequest $request, Invoice $invoice)
{
// Validate and update the invoice
$invoice->update($request->validated());
// Return the updated invoice as a JSON response
return new InvoiceResource($invoice);
}
/**
* Delete a specific invoice
*/
public function destroy(DeleteInvoiceRequest $request, Invoice $invoice)
{
// Delete the invoice
$invoice->delete();
return $this->returnNoContent();
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Api\ApiController;
use App\Http\Requests\Api\Admin\Orders\CreateOrderRequest;
use App\Http\Requests\Api\Admin\Orders\DeleteOrderRequest;
use App\Http\Requests\Api\Admin\Orders\GetOrderRequest;
use App\Http\Requests\Api\Admin\Orders\GetOrdersRequest;
use App\Http\Requests\Api\Admin\Orders\UpdateOrderRequest;
use App\Http\Resources\OrderResource;
use App\Models\Order;
use Dedoc\Scramble\Attributes\Group;
use Dedoc\Scramble\Attributes\QueryParameter;
use Spatie\QueryBuilder\QueryBuilder;
#[Group(name: 'Orders', weight: 2)]
class OrderController extends ApiController
{
protected const INCLUDES = [
'services',
];
/**
* List Orders
*/
#[QueryParameter('per_page', 'How many items to show per page.', type: 'int', default: 15, example: 20)]
#[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)]
public function index(GetOrdersRequest $request)
{
// Fetch orders with pagination
$orders = QueryBuilder::for(Order::class)
->allowedFilters(['id', 'currency_code'])
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->allowedSorts(['id', 'created_at', 'updated_at', 'currency_code'])
->simplePaginate(request('per_page', 15));
// Return the orders as a JSON response
return OrderResource::collection($orders);
}
/**
* Create a new order
*/
public function store(CreateOrderRequest $request)
{
// Validate and create the order
$order = Order::create($request->validated());
// Return the created order as a JSON response
return new OrderResource($order);
}
/**
* Show a specific order
*/
public function show(GetOrderRequest $request, Order $order)
{
$order = QueryBuilder::for(Order::class)
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->findOrFail($order->id);
// Return the order as a JSON response
return new OrderResource($order);
}
/**
* Update a specific order
*/
public function update(UpdateOrderRequest $request, Order $order)
{
// Validate and update the order
$order->update($request->validated());
// Return the updated order as a JSON response
return new OrderResource($order);
}
/**
* Delete a specific order
*/
public function destroy(DeleteOrderRequest $request, Order $order)
{
// Delete the order
$order->delete();
return $this->returnNoContent();
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Api\ApiController;
use App\Http\Requests\Api\Admin\Services\CreateServiceRequest;
use App\Http\Requests\Api\Admin\Services\DeleteServiceRequest;
use App\Http\Requests\Api\Admin\Services\GetServiceRequest;
use App\Http\Requests\Api\Admin\Services\GetServicesRequest;
use App\Http\Requests\Api\Admin\Services\UpdateServiceRequest;
use App\Http\Resources\ServiceResource;
use App\Models\Service;
use Dedoc\Scramble\Attributes\Group;
use Dedoc\Scramble\Attributes\QueryParameter;
use Spatie\QueryBuilder\QueryBuilder;
#[Group(name: 'Services', weight: 3)]
class ServiceController extends ApiController
{
protected const INCLUDES = [
'order',
'coupon',
'user',
'product',
'invoices',
'properties',
];
/**
* List Services
*/
#[QueryParameter('per_page', 'How many items to show per page.', type: 'int', default: 15, example: 20)]
#[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)]
public function index(GetServicesRequest $request)
{
// Fetch services with pagination
$services = QueryBuilder::for(Service::class)
->allowedFilters(['quantity', 'price', 'expires_at', 'subscription_id', 'status'])
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->allowedSorts(['id', 'created_at', 'updated_at', 'expires_at', 'status'])
->simplePaginate(request('per_page', 15));
// Return the services as a JSON response
return ServiceResource::collection($services);
}
/**
* Create a new service
*/
public function store(CreateServiceRequest $request)
{
// Validate and create the service
$service = Service::create($request->validated());
// Return the created service as a JSON response
return new ServiceResource($service);
}
/**
* Show a specific service
*/
public function show(GetServiceRequest $request, Service $service)
{
$service = QueryBuilder::for(Service::class)
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->findOrFail($service->id);
// Return the service as a JSON response
return new ServiceResource($service);
}
/**
* Update a specific service
*/
public function update(UpdateServiceRequest $request, Service $service)
{
// Validate and update the service
$service->update($request->validated());
// Return the updated service as a JSON response
return new ServiceResource($service);
}
/**
* Delete a specific service
*/
public function destroy(DeleteServiceRequest $request, Service $service)
{
// Delete the service
$service->delete();
return $this->returnNoContent();
}
}

View File

@@ -0,0 +1,89 @@
<?php
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Api\ApiController;
use App\Http\Requests\Api\Admin\Tickets\CreateTicketRequest;
use App\Http\Requests\Api\Admin\Tickets\DeleteTicketRequest;
use App\Http\Requests\Api\Admin\Tickets\GetTicketRequest;
use App\Http\Requests\Api\Admin\Tickets\GetTicketsRequest;
use App\Http\Requests\Api\Admin\Tickets\UpdateTicketRequest;
use App\Http\Resources\TicketResource;
use App\Models\Ticket;
use Dedoc\Scramble\Attributes\Group;
use Dedoc\Scramble\Attributes\QueryParameter;
use Spatie\QueryBuilder\QueryBuilder;
#[Group(name: 'Tickets', weight: 5)]
class TicketController extends ApiController
{
protected const INCLUDES = [
'messages',
];
/**
* List Tickets
*/
#[QueryParameter('per_page', 'How many items to show per page.', type: 'int', default: 15, example: 20)]
#[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)]
public function index(GetTicketsRequest $request)
{
// Fetch tickets with pagination
$tickets = QueryBuilder::for(Ticket::class)
->allowedFilters(['id', 'currency_code'])
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->allowedSorts(['id', 'created_at', 'updated_at', 'currency_code'])
->simplePaginate(request('per_page', 15));
// Return the tickets as a JSON response
return TicketResource::collection($tickets);
}
/**
* Create a new ticket
*/
public function store(CreateTicketRequest $request)
{
// Validate and create the ticket
$ticket = Ticket::create($request->validated());
// Return the created ticket as a JSON response
return new TicketResource($ticket);
}
/**
* Show a specific ticket
*/
public function show(GetTicketRequest $request, Ticket $ticket)
{
$ticket = QueryBuilder::for(Ticket::class)
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->findOrFail($ticket->id);
// Return the ticket as a JSON response
return new TicketResource($ticket);
}
/**
* Update a specific ticket
*/
public function update(UpdateTicketRequest $request, Ticket $ticket)
{
// Validate and update the ticket
$ticket->update($request->validated());
// Return the updated ticket as a JSON response
return new TicketResource($ticket);
}
/**
* Delete a specific ticket
*/
public function destroy(DeleteTicketRequest $request, Ticket $ticket)
{
// Delete the ticket
$ticket->delete();
return $this->returnNoContent();
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Api\ApiController;
use App\Http\Requests\Api\Admin\TicketMessages\CreateTicketMessageRequest;
use App\Http\Requests\Api\Admin\TicketMessages\DeleteTicketMessageRequest;
use App\Http\Requests\Api\Admin\TicketMessages\GetTicketMessageRequest;
use App\Http\Requests\Api\Admin\TicketMessages\GetTicketMessagesRequest;
use App\Http\Resources\TicketMessageResource;
use App\Models\TicketMessage;
use Dedoc\Scramble\Attributes\Group;
use Dedoc\Scramble\Attributes\QueryParameter;
use Spatie\QueryBuilder\QueryBuilder;
#[Group(name: 'Ticket Messages', weight: 6)]
class TicketMessageController extends ApiController
{
protected const INCLUDES = [
'user',
'ticket',
];
/**
* List TicketMessages
*/
#[QueryParameter('per_page', 'How many items to show per page.', type: 'int', default: 15, example: 20)]
#[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)]
public function index(GetTicketMessagesRequest $request)
{
// Fetch ticketMessages with pagination
$ticketMessages = QueryBuilder::for(TicketMessage::class)
->allowedFilters(['id', 'currency_code'])
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->allowedSorts(['id', 'created_at', 'updated_at', 'currency_code'])
->simplePaginate(request('per_page', 15));
// Return the ticketMessages as a JSON response
return TicketMessageResource::collection($ticketMessages);
}
/**
* Create a new ticketMessage
*/
public function store(CreateTicketMessageRequest $request)
{
// Validate and create the ticketMessage
$ticketMessage = TicketMessage::create($request->validated());
// Return the created ticketMessage as a JSON response
return new TicketMessageResource($ticketMessage);
}
/**
* Show a specific ticketMessage
*/
public function show(GetTicketMessageRequest $request, TicketMessage $ticketMessage)
{
$ticketMessage = QueryBuilder::for(TicketMessage::class)
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->findOrFail($ticketMessage->id);
// Return the ticketMessage as a JSON response
return new TicketMessageResource($ticketMessage);
}
/**
* Delete a specific ticketMessage
*/
public function destroy(DeleteTicketMessageRequest $request, TicketMessage $ticketMessage)
{
// Delete the ticketMessage
$ticketMessage->delete();
return $this->returnNoContent();
}
}

View File

@@ -0,0 +1,95 @@
<?php
namespace App\Http\Controllers\Api\Admin;
use App\Http\Controllers\Api\ApiController;
use App\Http\Requests\Api\Admin\Users\CreateUserRequest;
use App\Http\Requests\Api\Admin\Users\DeleteUserRequest;
use App\Http\Requests\Api\Admin\Users\GetUserRequest;
use App\Http\Requests\Api\Admin\Users\GetUsersRequest;
use App\Http\Requests\Api\Admin\Users\UpdateUserRequest;
use App\Http\Resources\UserResource;
use App\Models\User;
use Dedoc\Scramble\Attributes\Group;
use Dedoc\Scramble\Attributes\QueryParameter;
use Spatie\QueryBuilder\QueryBuilder;
#[Group(name: 'Users', weight: 1)]
class UserController extends ApiController
{
protected const INCLUDES = [
'properties',
'orders',
'services',
'invoices',
'tickets',
'credits',
'role',
];
/**
* List Users
*/
#[QueryParameter('per_page', 'How many items to show per page.', type: 'int', default: 15, example: 20)]
#[QueryParameter('page', 'Which page to show.', type: 'int', example: 2)]
public function index(GetUsersRequest $request)
{
// Fetch users with pagination
$users = QueryBuilder::for(User::class)
->allowedFilters(['first_name', 'last_name', 'email'])
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->allowedSorts(['id', 'first_name', 'last_name', 'email', 'created_at'])
->simplePaginate(request('per_page', 15));
// Return the users as a JSON response
return UserResource::collection($users);
}
/**
* Create a new user
*/
public function store(CreateUserRequest $request)
{
// Validate and create the user
$user = User::create($request->validated());
// Return the created user as a JSON response
return new UserResource($user);
}
/**
* Show a specific user
*/
public function show(GetUserRequest $request, User $user)
{
$user = QueryBuilder::for(User::class)
->allowedIncludes($this->allowedIncludes(self::INCLUDES))
->findOrFail($user->id);
// Return the user as a JSON response
return new UserResource($user);
}
/**
* Update a specific user
*/
public function update(UpdateUserRequest $request, User $user)
{
// Validate and update the user
$user->update($request->validated());
// Return the updated user as a JSON response
return new UserResource($user);
}
/**
* Delete a specific user
*/
public function destroy(DeleteUserRequest $request, User $user)
{
// Delete the user
$user->delete();
return $this->returnNoContent();
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Response;
abstract class ApiController extends Controller
{
const MAPPED_INCLUDES = [
'messages' => 'ticket_messages',
'role' => 'roles',
'user' => 'users',
'ticket' => 'tickets',
];
protected function allowedIncludes($includes = []): array
{
// Check if user has permission to include the specified relationships
$allowedIncludes = [];
foreach ($includes as $include) {
// Check if the include is mapped to a specific relation
$relation = self::MAPPED_INCLUDES[$include] ?? $include;
if (
in_array('admin.' . $relation . '.view', request()->attributes->get('api_key_permissions', [])) ||
!in_array('admin.' . $relation . '.view', config('permissions.api.admin', []))
) {
$allowedIncludes[] = $include;
}
}
return $allowedIncludes;
}
/**
* Return an HTTP/204 response for the API.
*/
protected function returnNoContent(): Response
{
return new Response('', Response::HTTP_NO_CONTENT);
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Dedoc\Scramble\Attributes\ExcludeAllRoutesFromDocs;
use Illuminate\Http\Request;
#[ExcludeAllRoutesFromDocs]
class ProfileController extends Controller
{
public function me(Request $request)
{
return response()->json($request->user());
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Http\Controllers;
abstract class Controller
{
//
}

View File

@@ -0,0 +1,98 @@
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\GithubProvider;
use Laravel\Socialite\Two\GoogleProvider;
use SocialiteProviders\Discord\Provider as DiscordProvider;
class SocialLoginController extends Controller
{
protected $discord_driver;
protected $github_driver;
protected $google_driver;
public function __construct()
{
$this->discord_driver = Socialite::buildProvider(DiscordProvider::class, [
'client_id' => config('settings.oauth_discord_client_id'),
'client_secret' => config('settings.oauth_discord_client_secret'),
'redirect' => '/oauth/discord/callback',
]);
$this->github_driver = Socialite::buildProvider(GithubProvider::class, [
'client_id' => config('settings.oauth_github_client_id'),
'client_secret' => config('settings.oauth_github_client_secret'),
'redirect' => '/oauth/github/callback',
]);
$this->google_driver = Socialite::buildProvider(GoogleProvider::class, [
'client_id' => config('settings.oauth_google_client_id'),
'client_secret' => config('settings.oauth_google_client_secret'),
'redirect' => '/oauth/google/callback',
]);
}
public function redirect($provider)
{
if (!config("settings.oauth_$provider")) {
abort(404);
}
return match ($provider) {
'discord' => $this->discord_driver->scopes(['email'])->redirect(),
'github' => $this->github_driver->scopes(['user:email'])->redirect(),
'google' => $this->google_driver->scopes(['email'])->redirect(),
default => abort(404)
};
}
public function handle($provider)
{
if ($provider == 'discord') {
$oauth_user = $this->discord_driver->user();
if ($oauth_user->user['verified'] == false) {
return redirect()->route('login')->with('error', __('auth.oauth.unverified_discord_account'));
}
$user = User::where('email', $oauth_user->email)->first();
if (!$user) {
return redirect()->route('register')->with('error', __('auth.oauth.account_not_registered'));
}
Auth::login($user, true);
return redirect()->route('home');
} elseif ($provider == 'google') {
$oauth_user = $this->google_driver->user();
$user = User::where('email', $oauth_user->email)->first();
if (!$user) {
return redirect()->route('register')->with('error', __('auth.oauth.account_not_registered'));
}
Auth::login($user, true);
return redirect()->route('home');
} elseif ($provider == 'github') {
$oauth_user = $this->github_driver->user();
$user = User::where('email', $oauth_user->email)->first();
if (!$user) {
return redirect()->route('register')->with('error', __('auth.oauth.account_not_registered'));
}
Auth::login($user, true);
return redirect()->route('home');
} else {
return redirect()->route('login');
}
}
}