Initial Laravel API import
Some checks failed
continuous-integration/drone/push Build is failing

- Complete GGZ Ecademy Laravel backend application
- RESTful API for learning products, members, filters
- Authentication and authorization system
- Database migrations and seeders
- Custom CRUD generator commands
- Email notification system
- Integration with frontend applications
This commit is contained in:
Joris Slagter
2025-12-02 17:40:21 +01:00
parent 786b6b6a78
commit df155bb13d
341 changed files with 116385 additions and 2 deletions

15
.editorconfig Normal file
View File

@@ -0,0 +1,15 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2

51
.env.example Normal file
View File

@@ -0,0 +1,51 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=http://127.0.0.1:8001
APP_URL_FRONTEND=http://localhost:3000
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=3110_cms
DB_USERNAME=root
DB_PASSWORD=
BROADCAST_DRIVER=pusher
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
PUSHER_APP_ID=local
PUSHER_APP_KEY=local
PUSHER_APP_SECRET=local
PUSHER_APP_CLUSTER=mt1
PUSHER_APP_ENCRYPTED=true
PUSHER_APP_PORT=6001
PUSHER_APP_SCHEME=http
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

5
.gitattributes vendored Normal file
View File

@@ -0,0 +1,5 @@
* text=auto
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
CHANGELOG.md export-ignore

16
.gitignore vendored Normal file
View File

@@ -0,0 +1,16 @@
/.local/
/node_modules/
/public/hot/
/public/storage/
/storage/debugbar/
/storage/*.key
/vendor
/.vscode
.DS_Store
.env
.env.backup
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log

13
.styleci.yml Normal file
View File

@@ -0,0 +1,13 @@
php:
preset: laravel
disabled:
- unused_use
finder:
not-name:
- index.php
- server.php
js:
finder:
not-name:
- webpack.mix.js
css: true

View File

@@ -1,3 +1,71 @@
# laravel-backend
# Mijn-GGZ back-end
GGZ Ecademy Laravel API Backend
This is a Laravel project that requires [PHP 7](https://stackoverflow.com/questions/34909101/how-can-i-easily-switch-between-php-versions-on-mac-osx).
## Installation
To install this project, first clone the repository to your local machine.
Next, navigate into the project directory and run the following command to install the required dependencies:
```
composer install
```
## Running the Project
To run the project, you can use the built-in Laravel development server. Navigate to the project directory in your terminal and run the following command:
```
php artisan serve --port=8000
```
This will start the server and make the project available at `http://localhost:8000`.
You can stop the server at any time by pressing `Ctrl+C` in your terminal.
You can visit http://127.0.0.1:8000/api/roles to see if the project is running succesfully.
## Configuration
This Laravel project comes with a `.env.example` file that you can use to configure the application. You can create a `.env` file by copying the `.env.example` file:
```
cp .env.example .env
```
In the `.env` file, you can set your database credentials, configure your email settings, and more. Since this project runs in conjunction with [mijn-ggz-frontend](https://github.com/3110-dev/mijnggz-frontend) you will need to specify the location of this environment in the .env file. This is being defined with the property name `APP_URL_FRONTEND`
## Database set-up
This project comes with database migrations that you can use to create the necessary database tables. To run the migrations, use the following command:
```
php artisan migrate
```
This will create the required database tables based on the migration files found in the `database/migrations` directory.
## Copying existing database
If you have a DB export, that you'd like to use. You can do that with the following command:
```
mysql -u root -p < database_filename.sql
```
## Testing
This project comes with PHPUnit tests that you can run to ensure everything is working as expected. To run the tests, use the following command:
```
php artisan test
```
This will run all the tests found in the `tests/` directory.
## Conclusion
That's it! You now know how to install, run, and configure this Laravel project. Happy coding!
## Note
Note that the server configuration should refer to `public/index.php`, not `server.php`

View File

@@ -0,0 +1,127 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Artisan;
class CrudGenerator extends Command
{
protected $signature = 'crud:generator
{name : Class (singular) for example User}';
protected $description = 'Create CRUD operations';
public function __construct()
{
parent::__construct();
}
public function handle()
{
$name = $this->argument('name');
$this->controller($name);
$this->model($name);
$this->service($name);
$this->migration($name);
// $this->validator($name);
//$this->request($name);
File::append(base_path('routes/api.php'), 'Route::resource(\'' . Str::plural(strtolower($name)) . "', '{$name}Controller');");
}
protected function controller($name)
{
$controllerTemplate = str_replace(
[
'{{modelName}}',
'{{modelNamePluralLowerCase}}',
'{{modelNameSingularLowerCase}}'
],
[
$name,
strtolower(Str::plural($name)),
strtolower($name)
],
$this->getStub('Controller')
);
file_put_contents(app_path("/Http/Controllers/{$name}Controller.php"), $controllerTemplate);
}
protected function model($name)
{
$modelTemplate = str_replace(
['{{modelName}}'],
[$name],
$this->getStub('Model')
);
if (!file_exists($path = app_path('/Repositories')))
mkdir($path, 0777, true);
file_put_contents(app_path("/Repositories/{$name}.php"), $modelTemplate);
}
protected function request($name)
{
$requestTemplate = str_replace(
['{{modelName}}'],
[$name],
$this->getStub('Request')
);
if (!file_exists($path = app_path('/Http/Requests')))
mkdir($path, 0777, true);
file_put_contents(app_path("/Http/Requests/{$name}Request.php"), $requestTemplate);
}
protected function service($name)
{
$modelTemplate = str_replace(
[
'{{modelName}}',
'{{modelNameSingularLowerCase}}'
],
[
$name,
strtolower($name)
],
$this->getStub('Service')
);
if (!file_exists($path = app_path('/Services')))
mkdir($path, 0777, true);
file_put_contents(app_path("/Services/{$name}Service.php"), $modelTemplate);
}
protected function migration($name)
{
$tableName = strtolower(Str::plural($name));
Artisan::call('make:migration', ['name' => "create_{$tableName}_table"]);
}
protected function validator($name)
{
$modelTemplate = str_replace(
['{{modelName}}'],
[$name],
$this->getStub('Validator')
);
if (!file_exists($path = app_path('/Validators')))
mkdir($path, 0777, true);
file_put_contents(app_path("/Validators/{$name}Validator.php"), $modelTemplate);
}
protected function getStub($type)
{
return file_get_contents(base_path("stubs/custom/$type.stub"));
}
}

View File

@@ -0,0 +1,84 @@
<?php
namespace App\Console\Commands;
use App\Services\UserService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Mail;
use App\Mail\CourseNotificationMail;
use App\Services\CourseNotificationService;
class SendProductEmailNotifications extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'send:lp-notifications';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command that checks scheduled learning product notifications, sending emails to users specified.';
private $userService;
private $courseNotificationService;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct(
UserService $userService,
CourseNotificationService $courseNotificationService
) {
parent::__construct();
$this->userService = $userService;
$this->courseNotificationService = $courseNotificationService;
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$course_notifications = $this->courseNotificationService->getExpiredToSendWithProducts();
// No notifications? Exit
if ($course_notifications->count() <= 0) return 0;
foreach ($course_notifications as $notification) {
$users = json_decode($notification->users);
$emails = json_decode($notification->emails);
// Send emails to not registered users
if (count($emails) > 0) {
foreach ($emails as $email) {
Mail::to($email)->queue(new CourseNotificationMail($notification));
}
}
// Send emails to specified registered users
foreach ($users as $userId) {
$user = $this->userService->get($userId);
Mail::to($user)->queue(new CourseNotificationMail($notification));
}
// Mark as sent
$notification->sent = true;
$notification->save();
}
return 0;
}
}

41
app/Console/Kernel.php Normal file
View File

@@ -0,0 +1,41 @@
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
//
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')->hourly();
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Data\Validation;
use Nette\Schema\Expect;
use Nette\Schema\Processor;
use Nette\Schema\Schema;
use Nette\Schema\ValidationException;
class NetteValidator extends Validator implements ValidatesArray
{
private Processor $schemaProcessor;
private Schema $schema;
public function __construct(Processor $schemaProcessor, Schema $schema)
{
$this->schemaProcessor = $schemaProcessor;
$this->schema = $schema;
}
public function validateArray(array $items): ValidationResult
{
try {
$this->schemaProcessor->process($this->schema, $items);
return $this->success();
} catch (ValidationException $e) {
return $this->error($e->getMessage());
}
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace App\Data\Validation;
interface ValidatesArray
{
/**
* @param mixed[] $items
* @return ValidationResult
*/
public function validateArray(array $items): ValidationResult;
}

View File

@@ -0,0 +1,8 @@
<?php
namespace App\Data\Validation;
class ValidationException extends \Exception
{
}

View File

@@ -0,0 +1,40 @@
<?php
namespace App\Data\Validation;
class ValidationResult
{
private bool $error;
private ?string $errorMessage;
public function __construct(bool $error, ?string $errorMessage = null)
{
$this->error = $error;
$this->errorMessage = $errorMessage;
}
/**
* @return void|never
*/
final public function assertIsSuccess(): void
{
if ($this->isError()) {
throw new ValidationException($this->getErrorMessage());
}
}
public function isError(): bool
{
return $this->error;
}
public function isSuccess(): bool
{
return !$this->isError();
}
public function getErrorMessage(): ?string
{
return $this->errorMessage;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Data\Validation;
abstract class Validator
{
protected function error(string $message): ValidationResult
{
return new ValidationResult(true, $message);
}
protected function success(): ValidationResult
{
return new ValidationResult(false);
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class MembersUpdated implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new channel('updates');
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastAs()
{
return 'members-updated';
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class ProductsCatalogUpdated implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new channel('updates');
}
/**
* The event's broadcast name.
*
* @return string
*/
public function broadcastAs()
{
return 'products-catalog-updated';
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class RealTimeNotification implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct()
{
//
}
public function broadcastWith()
{
return [
'message' => 'mio test'
];
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
// return new PrivateChannel('channel-name');
return new channel('communications');
}
/**
* The event's broadcast name.
*
* @return string
*/
public function broadcastAs()
{
return 'global.message';
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace App\Events;
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 UserInfoUpdated implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $userId;
/**
* Create a new event instance.
*
* @return void
*/
public function __construct($user)
{
$this->userId = $user->id;
}
/**
* Get the channels the event should broadcast on.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new channel('updates');
}
/**
* The event's broadcast name.
*
* @return string
*/
public function broadcastAs()
{
return 'updated-user-' . $this->userId;
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Exceptions;
use Throwable;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that are not reported.
*
* @var array
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Report or log an exception.
*
* @param \Throwable $exception
* @return void
*
* @throws \Exception
*/
public function report(Throwable $exception)
{
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Throwable $exception
* @return \Symfony\Component\HttpFoundation\Response
*
* @throws \Throwable
*/
public function render($request, Throwable $exception)
{
return parent::render($request, $exception);
}
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['message' => 'De inloggegevens zijn onjuist'], 401);
}
return redirect()->guest('login');
}
}

View File

@@ -0,0 +1,82 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Arr;
use App\Services\AccreditationService;
use App\Repositories\FilterItemsAssociation;
use App\Http\Requests\Learning\AccreditationStore;
class AccreditationController extends Controller
{
private $accreditationService;
public function __construct(AccreditationService $accreditationService)
{
$this->accreditationService = $accreditationService;
$this->middleware('auth:sanctum');
}
public function index()
{
$accreditations = $this->accreditationService->getAll();
return response()->json($accreditations, 201);
}
public function store(AccreditationStore $request)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
if ($request['filter_items']) {
$filter_items = Arr::collapse($request['filter_items']);
$filter_items = Arr::flatten($filter_items);
}
$data = Arr::except($request->validated(), ['filter_items']);
$accreditation = $this->accreditationService->save($data);
if (isset($filter_items) && $filter_items) {
$accreditation->filters()->delete();
foreach ($filter_items as $filter_item_id) {
$filter_association = new FilterItemsAssociation();
$filter_association->filter_item_id = $filter_item_id;
$accreditation->filters()->save($filter_association);
}
}
// return $request;
return response()->json($accreditation->load('filters'), 201);
}
public function show($id)
{
$accreditation = $this->accreditationService->get($id);
return response()->json($accreditation);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->accreditationService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Http\Controllers;
use App\Services\MemberService;
use App\Services\AddressService;
use App\Http\Requests\Member\AddressStore;
class AddressController extends Controller
{
private $addressService;
private $memberService;
public function __construct(
MemberService $memberService,
AddressService $addressService
) {
$this->memberService = $memberService;
$this->addressService = $addressService;
$this->middleware('auth:sanctum');
}
public function index()
{
$addresses = $this->addressService->getAll();
return response()->json($addresses, 201);
}
public function store(AddressStore $request)
{
$member = $this->memberService->get($request->member_id);
if (!$member) {
return response()->json(['message' => 'Member not found.'], 404);
}
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isSuperAdminOrAdmin = $isSuperAdmin || $isAdmin;
// $isUserDelegated = $member->user_id === auth()->user()->id;
if (!$isSuperAdmin && !$isAdmin) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$request_data = $request->validated();
// if is an user delegated to work with that member, remove approved_by and approved_at
$request_data['revisor_id'] = $isSuperAdminOrAdmin ? auth()->user()->id : null;
$request_data['approved_at'] = $isSuperAdminOrAdmin ? now() : null;
$address = $this->addressService->save($request_data);
return response()->json($address, 201);
}
public function show($id)
{
$address = $this->addressService->get($id);
return response()->json($address);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isSuperAdminOrAdmin = $isSuperAdmin || $isAdmin;
if (!$isSuperAdminOrAdmin) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->addressService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,199 @@
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Response\ApiResponse;
use Illuminate\Http\Request;
use App\Services\UserService;
use App\Services\MemberService;
use Illuminate\Support\Carbon;
use App\Http\Requests\User\Login;
use Illuminate\Support\Facades\Hash;
use App\Http\Resources\UserLoggedResource;
use App\Repositories\Role;
use Redirect;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Mail;
use Laravel\Sanctum\PersonalAccessToken;
use Illuminate\Support\Facades\Log;
class AuthController extends Controller
{
private $userService;
private $memberService;
public function __construct(
UserService $userService,
MemberService $memberService
) {
$this->userService = $userService;
$this->memberService = $memberService;
$this->middleware('auth:sanctum', [
'except' => [
'get_sso_data',
'login',
'signup',
'sso',
'status',
],
]);
}
public function login(Login $request)
{
if (empty($request->token)) {
$user = $this->userService->getByEmailWith($request->email, ['roles']);
if (!$user || !Hash::check($request->password, $user->password)) {
return response(['error' => ['The provided credentials are incorrect.']]);
}
} else {
$client = new \GuzzleHttp\Client(['base_uri' => static::determineIdpUri()]);
try {
$response = $client->request('POST', 'protocol/openid-connect/token', [
'form_params' => [
'code' => $request->token,
'client_id' => config('sso.client_id'),
'client_secret' => config('sso.secret'),
'redirect_uri' => config('sso.redirect_uri'),
'scope' => 'openid profile',
'grant_type' => 'authorization_code'
]
]);
$token = json_decode($response->getBody(), true)['id_token'];
$decodedToken = \Firebase\JWT\JWT::decode($token, $this->getJwks(), false);
} catch (ClientException $e) {
$html = 'Login faild with token:' . $request->token;
Mail::send([], [], function ($message) use ($html) {
$message
->to('joris@ggzecademy.nl')
->subject('Login failed via SSO')
->setBody($html, 'text/html');
});
}
if (empty($decodedToken->kg) || !stristr($decodedToken->kg, 'KG')) {
return response(['error' => ['The provided credentials are incorrect.']]);
}
$organization_id = str_replace('KG_', '', $decodedToken->kg);
$member = $this->memberService->get($organization_id);
$user = $this->userService->getByEmailWith($decodedToken->email, ['roles']);
if (!$user) {
$new_user = [
'first_name' => $decodedToken->given_name,
'last_name' => $decodedToken->family_name,
'email' => $decodedToken->email,
'password' => 'aT@5*Wb*W7gseVhC',
];
$user = $this->userService->save($new_user, false);
$user->roles()->attach(Role::whereName('user')->firstOrFail());
}
$member->users()->syncWithoutDetaching([$user->id]);
$member->save();
}
$user->last_login_at = $user->logged_at;
$user->last_login_ip = $request->getClientIp();
$user->logged_at = Carbon::now();
$user->save();
$token = $user->createToken('cms-token')->plainTextToken;
$response = ['token' => $token];
return response($response, 201);
}
private function getJwks(): array
{
$jwkData = json_decode(
file_get_contents(static::determineIdpUri() . 'protocol/openid-connect/certs'),
true
);
return \Firebase\JWT\JWK::parseKeySet($jwkData);
}
public function logout(Request $request)
{
$request->user()->tokens()->delete();
return response()->json('Logged-out', 201);
}
public function status(Request $request)
{
$bearerToken = $request->bearerToken();
if (is_null($bearerToken)) {
return ApiResponse::error(
new Error\AuthController\MissingBearerTokenError(),
);
} else {
$accessToken = PersonalAccessToken::findToken($bearerToken);
return ApiResponse::success([
'authenticated' => $accessToken instanceof PersonalAccessToken,
'user' => $accessToken ? $accessToken->tokenable->email : null,
]);
}
}
public function me(Request $request)
{
return response()->json(new UserLoggedResource($request->user()));
}
public function sso()
{
return Redirect::to(static::buildSsoEndpointUri());
}
private static function buildSsoEndpointUri(): string
{
$endpointQuery = http_build_query([
'client_id' => config('sso.client_id'),
'redirect_uri' => config('sso.redirect_uri'),
'scope' => 'openid profile',
'response_type' => 'code',
'nonce' => md5(rand()), // TODO: proper nonce handling
], '', '&', PHP_QUERY_RFC3986);
$endpointQuery = str_replace('%2B', '+', $endpointQuery);
return sprintf('%s?%s', static::determineIdpUri('protocol/openid-connect/auth'), $endpointQuery);
}
private static function determineIdpUri(string $path = ''): string
{
$baseUri = rtrim(config('sso.idp_base_uri'), '/');
return sprintf('%s/%s', $baseUri, $path);
}
public function get_sso_data() {
$client = new \GuzzleHttp\Client([
'base_uri' => static::determineIdpUri(),
'headers' => [
'Authorization' => sprintf('Bearer %s', $_GET['token']),
'Accept' => 'application/json',
],
]);
$response = $client->request('GET', 'oidc/userinfo.php');
return response($response->getBody()->getContents(), 201);
}
}

View File

@@ -0,0 +1,213 @@
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Response\ApiResponse;
use Illuminate\Http\Request;
use App\Services\UserService;
use App\Services\MemberService;
use Illuminate\Support\Carbon;
use App\Http\Requests\User\Login;
use Illuminate\Support\Facades\Hash;
use App\Http\Resources\UserLoggedResource;
use App\Repositories\Role;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Mail;
use Laravel\Sanctum\PersonalAccessToken;
class AuthController extends Controller
{
private $userService;
private $memberService;
public function __construct(
UserService $userService,
MemberService $memberService
) {
$this->userService = $userService;
$this->memberService = $memberService;
$this->middleware('auth:sanctum', [
'except' => [
'get_sso_data',
'login',
'signup',
'sso',
'status',
],
]);
}
public function login(Login $request)
{
if (empty($request->token)) {
$user = $this->userService->getByEmailWith($request->email, ['roles']);
if (!$user || !Hash::check($request->password, $user->password)) {
return response(['error' => ['The provided credentials are incorrect.']]);
}
} else {
$client = new \GuzzleHttp\Client(['base_uri' => static::determineIdpUri()]);
$headers = [
'Authorization' => 'Bearer ' . $request->token,
'Accept' => 'application/json',
];
try {
$response = $client->request('GET', 'oidc/userinfo.php', [
'headers' => $headers
]);
} catch (ClientException $e) {
$html = 'Login faild with token:' . $request->token;
Mail::send([], [], function ($message) use ($html) {
$message
->to('jasper@3110.nl')
->subject('Login failed via SSO')
->setBody($html, 'text/html');
});
}
$data = $response->getBody()->getContents();
$data = json_decode($data);
if (empty($data->profile) || !stristr($data->profile, 'KG')) {
return response(['error' => ['The provided credentials are incorrect.']]);
}
$profile_arr = explode(',', $data->profile);
$organization_id = str_replace('KG_', '', $profile_arr[0]);
$member = $this->memberService->get($organization_id);
$user = $this->userService->getByEmailWith($data->sub, ['roles']);
if (!$user) {
$new_user = [
'first_name' => $data->given_name,
'last_name' => $data->family_name,
'email' => $data->sub,
'password' => 'aT@5*Wb*W7gseVhC',
];
$user = $this->userService->save($new_user, false);
$user->roles()->attach(Role::whereName('user')->firstOrFail());
}
$member->users()->syncWithoutDetaching([$user->id]);
$member->save();
}
$user->last_login_at = $user->logged_at;
$user->last_login_ip = $request->getClientIp();
$user->logged_at = Carbon::now();
$user->save();
$token = $user->createToken('cms-token')->plainTextToken;
$response = ['token' => $token];
return response($response, 201);
}
public function logout(Request $request)
{
$request->user()->tokens()->delete();
return response()->json('Logged-out', 201);
}
public function status(Request $request)
{
$bearerToken = $request->bearerToken();
if (is_null($bearerToken)) {
return ApiResponse::error(
new Error\AuthController\MissingBearerTokenError(),
);
} else {
$accessToken = PersonalAccessToken::findToken($bearerToken);
return ApiResponse::success([
'authenticated' => $accessToken instanceof PersonalAccessToken,
'user' => $accessToken ? $accessToken->tokenable->email : null,
]);
}
}
public function me(Request $request)
{
return response()->json(new UserLoggedResource($request->user()));
}
private static function dumpLocal(...$values): void
{
if (static::isLocal()) {
dd(...$values);
}
}
private static function isLocal(): bool
{
return $_SERVER['REMOTE_ADDR'] === '89.98.81.170';
}
public function sso()
{
$cookieFileHandle = tmpfile();
$cookieFilePath = stream_get_meta_data($cookieFileHandle)['uri'];
$ch = curl_init(static::buildSsoEndpointUri());
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIESESSION, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFilePath);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFilePath);
$result = curl_exec($ch);
curl_close($ch);
fclose($cookieFileHandle);
if (static::isLocal()) {
echo $result; exit;
}
echo '<div style="display: none;">' . $result . '</div>';
}
private static function buildSsoEndpointUri(): string
{
$endpointQuery = http_build_query([
'client_id' => config('sso.client_id'),
'redirect_uri' => config('sso.redirect_uri'),
'scope' => implode('+', config('sso.scopes')),
'response_type' => 'id_token+token',
'response_mode' => 'form_post',
'nonce' => md5(rand()), // TODO: proper nonce handling
], '', '&', PHP_QUERY_RFC3986);
$endpointQuery = str_replace('%2B', '+', $endpointQuery);
return sprintf('%s?%s', static::determineIdpUri('oidc/authorize.php'), $endpointQuery);
}
private static function determineIdpUri(string $path = ''): string
{
$baseUri = rtrim(config('sso.idp_base_uri'), '/');
return sprintf('%s/%s', $baseUri, $path);
}
public function get_sso_data() {
$client = new \GuzzleHttp\Client([
'base_uri' => static::determineIdpUri(),
'headers' => [
'Authorization' => sprintf('Bearer %s', $_GET['token']),
'Accept' => 'application/json',
],
]);
$response = $client->request('GET', 'oidc/userinfo.php');
return response($response->getBody()->getContents(), 201);
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace App\Http\Controllers;
use App\Services\BranchService;
use App\Http\Requests\Member\BranchStore;
class BranchController extends Controller
{
private $branchService;
public function __construct(BranchService $branchService)
{
$this->branchService = $branchService;
$this->middleware('auth:sanctum');
}
public function index()
{
$branches = $this->branchService->getAll();
return response()->json($branches, 201);
}
public function store(BranchStore $request)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$branch = $this->branchService->save($request->all());
return response()->json($branch, 201);
}
public function show($id)
{
$branch = $this->branchService->get($id);
return response()->json($branch);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->branchService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ChecklistCategoryRequest;
use App\Services\ChecklistCategoryService;
class ChecklistCategoryController extends Controller
{
private $checklistCategoryService;
public function __construct(ChecklistCategoryService $checklistCategoryService)
{
$this->checklistCategoryService = $checklistCategoryService;
}
public function index()
{
$checklistCategories = $this->checklistCategoryService->with(['items']);
return response()->json($checklistCategories, 201);
}
public function store(ChecklistCategoryRequest $request)
{
$checklistcategory = $this->checklistCategoryService->save($request->all());
return response()->json($checklistcategory, 201);
}
public function show($id)
{
$checklistcategory = $this->checklistCategoryService->get($id);
return response()->json($checklistcategory);
}
public function destroy($id)
{
$this->checklistCategoryService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ChecklistRequest;
use App\Services\ChecklistService;
class ChecklistController extends Controller
{
private $checklistService;
public function __construct(ChecklistService $checklistService)
{
$this->checklistService = $checklistService;
}
public function index()
{
$checklists = $this->checklistService->getAll();
return response()->json($checklists, 201);
}
public function store(ChecklistRequest $request)
{
$checklist = $this->checklistService->save($request->all());
return response()->json($checklist, 201);
}
public function show($id)
{
$checklist = $this->checklistService->get($id);
return response()->json($checklist);
}
public function destroy($id)
{
$this->checklistService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ChecklistVersionRequest;
use App\Services\ChecklistVersionService;
class ChecklistVersionController extends Controller
{
private $checklistversionService;
public function __construct(ChecklistVersionService $checklistversionService)
{
$this->checklistversionService = $checklistversionService;
}
public function index()
{
$checklistversions = $this->checklistversionService->getAll();
return response()->json($checklistversions, 201);
}
public function store(ChecklistVersionRequest $request)
{
$checklistversion = $this->checklistversionService->save($request->all());
return response()->json($checklistversion, 201);
}
public function show($id)
{
$checklistversion = $this->checklistversionService->get($id);
return response()->json($checklistversion);
}
public function destroy($id)
{
$this->checklistversionService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace App\Http\Controllers;
use App\Services\MemberService;
use App\Services\ContactService;
use App\Http\Requests\Member\ContactStore;
class ContactController extends Controller
{
private $contactService;
private $memberService;
public function __construct(
MemberService $memberService,
ContactService $contactService
) {
$this->contactService = $contactService;
$this->memberService = $memberService;
$this->middleware('auth:sanctum');
}
public function index()
{
$contacts = $this->contactService->getAll();
return response()->json($contacts, 201);
}
public function store(ContactStore $request)
{
$member = $this->memberService->get($request->member_id);
if (!$member) {
return response()->json(['message' => 'Member not found.'], 404);
}
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isSuperAdminOrAdmin = $isSuperAdmin || $isAdmin;
$isUserDelegated = $member->user_id === auth()->user()->id;
if (
!$isSuperAdmin &&
!$isAdmin &&
!$isUserDelegated
) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$request_data = $request->validated();
// if is an user delegated to work with that member, remove approved_by and approved_at
$request_data['revisor_id'] = $isSuperAdminOrAdmin ? auth()->user()->id : null;
$request_data['approved_at'] = $isSuperAdminOrAdmin ? now() : null;
$contact = $this->contactService->save($request_data);
return response()->json($contact, 201);
}
public function show($id)
{
$contact = $this->contactService->get($id);
return response()->json($contact);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isSuperAdminOrAdmin = $isSuperAdmin || $isAdmin;
if (!$isSuperAdminOrAdmin) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->contactService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace App\Http\Controllers;
use App\Services\MemberService;
use App\Services\UserService;
use App\Services\ContributionService;
use App\Http\Requests\Member\ContributionStore;
use Illuminate\Support\Facades\Mail;
use App\Mail\MemberChanges;
class ContributionController extends Controller
{
private $contributionService;
private $userService;
public function __construct(
MemberService $memberService,
UserService $userService,
ContributionService $contributionService
) {
$this->memberService = $memberService;
$this->userService = $userService;
$this->contributionService = $contributionService;
$this->middleware('auth:sanctum');
}
public function index()
{
$contributions = $this->contributionService->getAll();
return response()->json($contributions, 201);
}
public function store(ContributionStore $request)
{
$member = $this->memberService->get($request->member_id);
if (!$member) {
return response()->json(['message' => 'Member not found.'], 404);
}
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isSuperAdminOrAdmin = $isSuperAdmin || $isAdmin;
$isAppliedToAll = $request->has('toAll') ? true : false;
if (!$isSuperAdminOrAdmin) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$request_data = $request->validated();
$request_data['revisor_id'] = auth()->user()->id;
$request_data['approved_at'] = now();
$contribution = null;
if ($isAppliedToAll) {
$members = $this->memberService->getAll();
// Store for all existing members
foreach ($members as $member) {
$request_data['member_id'] = $member['id'];
if ($request_data['member_id'] === $member['user_id']) {
$contribution = $this->contributionService->save($request_data);
} else {
$this->contributionService->save($request_data);
}
}
} else {
$contribution = $this->contributionService->save($request_data);
}
return response()->json($contribution, 201);
}
public function show($id)
{
$contribution = $this->contributionService->get($id);
return response()->json($contribution);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isSuperAdminOrAdmin = $isSuperAdmin || $isAdmin;
if (!$isSuperAdminOrAdmin) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->contributionService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

View File

@@ -0,0 +1,80 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Artisan;
use App\Services\CourseNotificationService;
use App\Http\Requests\Learning\CourseNotificationStore;
class CourseNotificationController extends Controller
{
private $courseNotificationService;
public function __construct(CourseNotificationService $courseNotificationService)
{
$this->courseNotificationService = $courseNotificationService;
$this->middleware('auth:sanctum');
}
public function index()
{
if (!auth()->user()->hasRole('admin')) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$course_notifications = $this->courseNotificationService->getAll();
return response()->json($course_notifications, 201);
}
public function store(CourseNotificationStore $request)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$course_notification = $this->courseNotificationService->save($request->validated());
return response()->json($course_notification, 201);
}
public function show($id)
{
$course_notification = $this->courseNotificationService->get($id);
return response()->json($course_notification);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->courseNotificationService->delete($id);
return response()->json(null, 204);
}
public function testCommand()
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
Artisan::call('send:lp-notifications');
return 0;
}
}

View File

@@ -0,0 +1,101 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
class CsvExportController extends Controller
{
public function downloadCSV()
{
// Execute SQL query
$results = DB::select("
SELECT
l.id,
l.title,
l.lead_time,
l.short_description,
l.learning_goals,
l.review,
l.certification,
l.extra_information,
l.target_audience,
l.quality_standards,
l.contract_agreements,
(
SELECT CONCAT('https://mijnggzbackend.ggzecademy.nl/storage/', m.id, '/', m.file_name)
FROM media m
WHERE m.model_id = l.id AND m.collection_name = 'learning_products_covers'
LIMIT 1
) AS cover,
(
SELECT CONCAT('https://mijnggzbackend.ggzecademy.nl/storage/', m.id, '/', m.file_name)
FROM media m
WHERE m.model_id = l.id AND m.collection_name = 'learning_products_tiles'
LIMIT 1
) AS thumb,
(
SELECT GROUP_CONCAT(CONCAT(i.title, '-', ac.credits))
FROM filter_items_associations a
LEFT JOIN filter_items AS i ON i.id = a.filter_item_id
LEFT JOIN accreditations AS ac ON ac.id = a.filter_items_associations_id
WHERE ac.learning_product_id = l.id AND i.filter_id = 10
) AS titles_and_credits
FROM
learning_products l
WHERE
l.published = 1 AND l.deleted_at IS NULL
GROUP BY
l.title, l.id, l.lead_time, l.short_description, l.learning_goals, l.review,
l.certification, l.extra_information, l.target_audience, l.quality_standards, l.contract_agreements
");
// Format the results into CSV
$csvOutput = $this->formatToCsv($results);
// Send the CSV file to the client
$filename = "export.csv";
return response($csvOutput, 200)
->header('Content-Type', 'text/csv')
->header('Content-Disposition', "attachment; filename=$filename");
}
protected function formatToCsv($data)
{
$handle = fopen('php://temp', 'w');
// Add headers for CSV (if needed)
fputcsv($handle, [
'ID', 'Title', 'Lead Time', 'Short Description',
'Learning Goals', 'Review', 'Certification', 'Extra Information',
'Target Audience', 'Quality Standards', 'Contract Agreements',
'Cover', 'Thumb', 'Titles and Credits'
]);
foreach ($data as $row) {
fputcsv($handle, [
$row->id,
strip_tags($row->title),
strip_tags($row->lead_time),
strip_tags($row->short_description),
strip_tags($row->learning_goals),
strip_tags($row->review),
strip_tags($row->certification),
strip_tags($row->extra_information),
strip_tags($row->target_audience),
strip_tags($row->quality_standards),
strip_tags($row->contract_agreements),
$row->cover,
$row->thumb,
$row->titles_and_credits
]);
}
rewind($handle);
$contents = stream_get_contents($handle);
fclose($handle);
return $contents;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Http\Controllers\Error\AuthController;
use App\Http\Controllers\Error\ErrorInterface;
use Illuminate\Http\Response;
class MissingBearerTokenError implements ErrorInterface
{
public function getStatusCode(): int
{
return Response::HTTP_BAD_REQUEST;
}
public function getErrorCode(): string
{
return 'missing.bearer_token';
}
public function getErrorMessage(): string
{
return 'Missing bearer token';
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Http\Controllers\Error;
interface ErrorInterface
{
public function getStatusCode(): int;
public function getErrorCode(): string;
public function getErrorMessage(): string;
}

View File

@@ -0,0 +1,77 @@
<?php
namespace App\Http\Controllers;
use App\Services\FilterService;
use App\Services\FilterItemService;
use App\Http\Resources\FiltersResource;
use App\Http\Requests\Filter\FilterStore;
use App\Http\Requests\Filter\FilterItemStore;
class FilterController extends Controller
{
private $filterService;
private $filterItemService;
public function __construct(FilterService $filterService, FilterItemService $filterItemService)
{
$this->filterService = $filterService;
$this->filterItemService = $filterItemService;
$this->middleware('auth:sanctum', [
'except' => [
'index', 'show'
]
]);
}
public function index()
{
$filters = $this->filterService->with(['items']);
return response()->json(FiltersResource::collection($filters), 201);
}
public function indexWithCount()
{
$filters = $this->filterService->withCount(['items']);
return response()->json(FiltersResource::collection($filters), 201);
}
public function store(FilterStore $request)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$filter = $this->filterService->save($request->all());
return response()->json($filter, 201);
}
public function show($id)
{
$filter = $this->filterService->getOneWith($id, ['items']);
return response()->json($filter);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->filterService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Http\Controllers;
use App\Services\FilterItemService;
use App\Http\Resources\FiltersResource;
use App\Http\Requests\Filter\FilterItemStore;
use App\Services\FilterItemsAssociationService;
class FilterItemController extends Controller
{
private $filterItemService;
public function __construct(
FilterItemService $filterItemService,
FilterItemsAssociationService $filterItemsAssociationService
) {
$this->filterItemService = $filterItemService;
$this->filterItemsAssociationService = $filterItemsAssociationService;
$this->middleware('auth:sanctum');
}
public function index()
{
$filter_items = $this->filterItemService->getAll();
return response()->json($filter_items, 201);
}
public function store(FilterItemStore $request)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$filter_item = $this->filterItemService->save($request->all());
return response()->json(new FiltersResource($filter_item), 201);
}
public function show($id)
{
$filter_item = $this->filterItemService->get($id);
return response()->json($filter_item);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->filterItemsAssociationService->deleteAllWithFilterItemId($id);
$this->filterItemService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\FilterItemsAssociationRequest;
use App\Services\FilterItemsAssociationService;
class FilterItemsAssociationController extends Controller
{
private $filterItemsAssociationService;
public function __construct(FilterItemsAssociationService $filterItemsAssociationService)
{
$this->filterItemsAssociationService = $filterItemsAssociationService;
}
public function index()
{
$filterItemsAssociations = $this->filterItemsAssociationService->getAll();
return response()->json($filterItemsAssociations, 201);
}
public function store(FilterItemsAssociationRequest $request)
{
$filterItemsAssociations = $this->filterItemsAssociationService->save($request->all());
return response()->json($filterItemsAssociations, 201);
}
public function show($id)
{
$filterItemsAssociations = $this->filterItemsAssociationService->get($id);
return response()->json($filterItemsAssociations);
}
public function destroy($id)
{
$this->filterItemsAssociationService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\Request;
class ForgotPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset emails and
| includes a trait which assists in sending these notifications from
| your application to your users. Feel free to explore this trait.
|
*/
use SendsPasswordResetEmails;
protected function sendResetLinkResponse(Request $request, $response)
{
return response(['message' => $response]);
}
protected function sendResetLinkFailedResponse(Request $request, $response)
{
return response(['error' => $response], 422);
}
}

View File

@@ -0,0 +1,340 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Arr;
use App\Services\LearningProductService;
use App\Repositories\FilterItemsAssociation;
use App\Http\Resources\LearningProductResource;
use App\Http\Requests\Learning\LearningProductId;
use App\Http\Requests\Learning\LearningProductStore;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Log;
class LearningProductController extends Controller
{
private $learningProductService;
public function __construct(LearningProductService $learningProductService)
{
$this->learningProductService = $learningProductService;
$this->middleware('auth:sanctum', [
'except' => [
'getPublished',
]
]);
}
public function index()
{
$learningProducts = $this->learningProductService->withTrashedAndChildren([
'filters',
'filters.filter_item.filter',
// 'versions',
'accreditations',
'notifications',
])->sortDesc();
return response()->json(
LearningProductResource::collection($learningProducts),
201,
);;
}
public function getPublished()
{
$withColumnAll = [
'filters',
'filters.filter_item.filter',
'accreditations',
'accreditations.filters.filter_item',
'notifications'
];
$learningProductAll = $this->learningProductService->getPublishedWith($withColumnAll)
->groupBy('code')
->map(function (Collection $groupedLearningProductAll) {
return $groupedLearningProductAll->last();
})
->sortDesc()
->flatten(1);
return response()->json(
LearningProductResource::collection($learningProductAll),
201,
);
}
public function store(LearningProductStore $request)
{
try {
Log::info('Store method called');
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
Log::info('User roles checked', ['isSuperAdmin' => $isSuperAdmin, 'isAdmin' => $isAdmin, 'isOperator' => $isOperator]);
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
// Is it draft with parent_id marked as published?
$is_draft = isset($request['parent_id']);
$is_draft_published = $is_draft && $request['published'];
Log::info('Draft status checked', ['is_draft' => $is_draft, 'is_draft_published' => $is_draft_published]);
$hasCover = isset($request['cover']) && $request->hasFile('cover');
$hasTile = isset($request['tile']) && $request->hasFile('tile');
Log::info('File status checked', ['hasCover' => $hasCover, 'hasTile' => $hasTile]);
// Validate and prepare request data
$request_data = $request->validated();
if ($hasCover) {
$request_data = Arr::except($request_data, ['cover']);
}
if ($hasTile) {
$request_data = Arr::except($request_data, ['tile']);
}
// Publish without parent_id
if ($is_draft_published) {
$request_data['parent_id'] = null;
}
$request_data = Arr::except($request_data, ['filtersGrouped', 'synonymsSelected']);
// Ensure voor_opleiders has a default value
if (!isset($request_data['voor_opleiders']) || $request_data['voor_opleiders'] === null) {
$request_data['voor_opleiders'] = false;
}
Log::info('Request data prepared', ['request_data' => $request_data]);
// Save finally the product
$learning_product = $this->learningProductService->save($request_data);
Log::info('Learning product saved', ['learning_product' => $learning_product]);
// Get Filter Items passed
$filter_items = json_decode(html_entity_decode(stripslashes($request['filtersGrouped'])));
$synonyms_selected = json_decode(html_entity_decode(stripslashes($request['synonymsSelected'])));
Log::info('Filters and synonyms decoded', ['filter_items' => $filter_items, 'synonyms_selected' => $synonyms_selected]);
if ($synonyms_selected) {
$learning_product->synonyms()->sync($synonyms_selected);
}
$arrayTmp = [];
if ($filter_items) {
foreach ($filter_items as $key => $value) {
$arrayTmp[] = $value;
}
$filter_items = Arr::collapse($arrayTmp);
$filter_items = Arr::flatten($arrayTmp);
// Saves filter items associations with this learning product
$learning_product->filters()->delete();
foreach ($filter_items as $filter_item_id) {
$filter_association = new FilterItemsAssociation();
$filter_association->filter_item_id = $filter_item_id;
$learning_product->filters()->save($filter_association);
}
}
// if a file was uploaded as cover or tile, add them
if ($hasCover) {
$learning_product->addMediaFromRequest('cover')->toMediaCollection('learning_products_covers');
}
if ($hasTile) {
$learning_product->addMediaFromRequest('tile')->toMediaCollection('learning_products_tiles');
}
if ($is_draft) {
// 1st draft of the published product
$original_product_published = $this->learningProductService->get($request['parent_id']);
// If no cover has been attached before
if (!$hasCover && !$learning_product->cover) {
$image = $original_product_published->getMedia('learning_products_covers')->first();
if ($image) {
$learning_product->copyMedia($image->getPath())->toMediaCollection('learning_products_covers');
}
}
// If no tile has been attached before
if (!$hasTile && !$learning_product->tile) {
$image = $original_product_published->getMedia('learning_products_tiles')->first();
if ($image) {
$learning_product->copyMedia($image->getPath())->toMediaCollection('learning_products_tiles');
}
}
}
// ForceDelete the parent if draft published
if ($is_draft_published && $learning_product) {
$this->destroy($request['parent_id'], true);
}
Log::info('Learning product processed successfully', ['learning_product' => $learning_product]);
// Emit Event to update products
// broadcast(new \App\Events\ProductsCatalogUpdated);
if ($learning_product) {
return response()->json(new LearningProductResource($learning_product), 201);
} else {
return response()->json(['message' => 'Learning Product not found.'], 404);
}
} catch (\Exception $e) {
Log::error('Error in LearningProductController@store: ' . $e->getMessage(), ['exception' => $e]);
return response()->json(['message' => 'Internal Server Error'], 500);
}
}
public function show($id)
{
$learning_product = $this->learningProductService->getOneWithChildrenAndTrashed($id, [
'filters',
'filters.filter_item.filter',
'versions',
'accreditations',
'notifications',
'synonyms',
]);
return response()->json(new LearningProductResource($learning_product));
}
public function countAll()
{
return response()->json($this->learningProductService->countAll());
}
public function destroy(String $id, $forceDelete = false)
{
try {
Log::info('Destroy method called', ['id' => $id, 'forceDelete' => $forceDelete]);
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$learning_product = $this->learningProductService->get($id);
if (!$learning_product) {
return response()->json(['message' => 'Learning Product not found.'], 404);
}
// Verwijder gerelateerde records in de versions tabel
\DB::table('versions')->where('learning_product_id', $id)->delete();
if ($forceDelete) {
$learning_product->forceDelete();
} else {
$learning_product->delete();
}
Log::info('Learning product deleted successfully', ['id' => $id]);
return response()->json(null, 204);
} catch (\Exception $e) {
Log::error('Error in LearningProductController@destroy: ' . $e->getMessage(), ['exception' => $e]);
return response()->json(['message' => 'Internal Server Error'], 500);
}
}
public function clone(LearningProductId $request)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
if (!isset($request['product_id']) || !$request['product_id']) {
return response()->json(['message' => 'Product id missing.'], 400);
}
// get original product to clone
$original_product = $this->learningProductService->getOneWith($request['product_id'], [
'filters',
'filters.filter_item.filter',
'versions',
'accreditations',
'notifications',
'synonyms',
]);
// Return if not published
if (!$original_product->published) {
return response()->json([
'error' => 'You cannot duplicate a draft'
], 400);
}
// Return already has a draft
if ($original_product->draft) {
return response()->json(['message' => 'There is already a draft for this product'], 400);
}
// set as draft
$draft = $original_product->replicate();
$draft->parent_id = $original_product->id;
$draft->published = false;
// clone cover & tiles, finally save
$cover = $original_product->getMedia('learning_products_covers')->first();
$tile = $original_product->getMedia('learning_products_tiles')->first();
if ($cover) {
$draft
->copyMedia($cover->getPath())
->toMediaCollection('learning_products_covers');
}
if ($tile) {
$draft
->copyMedia($tile->getPath())
->toMediaCollection('learning_products_covers');
}
$draft->save();
// TODO: clone accreditations, versions too?
// Clone Filter Items
if ($original_product->filters()) {
$filter_items_ids = $original_product->filters->pluck('filter_item_id');
foreach ($filter_items_ids as $filter_item_id) {
$filter_association = new FilterItemsAssociation();
$filter_association->filter_item_id = $filter_item_id;
$draft->filters()->save($filter_association);
}
}
// Clone Synonyms
if ($original_product->synonyms()) {
$synonyms_ids = $original_product->synonyms->pluck('id');
$draft->synonyms()->sync($synonyms_ids);
}
return response()->json(null, 201);
}
}

View File

@@ -0,0 +1,335 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Arr;
use App\Services\LearningProductService;
use App\Repositories\FilterItemsAssociation;
use App\Http\Resources\LearningProductResource;
use App\Http\Requests\Learning\LearningProductId;
use App\Http\Requests\Learning\LearningProductStore;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Log;
class LearningProductController extends Controller
{
private $learningProductService;
public function __construct(LearningProductService $learningProductService)
{
$this->learningProductService = $learningProductService;
$this->middleware('auth:sanctum', [
'except' => [
'getPublished',
]
]);
}
public function index()
{
$learningProducts = $this->learningProductService->withTrashedAndChildren([
'filters',
'filters.filter_item.filter',
// 'versions',
'accreditations',
'notifications',
])->sortDesc();
return response()->json(
LearningProductResource::collection($learningProducts),
201,
);;
}
public function getPublished()
{
$withColumnAll = [
'filters',
'filters.filter_item.filter',
'accreditations',
'accreditations.filters.filter_item',
'notifications'
];
$learningProductAll = $this->learningProductService->getPublishedWith($withColumnAll)
->groupBy('code')
->map(function (Collection $groupedLearningProductAll) {
return $groupedLearningProductAll->last();
})
->sortDesc()
->flatten(1);
return response()->json(
LearningProductResource::collection($learningProductAll),
201,
);
}
public function store(LearningProductStore $request)
{
try {
Log::info('Store method called');
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
Log::info('User roles checked', ['isSuperAdmin' => $isSuperAdmin, 'isAdmin' => $isAdmin, 'isOperator' => $isOperator]);
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
// Is it draft with parent_id marked as published?
$is_draft = isset($request['parent_id']);
$is_draft_published = $is_draft && $request['published'];
Log::info('Draft status checked', ['is_draft' => $is_draft, 'is_draft_published' => $is_draft_published]);
$hasCover = isset($request['cover']) && $request->hasFile('cover');
$hasTile = isset($request['tile']) && $request->hasFile('tile');
Log::info('File status checked', ['hasCover' => $hasCover, 'hasTile' => $hasTile]);
// Validate and prepare request data
$request_data = $request->validated();
if ($hasCover) {
$request_data = Arr::except($request_data, ['cover']);
}
if ($hasTile) {
$request_data = Arr::except($request_data, ['tile']);
}
// Publish without parent_id
if ($is_draft_published) {
$request_data['parent_id'] = null;
}
$request_data = Arr::except($request_data, ['filtersGrouped', 'synonymsSelected']);
Log::info('Request data prepared', ['request_data' => $request_data]);
// Save finally the product
$learning_product = $this->learningProductService->save($request_data);
Log::info('Learning product saved', ['learning_product' => $learning_product]);
// Get Filter Items passed
$filter_items = json_decode(html_entity_decode(stripslashes($request['filtersGrouped'])));
$synonyms_selected = json_decode(html_entity_decode(stripslashes($request['synonymsSelected'])));
Log::info('Filters and synonyms decoded', ['filter_items' => $filter_items, 'synonyms_selected' => $synonyms_selected]);
if ($synonyms_selected) {
$learning_product->synonyms()->sync($synonyms_selected);
}
$arrayTmp = [];
if ($filter_items) {
foreach ($filter_items as $key => $value) {
$arrayTmp[] = $value;
}
$filter_items = Arr::collapse($arrayTmp);
$filter_items = Arr::flatten($arrayTmp);
// Saves filter items associations with this learning product
$learning_product->filters()->delete();
foreach ($filter_items as $filter_item_id) {
$filter_association = new FilterItemsAssociation();
$filter_association->filter_item_id = $filter_item_id;
$learning_product->filters()->save($filter_association);
}
}
// if a file was uploaded as cover or tile, add them
if ($hasCover) {
$learning_product->addMediaFromRequest('cover')->toMediaCollection('learning_products_covers');
}
if ($hasTile) {
$learning_product->addMediaFromRequest('tile')->toMediaCollection('learning_products_tiles');
}
if ($is_draft) {
// 1st draft of the published product
$original_product_published = $this->learningProductService->get($request['parent_id']);
// If no cover has been attached before
if (!$hasCover && !$learning_product->cover) {
$image = $original_product_published->getMedia('learning_products_covers')->first();
if ($image) {
$learning_product->copyMedia($image->getPath())->toMediaCollection('learning_products_covers');
}
}
// If no tile has been attached before
if (!$hasTile && !$learning_product->tile) {
$image = $original_product_published->getMedia('learning_products_tiles')->first();
if ($image) {
$learning_product->copyMedia($image->getPath())->toMediaCollection('learning_products_tiles');
}
}
}
// ForceDelete the parent if draft published
if ($is_draft_published && $learning_product) {
$this->destroy($request['parent_id'], true);
}
Log::info('Learning product processed successfully', ['learning_product' => $learning_product]);
// Emit Event to update products
// broadcast(new \App\Events\ProductsCatalogUpdated);
if ($learning_product) {
return response()->json(new LearningProductResource($learning_product), 201);
} else {
return response()->json(['message' => 'Learning Product not found.'], 404);
}
} catch (\Exception $e) {
Log::error('Error in LearningProductController@store: ' . $e->getMessage(), ['exception' => $e]);
return response()->json(['message' => 'Internal Server Error'], 500);
}
}
public function show($id)
{
$learning_product = $this->learningProductService->getOneWithChildrenAndTrashed($id, [
'filters',
'filters.filter_item.filter',
'versions',
'accreditations',
'notifications',
'synonyms',
]);
return response()->json(new LearningProductResource($learning_product));
}
public function countAll()
{
return response()->json($this->learningProductService->countAll());
}
public function destroy(String $id, $forceDelete = false)
{
try {
Log::info('Destroy method called', ['id' => $id, 'forceDelete' => $forceDelete]);
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$learning_product = $this->learningProductService->get($id);
if (!$learning_product) {
return response()->json(['message' => 'Learning Product not found.'], 404);
}
// Verwijder gerelateerde records in de versions tabel
\DB::table('versions')->where('learning_product_id', $id)->delete();
if ($forceDelete) {
$learning_product->forceDelete();
} else {
$learning_product->delete();
}
Log::info('Learning product deleted successfully', ['id' => $id]);
return response()->json(null, 204);
} catch (\Exception $e) {
Log::error('Error in LearningProductController@destroy: ' . $e->getMessage(), ['exception' => $e]);
return response()->json(['message' => 'Internal Server Error'], 500);
}
}
public function clone(LearningProductId $request)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
if (!isset($request['product_id']) || !$request['product_id']) {
return response()->json(['message' => 'Product id missing.'], 400);
}
// get original product to clone
$original_product = $this->learningProductService->getOneWith($request['product_id'], [
'filters',
'filters.filter_item.filter',
'versions',
'accreditations',
'notifications',
'synonyms',
]);
// Return if not published
if (!$original_product->published) {
return response()->json([
'error' => 'You cannot duplicate a draft'
], 400);
}
// Return already has a draft
if ($original_product->draft) {
return response()->json(['message' => 'There is already a draft for this product'], 400);
}
// set as draft
$draft = $original_product->replicate();
$draft->parent_id = $original_product->id;
$draft->published = false;
// clone cover & tiles, finally save
$cover = $original_product->getMedia('learning_products_covers')->first();
$tile = $original_product->getMedia('learning_products_tiles')->first();
if ($cover) {
$draft
->copyMedia($cover->getPath())
->toMediaCollection('learning_products_covers');
}
if ($tile) {
$draft
->copyMedia($tile->getPath())
->toMediaCollection('learning_products_covers');
}
$draft->save();
// TODO: clone accreditations, versions too?
// Clone Filter Items
if ($original_product->filters()) {
$filter_items_ids = $original_product->filters->pluck('filter_item_id');
foreach ($filter_items_ids as $filter_item_id) {
$filter_association = new FilterItemsAssociation();
$filter_association->filter_item_id = $filter_item_id;
$draft->filters()->save($filter_association);
}
}
// Clone Synonyms
if ($original_product->synonyms()) {
$synonyms_ids = $original_product->synonyms->pluck('id');
$draft->synonyms()->sync($synonyms_ids);
}
return response()->json(null, 201);
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ManagementLinkRequest;
use App\Services\ManagementLinkService;
use App\Http\Requests\Member\ManagementLinkStore;
class ManagementLinkController extends Controller
{
private $managementLinkService;
public function __construct(ManagementLinkService $managementLinkService)
{
$this->managementLinkService = $managementLinkService;
}
public function index()
{
$management_links = $this->managementLinkService->getAll();
return response()->json($management_links, 201);
}
public function store(ManagementLinkService $request)
{
$management_links = $this->managementLinkService->save($request->all());
return response()->json($management_links, 201);
}
public function show($id)
{
$management_links = $this->managementLinkService->get($id);
return response()->json($management_links);
}
public function destroy(ManagementLinkStore $request)
{
$this->managementLinkService->delete($request->link_id);
return response()->json(null, 204);
}
public function storeManagementLink(ManagementLinkStore $request) {
$managementLink = [
'member_id' => $request->member_id
];
$link = $this->managementLinkService->save($managementLink);
return response()->json($request, 201);
}
public function changeManagementLink(ManagementLinkStore $request) {
$managementLink = [
'id' => $request->link_id,
$request->field => $request->value
];
$link = $this->managementLinkService->save($managementLink);
return response()->json($request, 201);
}
}

View File

@@ -0,0 +1,154 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Arr;
use App\Services\MemberService;
use App\Services\RevisionService;
use App\Http\Resources\MemberResource;
use App\Http\Requests\Member\MemberStore;
use App\Http\Requests\Member\RevisionStore;
use App\Repositories\Member;
use App\Repositories\User;
use App\Services\QueryBuilderService;
use Illuminate\Http\Request;
class MemberController extends Controller
{
private MemberService $memberService;
private RevisionService $revisionService;
private QueryBuilderService $queryBuilderService;
public function __construct(
MemberService $memberService,
RevisionService $revisionService,
QueryBuilderService $queryBuilderService
) {
$this->memberService = $memberService;
$this->revisionService = $revisionService;
$this->queryBuilderService = $queryBuilderService;
$this->middleware('auth:sanctum', ['except' => ['storeMemberRevisions']]);
}
public function index(Request $request)
{
$members = $this->queryBuilderService
->createQueryBuilder(Member::class, Member::class, $request)
->with([
'addresses',
'contacts',
'main_branch',
'management_links',
'revision',
'sub_branches',
'summaries',
'contributions',
'users',
])
->withTrashed()
->defaultSort('-id')
->get();
return response()->json(MemberResource::collection($members), 201);
}
public function store(MemberStore $request)
{
/** @var User */
$user = auth()->user();
$isSuperAdmin = $user->hasRole('super_admin');
$isAdmin = $user->hasRole('admin');
// $isOperator = $user->hasRole('operator');
// $isAdminOrOperator = $isAdmin || $isOperator;
// $isUserDelegated = $member->user_id === $user->id;
if (!$isSuperAdmin && !$isAdmin) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$hasLogo = isset($request['logo']) && $request->hasFile('logo');
$request_data = Arr::except($request->validated(), ['sub_branches']);
if (!isset($request_data['user_id']) || !is_int($request_data['user_id'])) {
$request_data['user_id'] = $user->id;
}
$member = $this->memberService->save($request_data);
if ($request->revisor_id && $request->revisor_id == $user->id) {
$member->revision->revisor_id = $user->id;
$member->revision->touch();
$member->revision->accepted_at = $member->revision->updated_at;
$member->revision->timestamps = false;
$member->revision->save();
}
$sub_branches = json_decode(html_entity_decode(stripslashes($request['sub_branches'])));
$member->sub_branches()->sync($sub_branches);
if ($hasLogo) $member->addMediaFromRequest('logo')->toMediaCollection('members_logos');
// Emit Event to update members
broadcast(new \App\Events\MembersUpdated);
return response()->json($member, 201);
}
public function storeMemberRevision(RevisionStore $request)
{
if ($request->user_id != auth()->user()->id) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$member = $this->memberService->get($request->member_id);
if (!$member) {
return response()->json(['message' => 'Member not found.'], 404);
}
if ($member->user_id != auth()->user()->id) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$hasLogo = isset($request['logo']) && $request->hasFile('logo');
$revision = $this->revisionService->save($request->validated());
if ($hasLogo) $member->addMediaFromRequest('logo')->toMediaCollection('members_logos');
// Emit Event to update members
broadcast(new \App\Events\MembersUpdated);
return response()->json($revision, 201);
}
public function show($id)
{
$member = $this->memberService->getOneWith($id, ['summaries', 'addresses', 'contacts', 'contributions', 'sub_branches', 'revision', 'management_links']);
return response()->json(new MemberResource($member));
}
public function destroy(String $id, $forceDelete = false)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isSuperAdminOrAdmin = $isSuperAdmin || $isAdmin;
if (!$isSuperAdminOrAdmin) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->memberService->delete($id, $forceDelete);
return response()->json(null, 204);
}
public function countAll()
{
return response()->json($this->memberService->countAll());
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Notifications\CustomNotification;
use App\Http\Resources\UserLoggedResource;
class NotificationController extends Controller
{
public function __construct()
{
$this->middleware('auth:sanctum');
}
public function markAsRead(Request $request)
{
$notification = auth()->user()->notifications()->find($request->id);
if ($notification) {
$notification->markAsRead();
return response()->json(new UserLoggedResource(auth()->user()));
}
}
public function markAsUnread(Request $request)
{
$notification = auth()->user()->notifications()->find($request->id);
if ($notification) {
$notification->read_at = null;
$notification->save();
return response()->json(new UserLoggedResource(auth()->user()));
}
}
public function delete(Request $request)
{
$notification = auth()->user()->notifications()->find($request->id);
if ($notification) {
$notification->delete();
return response()->json(new UserLoggedResource(auth()->user()));
}
}
public function test()
{
if (!auth()->user()) return;
$demo_notification = new CustomNotification(
'Subject',
'Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab dolores libero at dolorem unde, consequuntur sed eveniet totam aperiam aspernatur.'
);
auth()->user()->notify($demo_notification);
broadcast(new \App\Events\UserInfoUpdated(auth()->user()));
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace App\Http\Controllers;
class PingController extends Controller
{
public function index()
{
return response('', 200);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Http\Request;
class ResetPasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
protected function sendResetResponse(Request $request, $response)
{
return response(['message' => trans($response)]);
}
protected function sendResetFailedResponse(Request $request, $response)
{
return response(['error' => trans($response)], 422);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace App\Http\Controllers\Response;
use App\Http\Controllers\Error\ErrorInterface;
use Illuminate\Http\Response;
class ApiResponse
{
public static function success(
array $content,
int $status = Response::HTTP_OK,
array $headers = []
): Response
{
return static::determineResponse($content, $status, false, $headers);
}
private static function determineResponse(
array $content,
int $status,
bool $error,
array $headers = []
): Response
{
return response(
[
'error' => $error,
'status' => [
'code' => $status,
'text' => Response::$statusTexts[$status],
],
'content' => $content,
],
$status,
$headers,
);
}
public static function error(
ErrorInterface $error,
array $headers = []
): Response
{
return static::determineResponse(
[
'code' => $error->getErrorCode(),
'message' => $error->getErrorMessage(),
],
$error->getStatusCode(),
true,
$headers,
);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Http\Controllers;
use App\Services\RoleService;
class RoleController extends Controller
{
public function __construct(RoleService $roleService)
{
$this->roleService = $roleService;
}
public function index()
{
return $this->roleService->getAll();
}
}

View File

@@ -0,0 +1,148 @@
<?php
namespace App\Http\Controllers;
use App\Mail\MemberChanges;
use App\Services\MemberService;
use App\Services\SummaryService;
use App\Services\UserService;
use Illuminate\Support\Facades\Mail;
use App\Http\Requests\Member\SummaryStore;
class SummaryController extends Controller
{
private $summaryService;
private $memberService;
public function __construct(
MemberService $memberService,
UserService $userService,
SummaryService $summaryService
) {
$this->memberService = $memberService;
$this->summaryService = $summaryService;
$this->userService = $userService;
$this->middleware('auth:sanctum');
}
public function index()
{
$summaries = $this->summaryService->getAll();
return response()->json($summaries, 201);
}
public function store(SummaryStore $request)
{
$member = $this->memberService->get($request->member_id);
if (!$member) {
return response()->json(['message' => 'Member not found.'], 404);
}
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isSuperAdminOrAdmin = $isSuperAdmin || $isAdmin;
$isUserDelegated = $member->user_id === auth()->user()->id;
$isAppliedToAll = $request->has('toAll') ? true : false;
if (!$isSuperAdminOrAdmin && !$isUserDelegated) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$request_data = $request->validated();
$is_edit_mode = isset($request_data['id']);
$is_create_mode = !$is_edit_mode;
$summary = null;
if ($is_edit_mode) {
if ($isSuperAdminOrAdmin) {
$request_data['revisor_id'] = auth()->user()->id;
$request_data['approved_at'] = now();
}
$summary = $this->summaryService->get($request_data['id']);
$is_already_approved = $summary->approved_at;
if ($isUserDelegated && !$isSuperAdminOrAdmin && $is_already_approved) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
}
if ($isAppliedToAll && $is_create_mode) {
if ($isUserDelegated && !$isSuperAdminOrAdmin) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$members = $this->memberService->with(['summaries']);
// Store for all existing members
foreach ($members as $member) {
// If the member doesn't have that year set, store the record
if (!$member->summaries->contains('year', $request_data['year'])) {
$request_data['member_id'] = $member['id'];
// Gives back the summary to update the page
if ($request_data['member_id'] === $member['user_id']) {
$summary = $this->summaryService->save($request_data);
} else {
$this->summaryService->save($request_data);
}
}
}
} else {
$summary = $this->summaryService->save($request_data);
}
// If is a user delegated to make changes, send a mail
if ($isUserDelegated) {
// Get super admins & admins, send them an email
$super_admins_and_admins = $this->userService->getAllWithRoles(['super_admin', 'admin']);
$notification = (object) array();
$notification->member = $member;
$notification->subject = 'Er zijn wijzigingen doorgevoerd';
$notification->message = sprintf(
'De volgende wijzigingen kunnen worden beoordeeld, voor het volgende lid: <em>%s</em>',
$member->informal_name,
);
// Add emails to queue | * php artisan queue:listen
foreach ($super_admins_and_admins as $user) {
Mail::to($user)->send(new MemberChanges($notification));
}
}
return response()->json($summary, 201);
}
public function show($id)
{
$summary = $this->summaryService->get($id);
return response()->json($summary);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isSuperAdminOrAdmin = $isSuperAdmin || $isAdmin;
if (!$isSuperAdminOrAdmin) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->summaryService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace App\Http\Controllers;
use App\Services\SynonymService;
use App\Http\Requests\Learning\SynonymStore;
class SynonymController extends Controller
{
private $synonymService;
public function __construct(SynonymService $synonymService)
{
$this->synonymService = $synonymService;
$this->middleware('auth:sanctum', [
'except' => [
'index',
]
]);
}
public function index()
{
$synonyms = $this->synonymService->getAll();
return response()->json($synonyms, 201);
}
public function store(SynonymStore $request)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$synonym = $this->synonymService->save($request->all());
return response()->json($synonym, 201);
}
public function show($id)
{
$synonym = $this->synonymService->get($id);
return response()->json($synonym);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->synonymService->delete($id);
return response()->json(null, 204);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Http\Controllers;
use App\Services\MemberService;
use Illuminate\Http\Request;
class TypeController extends Controller
{
private MemberService $memberService;
public function __construct(MemberService $memberService)
{
$this->memberService = $memberService;
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
return response()->json($this->memberService->getValidTypes());
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Arr;
use App\Services\UserService;
use App\Http\Resources\UsersList;
use App\Http\Resources\UserResource;
use App\Http\Requests\User\UserStore;
use App\Http\Resources\UserLoggedResource;
class UserController extends Controller
{
private $userService;
public function __construct(UserService $userService)
{
$this->userService = $userService;
$this->middleware('auth:sanctum');
}
public function index()
{
$users = $this->userService->getWith(['roles']);
return response()->json(UserResource::collection($users), 200);
}
public function show($id)
{
$isAdmin = auth()->user()->hasRole('admin');
$isTheUserOwner = auth()->user()->id === (int) $id;
if (!$isAdmin && !$isTheUserOwner) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$user = $this->userService->getOneWith($id, ['roles']);
if ($user) {
return response()->json(new UserResource($user));
} else return response()->json(['message' => 'User not found.'], 404);
}
public function store(UserStore $request)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isEditingHimself = auth()->user()->id === (int) $request['id'];
if (!$isSuperAdmin && !$isEditingHimself) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$hasImage = isset($request['image']) && $request->hasFile('image');
$request_data = $hasImage ? Arr::except($request->validated(), ['image']) : $request->validated();
// only super admin can manage users and rules
$user = $this->userService->save($request_data, $isSuperAdmin);
if ($hasImage) {
$user->addMedia($request['image'])->toMediaCollection('profile_pics');
}
if ($user) {
return response()->json($isEditingHimself ? new UserLoggedResource($user) : new UserResource($user));
} else return response()->json(['message' => 'User not found.'], 404);
}
public function destroy(String $id)
{
if (!auth()->user()->hasRole('admin')) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->userService->delete($id);
return response()->json(null, 204);
}
public function getList()
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$users = $this->userService->getAll();
return response()->json(UsersList::collection($users), 200);
}
}

View File

@@ -0,0 +1,112 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Arr;
use App\Services\VersionService;
use App\Http\Requests\Learning\VersionStore;
use App\Repositories\FilterItemsAssociation;
class VersionController extends Controller
{
private $versionService;
public function __construct(VersionService $versionService)
{
$this->versionService = $versionService;
$this->middleware('auth:sanctum');
}
public function index()
{
$versions = $this->versionService->getAll();
return response()->json($versions, 201);
}
public function store(VersionStore $request)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
if ($request['filter_items']) {
$filter_items = Arr::collapse($request['filter_items']);
$filter_items = Arr::flatten($filter_items);
}
if ($request['checklists_selected']) {
$checklists_selected = $request['checklists_selected'];
}
$data = Arr::except($request->validated(), ['filter_items', 'checklists_selected']);
$version = $this->versionService->save($data);
if (isset($filter_items) && $filter_items) {
$version->filters()->delete();
foreach ($filter_items as $filter_item_id) {
$filter_association = new FilterItemsAssociation();
$filter_association->filter_item_id = $filter_item_id;
$version->filters()->save($filter_association);
}
}
if (isset($checklists_selected) && $checklists_selected) {
// Fetch all checklists ids already stored
$checklists_ids_stored = $version->checklists()->pluck('checklist_id');
// If an id from $checklists_ids_stored is not present in the uploaded checklists_selected, delete it
foreach ($checklists_ids_stored as $checklist_id_stored) {
if (!in_array($checklist_id_stored, $checklists_selected)) {
$version->checklists()->where('checklist_id', $checklist_id_stored)->delete();
}
}
// If a checklist from the uploaded is not present in $version->checklists(), create
foreach ($checklists_selected as $checklist_selected) {
if (!in_array($checklist_selected, $checklists_ids_stored->toArray())) {
$version->checklists()->create([
'user_id' => auth()->user()->id,
'version_id' => $version->id,
'checklist_id' => $checklist_selected,
]);
}
}
}
return response()->json($version->load(['filters', 'checklists']), 201);
}
public function show($id)
{
$version = $this->versionService->get($id);
return response()->json($version);
}
public function destroy($id)
{
$isSuperAdmin = auth()->user()->hasRole('super_admin');
$isAdmin = auth()->user()->hasRole('admin');
$isOperator = auth()->user()->hasRole('operator');
if (!$isSuperAdmin && !$isAdmin && !$isOperator) {
return response()->json(['message' => 'You have no rights to do this'], 401);
}
$this->versionService->delete($id);
return response()->json(null, 204);
}
}

73
app/Http/Kernel.php Normal file
View File

@@ -0,0 +1,73 @@
<?php
namespace App\Http;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\HandleCors::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
protected function schedule(Schedule $schedule)
{
$schedule->command('backup:clean')->daily()->at('02:00');
$schedule->command('backup:run')->daily()->at('02:30');
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* @param \Illuminate\Http\Request $request
* @return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
class CheckForMaintenanceMode extends Middleware
{
/**
* The URIs that should be reachable while maintenance mode is enabled.
*
* @var array
*/
protected $except = [
//
];
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array
*/
protected $except = [
//
];
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Middleware;
use App\Services\CorsService;
use Illuminate\Http\Request;
class HandleCors
{
private CorsService $corsService;
public function __construct(CorsService $corsService)
{
$this->corsService = $corsService;
}
public function handle(Request $request, \Closure $next)
{
/** @var \Illuminate\Http\Response */
$response = $next($request);
if ($this->corsService->isRequestValid($request)) {
$this->corsService->addHeadersToResponse($response);
}
return $response;
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Http\Middleware;
use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect(RouteServiceProvider::HOME);
}
return $next($request);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
class TrimStrings extends Middleware
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array
*/
protected $except = [
'password',
'password_confirmation',
];
}

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Middleware;
use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array|string
*/
protected $proxies;
/**
* The headers that should be used to detect proxies.
*
* @var int
*/
protected $headers = Request::HEADER_X_FORWARDED_ALL;
}

View File

@@ -0,0 +1,17 @@
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
//
];
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Component;
use Illuminate\Foundation\Http\FormRequest;
class ComponentSort extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"model_id" => 'required',
"model" => 'required',
"components_ids" => 'required',
];
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests\Component;
use Illuminate\Foundation\Http\FormRequest;
class ComponentStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required',
'description' => '',
'content' => '',
'component_type_id' => 'required',
];
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Component;
use Illuminate\Foundation\Http\FormRequest;
class ComponentSync extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"model_id" => 'required',
"model" => 'required',
"components_ids" => '',
];
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Filter;
use Illuminate\Foundation\Http\FormRequest;
class FilterItemStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'required_without:filter_id|numeric',
"filter_id" => 'required_without:id|numeric',
"title" => 'required|max:255',
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Filter;
use Illuminate\Foundation\Http\FormRequest;
class FilterStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"title" => 'required|max:255',
];
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\Learning;
use Illuminate\Foundation\Http\FormRequest;
class AccreditationStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"learning_product_id" => 'required|numeric',
'credits' => 'required',
'date_start' => '',
'date_end' => '',
'filter_items' => '',
];
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace App\Http\Requests\Learning;
use Illuminate\Foundation\Http\FormRequest;
class CourseNotificationStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"learning_product_id" => 'required|numeric',
'date' => 'required',
'sent' => '',
'time' => 'required',
'emails' => 'required',
'users' => 'required',
'subject' => 'required',
'message' => 'required',
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Learning;
use Illuminate\Foundation\Http\FormRequest;
class LearningProductId extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"product_id" => 'required|numeric',
];
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace App\Http\Requests\Learning;
use Illuminate\Foundation\Http\FormRequest;
class LearningProductStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"parent_id" => 'sometimes|numeric',
"title" => 'required|max:255',
'description' => 'max:255',
'video' => 'max:255',
'code' => 'required|max:255',
'seo_title' => 'required|max:255',
'meta_description' => 'max:255',
'url' => 'max:255',
'published' => '',
'lead_time' => '',
'short_description' => '',
'learning_goals' => '',
'review' => '',
'certification' => '',
'extra_information' => '',
'target_audience' => '',
'quality_standards' => '',
'in_the_picture' => '',
'in_the_picture_start' => 'required_if:in_the_picture,1',
'in_the_picture_end' => 'required_if:in_the_picture,1',
'owner' => '',
'partner' => '',
'supplier' => '',
'contract_agreements' => '',
'tile' => 'sometimes|mimes:jpeg,jpg,png|max:2048',
'cover' => 'sometimes|mimes:jpeg,jpg,png|max:2048',
'prognosis_members' => '',
'prognosis_attendees' => '',
'sharepoint_link' => 'max:500',
'support_link' => 'max:500',
'support_tickets_link' => 'max:500',
'for_members' => '',
'third_party_training' => '',
'voor_opleiders' => '',
'filtersGrouped' => '',
'synonymsSelected' => '',
];
}
public function messages()
{
return [
'title.required' => 'De titel is verplicht.',
'code.required' => 'De productcode is verplicht',
'seo_title.required' => 'De SEO title is verplicht',
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Http\Requests\Learning;
use Illuminate\Foundation\Http\FormRequest;
class SynonymStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"title" => 'required',
];
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace App\Http\Requests\Learning;
use Illuminate\Foundation\Http\FormRequest;
class VersionStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.Nc
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"learning_product_id" => 'required|numeric',
'filter_items' => '',
'version_number' => 'required',
'release_start' => 'required',
'release_end' => '',
'release_planning_date' => '',
'release_planning_description' => '',
'technical_information' => '',
'checklists_selected' => '',
];
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace App\Http\Requests\Member;
use Illuminate\Foundation\Http\FormRequest;
class AddressStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"member_id" => 'required|numeric',
'indicating' => '',
'type' => 'required|max:255',
'first_name_contact_person' => '',
'last_name_contact_person' => '',
'infix' => '',
'email' => 'required_if:type,==,invoice',
'phone' => '',
'address' => '',
'postal' => '',
'city' => '',
'title_contact_person' => '',
'initials_contact_person' => '',
'middle_name_contact_person' => '',
'job_title_contact_person' => '',
'house_number' => '',
'country' => '',
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Member;
use Illuminate\Foundation\Http\FormRequest;
class BranchStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"title" => 'required|max:255',
];
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Http\Requests\Member;
use Illuminate\Foundation\Http\FormRequest;
class ContactStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"member_id" => 'required|numeric',
'function' => '',
'salutation' => '',
'initials' => '',
'firstname' => 'required',
'middlename' => '',
'lastname' => 'required',
'email' => 'required|email',
'email2' => 'nullable|email',
'email3' => 'nullable|email',
'phone' => '',
'job_title' => '',
'mobile' => '',
'address_id' => 'nullable|numeric',
];
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Http\Requests\Member;
use Illuminate\Foundation\Http\FormRequest;
class ContributionStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"member_id" => 'required|numeric',
"year" => 'required|numeric',
"contribution" => 'required|numeric',
"toAll" => '',
];
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Http\Requests\Member;
use Illuminate\Foundation\Http\FormRequest;
class ManagementLinkStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'id' => 'sometimes|numeric',
'member_id' => 'sometimes|numeric',
'title' => '',
'url' => '',
'target' => '',
];
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace App\Http\Requests\Member;
use Illuminate\Foundation\Http\FormRequest;
class MemberStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"user_id" => 'sometimes|numeric',
"branch_id" => 'numeric',
"sub_branches" => '',
'type' => '',
"informal_name" => 'required|max:255',
"formal_name" => 'required|max:255',
"kvk_number" => 'required|numeric',
'website' => '',
'logo' => 'sometimes|mimes:jpeg,jpg,png|max:2048',
'show_on_website' => '',
'helpdesk_department' => '',
'helpdesk_contact_person' => '',
'helpdesk_email' => '',
'helpdesk_phone' => '',
'info_department' => '',
'info_contacteperson' => '',
'info_email' => '',
'info_phone' => '',
'info_address' => '',
'info_housenumber' => '',
'info_postal' => '',
'info_city' => '',
'info_country' => '',
'info_link' => '',
'more_info_link' => '',
'start_membership' => '',
'end_membership' => '',
'contribution' => '',
'invoice_number' => '',
];
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests\Member;
use Illuminate\Foundation\Http\FormRequest;
class RevisionStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"member_id" => 'sometimes|numeric',
"user_id" => 'numeric',
"data" => 'required'
];
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace App\Http\Requests\Member;
use Illuminate\Foundation\Http\FormRequest;
class SummaryStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"member_id" => 'required|numeric',
"year" => 'required|numeric',
"real_number_last_year" => 'required|numeric',
"estimated_number_next_year" => 'required|numeric',
"toAll" => '',
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Page;
use Illuminate\Foundation\Http\FormRequest;
class ComponentPageDelete extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"page_id" => 'required|numeric',
"component_id" => 'required',
];
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace App\Http\Requests\Page;
use Illuminate\Foundation\Http\FormRequest;
class ComponentPageStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"page_id" => 'required|numeric',
"content" => '',
"component_type_id" => 'required',
];
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Requests\Page;
use Illuminate\Foundation\Http\FormRequest;
class PageStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"title" => 'required|max:255',
"subtitle" => 'max:255',
"slug" => 'max:255',
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\User;
use Illuminate\Foundation\Http\FormRequest;
class Login extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'email' => 'required|email',
'password' => 'required',
];
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Http\Requests\User;
use Illuminate\Foundation\Http\FormRequest;
class UserStore extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
"id" => 'sometimes|numeric',
"first_name" => 'required|max:255',
"last_name" => 'required|max:255',
'email' => 'required|email',
'password' => 'sometimes|confirmed|min:8',
'roles' => '',
'image' => 'sometimes|mimes:jpeg,jpg,png|max:2048',
];
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class FiltersResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'multiple' => $this->type,
'items' => $this->whenLoaded('items'),
'items_count' => $this->items ? $this->items_count : null,
'slug' => $this->slug,
];
}
}

View File

@@ -0,0 +1,136 @@
<?php
namespace App\Http\Resources;
use Illuminate\Support\Arr;
use Illuminate\Http\Resources\Json\JsonResource;
class LearningProductResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$filtersGrouped = [];
// merging accreditation filters to allow the filtering in frontend
if (isset($this->accreditations)) {
foreach ($this->accreditations as $accreditation) {
foreach ($accreditation->filters as $filter) {
$filtersGrouped[$filter->filter_item->filter_id][] = $filter->filter_item_id;
// To avoid double values
$filtersGrouped[$filter->filter_item->filter_id] = array_unique($filtersGrouped[$filter->filter_item->filter_id]);
}
}
}
if (isset($this->filters)) {
foreach ($this->filters as $filter) {
$filtersGrouped[$filter->filter_item->filter_id][] = $filter->filter_item_id;
// To avoid double values
$filtersGrouped[$filter->filter_item->filter_id] = array_unique($filtersGrouped[$filter->filter_item->filter_id]);
}
}
$filtersFlattened = [
'status' => null,
'product_type' => null,
'theme' => null,
'course' => null,
];
foreach ($filtersFlattened as $title => $value) {
if (isset($this->filters)) {
foreach ($this->filters as $filter) {
if (
$filter->filter_item->filter->title === $title
&& $filter->filter_item->title
) {
$filtersFlattened[$title][] = $filter->filter_item->title;
}
}
if ($filtersFlattened[$title]) {
sort($filtersFlattened[$title]);
$filtersFlattened[$title] = implode(", ", $filtersFlattened[$title]);
}
}
}
return [
'id' => $this->id,
'parent_id' => $this->parent_id,
'title' => $this->title,
'description' => $this->description,
'video' => $this->video,
'code' => $this->code,
'published' => $this->published,
'lead_time' => $this->lead_time,
'short_description' => $this->short_description,
'learning_goals' => $this->learning_goals,
'review' => $this->review,
'certification' => $this->certification,
'extra_information' => $this->extra_information,
'target_audience' => $this->target_audience,
'quality_standards' => $this->quality_standards,
'in_the_picture' => $this->in_the_picture,
'in_the_picture_start' => $this->in_the_picture_start,
'in_the_picture_end' => $this->in_the_picture_end,
'owner' => $this->owner,
'partner' => $this->partner,
'supplier' => $this->supplier,
'contract_agreements' => $this->contract_agreements,
'draft' => $this->draft ? $this->draft : null,
'slug' => $this->slug,
'seo_title' => $this->seo_title,
'meta_description' => $this->meta_description,
'url' => $this->url,
'cover' => [
'full' => $this->getFirstMediaUrl('learning_products_covers'),
'thumb' => $this->getFirstMediaUrl('learning_products_covers', 'thumb')
],
'tile' => [
'full' => $this->getFirstMediaUrl('learning_products_tiles'),
'thumb' => $this->getFirstMediaUrl('learning_products_tiles', 'thumb')
],
'prognosis_members' => $this->prognosis_members,
'prognosis_attendees' => $this->prognosis_attendees,
'sharepoint_link' => $this->sharepoint_link,
'support_link' => $this->support_link,
'support_tickets_link' => $this->support_tickets_link,
'filters' => $this->whenLoaded('filters'),
'accreditations' => $this->whenLoaded('accreditations'),
'notifications' => $this->whenLoaded('notifications'),
'filtersGrouped' => (object) $filtersGrouped,
'filterItemsSelected' => Arr::flatten(get_object_vars((object) $filtersGrouped)),
'versions' => $this->whenLoaded('versions'),
'synonyms' => $this->synonyms,
'for_members' => $this->for_members,
'third_party_training' => $this->third_party_training,
'voor_opleiders' => $this->voor_opleiders,
// Returns a concatenated string with all the "theme" titles attached
'theme' => $filtersFlattened['theme'],
'status' => $filtersFlattened['status'],
'course' => $filtersFlattened['course'],
'product_type' => $filtersFlattened['product_type'],
'created_at' => $this->created_at->toDateTimeString(),
'updated_at' => $this->updated_at->toDateTimeString(),
'deleted_at' => $this->deleted_at ? $this->deleted_at->toDateTimeString() : null,
];
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class MemberResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'slug' => $this->slug,
'type' => $this->type,
'branch_id' => $this->branch_id,
'main_branch' => $this->main_branch->title ?? null,
'informal_name' => $this->informal_name,
'formal_name' => $this->formal_name,
'kvk_number' => $this->kvk_number,
'website' => $this->website,
'logo' => [
'full' => $this->getFirstMediaUrl('members_logos'),
'thumb' => $this->getFirstMediaUrl('members_logos', 'thumb')
],
'show_on_website' => $this->show_on_website,
'helpdesk_department' => $this->helpdesk_department,
'helpdesk_contact_person' => $this->helpdesk_contact_person,
'helpdesk_email' => $this->helpdesk_email,
'helpdesk_phone' => $this->helpdesk_phone,
'info_department' => $this->info_department,
'info_contacteperson' => $this->info_contacteperson,
'info_email' => $this->info_email,
'info_phone' => $this->info_phone,
'info_address' => $this->info_address,
'info_housenumber' => $this->info_housenumber,
'info_postal' => $this->info_postal,
'info_city' => $this->info_city,
'info_country' => $this->info_country,
'info_link' => $this->info_link,
'more_info_link' => $this->more_info_link,
'summaries' => $this->whenLoaded('summaries'),
'addresses' => $this->whenLoaded('addresses'),
'contacts' => $this->whenLoaded('contacts'),
'contributions' => $this->whenLoaded('contributions'),
'management_links' => $this->whenLoaded('management_links'),
'sub_branches' => $this->whenLoaded('sub_branches'),
'user_ids' => $this->relationLoaded('users')
? $this->users->pluck('id')
: [],
'revision' => $this->whenLoaded('revision'),
'start_membership' => $this->start_membership,
'end_membership' => $this->end_membership,
'contribution' => $this->contribution,
'invoice_number' => $this->invoice_number,
'created_at' => $this->created_at->toDateTimeString(),
'updated_at' => $this->updated_at ? $this->updated_at->toDateTimeString() : null,
'deleted_at' => $this->deleted_at ? $this->deleted_at->toDateTimeString() : null,
];
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class PageResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'subtitle' => $this->subtitle,
'published_at' => $this->updated_at->toDateTimeString(),
'created_at' => $this->updated_at->toDateTimeString(),
'updated_at' => $this->created_at->toDateTimeString(),
'slug' => $this->slug,
'components' => $this->whenLoaded('components'),
];
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserLoggedResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'fullName' => $this->fullName,
'email' => $this->email,
'created_at' => $this->updated_at->toDateTimeString(),
'updated_at' => $this->created_at->toDateTimeString(),
'last_login_at' => $this->last_login_at,
'logged_at' => $this->logged_at,
'roles' => $this->roles,
'isMemberEditor' => $this->isMemberEditor,
'image' => [
'full' => $this->getFirstMediaUrl('profile_pics'),
'thumb' => $this->getFirstMediaUrl('profile_pics', 'thumb')
],
'notifications' => $this->when($this->notifications, $this->notifications),
'membersManagedCount' => $this->when($this->members, $this->members->count()),
];
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'fullName' => $this->fullName,
'email' => $this->email,
'created_at' => $this->updated_at->toDateTimeString(),
'updated_at' => $this->created_at->toDateTimeString(),
'roles' => $this->roles,
'isMemberEditor' => $this->isMemberEditor,
'image' => [
'full' => $this->getFirstMediaUrl('profile_pics'),
'thumb' => $this->getFirstMediaUrl('profile_pics', 'thumb')
]
];
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UsersList extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'fullName' => $this->fullName,
];
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use League\HTMLToMarkdown\HtmlConverter;
class CourseNotificationMail extends Mailable
{
use Queueable, SerializesModels;
public $email;
public $notification;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($notification)
{
$this->notification = $notification;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
$converter = new HtmlConverter();
$this->notification->message = $converter->convert($this->notification->message);
$link = env('APP_URL_FRONTEND', 'http://localhost:3000') . "/manager/learning/" . $this->notification->learning_product->slug;
return $this->from(env('MAIL_FROM_ADDRESS'))
->with([
'notification' => $this->notification,
'link' => $link
])
->markdown('emails.courses.notification');
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use League\HTMLToMarkdown\HtmlConverter;
class MemberChanges extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
public $notification;
public $email;
public $subject = 'Wijzigingen in MijnGGZ Ecademy';
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($notification)
{
$this->notification = $notification;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
$converter = new HtmlConverter();
$this->notification->message = $converter->convert($this->notification->message);
$link = env('APP_URL_FRONTEND', 'http://localhost:3000') . "/manager/members/" . $this->notification->member->slug;
return $this->from(env('MAIL_FROM_ADDRESS'))
->with([
'notification' => $this->notification,
'link' => $link
])
->markdown('emails.members.hasChanges');
}
}

View File

@@ -0,0 +1,69 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class CustomNotification extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($subject, $message)
{
$this->subject = $subject;
$this->message = $message;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return [
// 'mail',
'database',
'broadcast'
];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
'subject' => $this->subject,
'message' => $this->message,
];
}
}

View File

@@ -0,0 +1,71 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Support\Facades\Lang;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class PasswordResetNotification extends Notification
{
use Queueable;
public $token;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct($token)
{
$this->token = $token;
}
/**
* 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)
{
$urlToResetForm = sprintf(
'%s/auth/password-reset?token=%s',
config('app.frontend_url', '#'),
urlencode($this->token),
);
return (new MailMessage)
->subject('Opnieuw instellen van wachtwoord')
->line('Je hebt aangegeven dat je je wachtwoord bent vergeten.
Ga naar MijnGGZecademy en stel jouw nieuwe wachtwoord in.')
->action('Stel je wachtwoord in', $urlToResetForm);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class UserNotification extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return [
'broadcast',
'database',
];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
'message' => 'User Notification',
];
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
// 'App\Model' => 'App\Policies\ModelPolicy',
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Broadcast;
use Illuminate\Support\ServiceProvider;
class BroadcastServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Broadcast::routes(['middleware' => ['auth:sanctum']]);
require base_path('routes/channels.php');
}
}

Some files were not shown because too many files have changed in this diff Show More