Mohammad Akbari
4 years ago
27 changed files with 972 additions and 2 deletions
-
1app/Enums/business.php
-
1app/Enums/comment.php
-
1app/Enums/levels.php
-
1app/Enums/log.php
-
1app/Enums/post.php
-
1app/Enums/roles.php
-
1app/Enums/service.php
-
1app/Enums/status.php
-
56app/Enums/tables.php
-
1app/Enums/ticket.php
-
1app/Enums/user.php
-
58app/Utilities/Exceptions/Handler.php
-
1app/Utilities/Helpers/enum.php
-
1app/Utilities/Helpers/http.php
-
1app/Utilities/Helpers/index.php
-
244app/Utilities/Helpers/permission.php
-
1app/Utilities/Jobs/AsyncCall.php
-
83app/Utilities/Logger/CreateCustomLogger.php
-
37app/Utilities/Logger/LogServiceRecordProcessor.php
-
1app/Utilities/Middlewares/BindBusinessInfo.php
-
254app/Utilities/Models/Model.php
-
138app/Utilities/Models/ReportableRelation.php
-
1app/Utilities/Providers/AuthServiceProvider.php
-
49app/Utilities/Providers/HiLibraryServiceProvider.php
-
2config/amqp.php
-
2config/logging.php
-
35docker-compose.yml
@ -0,0 +1 @@ |
|||
<?php
return [
'fee' => [
'user' => 100,
'file' => 200,
]
]; |
@ -0,0 +1 @@ |
|||
<?php
return [
'status' => [
'reject' => [
'id' => 10,
'label' => 'رد'
],
'approve' => [
'id' => 20,
'label' => 'تایید'
],
]
]; |
@ -0,0 +1 @@ |
|||
<?php
return [
'owner' => [
'id' => 4,
'name' => 'Owner',
'label' => 'صاحب'
],
'admin' => [
'id' => 3,
'name' => 'Admin',
'label' => 'مدیر'
],
'colleague' => [
'id' => 2,
'name' => 'Colleague',
'label' => 'همکار'
],
'guest' => [
'id' => 1,
'name' => 'Guest',
'label' => 'مهمان'
],
'inactive' => [
'id' => 0,
'name' => 'Inactive',
'label' => 'غیر فعال'
],
]; |
@ -0,0 +1 @@ |
|||
<?php
use App\User;
use App\Business;
use App\Project;
use App\Task;
use App\SpentHour;
return [
'types' => [
User::class => 10,
Business::class => 20,
Project::class => 30,
Task::class => 40,
Spenthour::class => 50,
],
'actions' => [
'created' => 10,
'updated' => 20,
'deleted' => 30,
'restored' => 40,
],
]; |
@ -0,0 +1 @@ |
|||
<?php
return [
'status' => [
'draft' => [
'id' => 10,
'label' => 'پیش نویس'
],
'review' => [
'id' => 20,
'label' => 'در حال بررسی'
],
'published' => [
'id' => 30,
'label' => 'منتشر'
],
'trashed' => [
'id' => 40,
'label' => 'حذف'
],
]
]; |
@ -0,0 +1 @@ |
|||
<?php
return [
'hidden' => [
'id' => 0,
'label' => 'غیر فعال'
],
'guest' => [
'id' => 1,
'label' => 'میهمان'
],
'Colleague' => [
'id' => 2,
'label' => 'همکار'
],
'senior' => [
'id' => 3,
'label' => 'معاون'
],
'manager' => [
'id' => 4,
'label' => 'مدیر'
],
]; |
@ -0,0 +1 @@ |
|||
<?php
return [
'post' => [
'file' => [
'orphanage' => [
'id' => 'orphanage',
'label' => 'دادههای موقت',
]
]
]
]; |
@ -0,0 +1 @@ |
|||
<?php
return [
'states' => [
'inactive' => [
'id' => 0,
'label' => 'غیر فعال',
'name' => 'Inactive'
],
'active' => [
'id' => 1,
'label' => 'فعال',
'name' => 'Active'
],
'close' => [
'id' => 2,
'label' => 'بسته',
'name' => 'Close'
],
'done' => [
'id' => 3,
'label' => 'انجام شده',
'name' => 'Done'
],
],
]; |
@ -0,0 +1,56 @@ |
|||
<?php |
|||
|
|||
return [ |
|||
|
|||
//Main Table's
|
|||
'businesses' => [ |
|||
'id' => 10, |
|||
'name' => 'Businesses' |
|||
], |
|||
'projects' => [ |
|||
'id' => 20, |
|||
'name' => 'Projects' |
|||
], |
|||
'sprints' => [ |
|||
'id' => 30, |
|||
'name' => 'Sprints' |
|||
], |
|||
'statuses' => [ |
|||
'id' => 40, |
|||
'name' => 'Statuses' |
|||
], |
|||
'systems' => [ |
|||
'id' => 50, |
|||
'name' => 'Systems' |
|||
], |
|||
'workflows' => [ |
|||
'id' => 60, |
|||
'name' => 'Workflows' |
|||
], |
|||
'tags' => [ |
|||
'id' => 70, |
|||
'name' => 'Tags' |
|||
], |
|||
'tasks' => [ |
|||
'id' => 80, |
|||
'name' => 'Tasks' |
|||
], |
|||
'works' => [ |
|||
'id' => 90, |
|||
'name' => 'Works' |
|||
], |
|||
|
|||
//Relation Table's
|
|||
'business_user' => [ |
|||
'id' => 210, |
|||
'name' => 'BusinessUser' |
|||
], |
|||
'project_user' => [ |
|||
'id' => 220, |
|||
'name' => 'ProjectUser' |
|||
], |
|||
'tag_task' => [ |
|||
'id' => 230, |
|||
'name' => 'TagTask' |
|||
], |
|||
]; |
@ -0,0 +1 @@ |
|||
<?php
return [
'type' => [
'sale' => [
'id' => 1,
'label' => 'فروش',
],
'support' => [
'id' => 2,
'label' => 'پشتیبانی'
]
],
'category' => [
'webdesign-sale' => [
'id' => 1,
'label' => 'طراحی سایت',
'type' => 1
],
'seo-sale' => [
'id' => 2,
'label' => 'فروش سئو',
'type' => 1
],
'webdesign-support' => [
'id' => 3,
'label' => 'پشتیبانی طراحی سایت',
'type' => 2
]
],
'status' => [
'active' => [
'id' => 1,
'label' => 'فعال'
],
'close' => [
'id' => 2,
'label' => 'بسته'
]
]
]; |
@ -0,0 +1 @@ |
|||
<?php
return [
'type' => [
'guest' => [
'id' => 1,
'label' => 'مهمان'
],
'user' => [
'id' => 2,
'label' => 'کاربر'
],
'service' => [
'id' => 3,
'label' => 'سرویس'
]
],
'status' => [
'desable' => [
'id' => 0,
'label' => 'غیر فعال'
],
'active' => [
'id' => 1,
'label' => 'فعال'
]
],
'permissions' => [
// user
'user-user-create',
'user-user-view-any',
'user-user-update-own',
'user-user-update-any',
'user-user-role-own',
'user-user-role-any',
'user-role-create',
'user-role-view-any',
// ticket
'ticket-ticket-create',
'ticket-ticket-view-any',
'ticket-ticket-reply-any',
// post
'post-post-create',
'post-post-view-publish',
'post-post-view-any',
'post-post-view-own',
'post-post-update-own',
'post-post-update-any',
'post-post-delete-own',
'post-post-delete-any',
// tag
'post-tag-update-any',
'post-tag-create',
'post-tag-delete-any',
// taxonomies
'post-taxonomy-view-any',
'post-taxonomy-update-any',
'post-taxonomy-create',
'post-taxonomy-delete-any',
// comments
'post-comment-view-any',
'post-comment-view-published',
'post-comment-view-own',
'post-comment-create',
'post-comment-update-any',
'post-comment-delete-any',
]
]; |
@ -0,0 +1,58 @@ |
|||
<?php |
|||
|
|||
namespace App\HiLib\Exceptions; |
|||
|
|||
use Throwable; |
|||
use ReflectionClass; |
|||
use ReflectionMethod; |
|||
use Illuminate\Support\Facades\Log; |
|||
use Illuminate\Validation\ValidationException; |
|||
use Illuminate\Auth\Access\AuthorizationException; |
|||
use Illuminate\Database\Eloquent\ModelNotFoundException; |
|||
use Laravel\Lumen\Exceptions\Handler as ExceptionHandler; |
|||
use Symfony\Component\HttpKernel\Exception\HttpException; |
|||
|
|||
class Handler extends ExceptionHandler |
|||
{ |
|||
/** |
|||
* A list of the exception types that should not be reported. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $dontReport = [ |
|||
AuthorizationException::class, |
|||
HttpException::class, |
|||
ModelNotFoundException::class, |
|||
ValidationException::class, |
|||
]; |
|||
|
|||
public function report(Throwable $exception) |
|||
{ |
|||
// A trick that I took from Laravel macroable trait
|
|||
$methods = (new ReflectionClass($exception))->getMethods( |
|||
ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED |
|||
); |
|||
|
|||
|
|||
$result = []; |
|||
foreach ($methods as $method) { |
|||
// invoke the method so we can collect the result of execution it
|
|||
$result[$method->name] = $method->invoke($exception); |
|||
} |
|||
|
|||
// Clear the unnecessary method
|
|||
unset($result['getTrace']); |
|||
unset($result['__toString']); |
|||
|
|||
// clear the null values then encode it as json
|
|||
// so we can decode it as an object in the Monolog Processor
|
|||
$result = json_encode(array_filter($result)); |
|||
|
|||
return Log::emergency($result); |
|||
} |
|||
|
|||
public function render($request, Throwable $exception) |
|||
{ |
|||
return parent::render($request, $exception); |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
<?php
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
if (! function_exists('enum')) {
function enum($key)
{
// add a dot at the end of string to prevent undefined offset
$key .= Str::of($key)->contains(".") ? "" : ".";
// the first parameter of all enum keys are its filename
[$filename, $key] = explode(".", $key, 2);
// because we do not want to load the file every time use require
$enums = require __DIR__ . "/../Enums/$filename.php";
// if the key that user provided not exists then null return
$enums = Arr::get($enums, $key, null);
// if enum null means that key not found
throw_if($enums === null, 'Exception', "Undefined enum '{$key}'");
// if enum value is array its mean that user want to use it as collection
return is_array($enums) ? collect($enums) : $enums;
}
} |
@ -0,0 +1 @@ |
|||
<?php
use App\Jobs\AsyncCall;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Http;
use Symfony\Component\HttpFoundation\Request;
if (!function_exists('get')) {
function get(string $service, string $path, array $data, ?string $queue = null)
{
return call(Request::METHOD_GET, $service, $path, $data, $queue);
}
}
if (!function_exists('post')) {
function post(string $service, string $path, array $data, ?string $queue = null)
{
return call(Request::METHOD_POST, $service, $path, $data, $queue);
}
}
if (!function_exists('put')) {
function put(string $service, string $path, array $data, ?string $queue = null)
{
return call(Request::METHOD_PUT, $service, $path, $data, $queue);
}
}
if (!function_exists('delete')) {
function delete(string $service, string $path, array $data, ?string $queue = null)
{
return call(Request::METHOD_DELETE, $service, $path, $data, $queue);
}
}
if (!function_exists('call')) {
/**
* @return \Illuminate\Http\Client\Response
*/
function call(string $method, string $service, string $path, array $data, ?string $queue = null)
{
// token of this service for send data to other service
$token = 'YT76Nt2ofTbmkiP0ubvnlwOJLBtglA3UubjRhieTiTVP7jGPNX0RlueVOgIc';
// url for reaching the target service
$baseUrl = config("services.$service");
// create a pending request for this url
$pendingRequest = Http::retry(3, 100);
// if command data contain file, then it will be attached to the pending request
foreach ($data as $piece) {
if ($piece instanceof UploadedFile) {
$pendingRequest->attach($piece->getFilename(), $piece);
}
}
// if queue set then queue this command
if ($queue !== null) {
return dispatch(new AsyncCall(...func_get_args()));
}
try {
// otherwise execute the pending request
return $pendingRequest
->withToken($token)
->withoutRedirecting()
->withoutVerifying()
->$method($path, $data);
} catch (Throwable $thr) {
return $thr->response;
}
}
} |
@ -0,0 +1 @@ |
|||
<?php
use Illuminate\Support\Str;
$helpers = scandir(__DIR__);
foreach ($helpers as $helper) {
$filename = Str::of($helper)->trim(".");
if ($filename->isEmpty()) {
continue;
}
require_once (string) $filename;
} |
@ -0,0 +1,244 @@ |
|||
<?php |
|||
|
|||
use Illuminate\Http\Response; |
|||
|
|||
if (!function_exists('businessInfoIsEmpty')) { |
|||
function businessInfoIsEmpty($userId) |
|||
{ |
|||
return !isset(request('_business_info')['members'][$userId]); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('permit')) { |
|||
function permit($actionName = null, $ids = []) |
|||
{ |
|||
throw_if($actionName === null, '$actionName must not be null.'); |
|||
|
|||
$response = call_user_func($actionName, $ids); |
|||
|
|||
if ($response === false) { |
|||
abort(Response::HTTP_FORBIDDEN); |
|||
} |
|||
|
|||
} |
|||
} |
|||
|
|||
|
|||
if (!function_exists('can')) { |
|||
function can($actionName = null, $ids = []) |
|||
{ |
|||
throw_if($actionName === null, '$actionName must not be null.'); |
|||
|
|||
return call_user_func($actionName, $ids); |
|||
} |
|||
} |
|||
|
|||
|
|||
if (!function_exists('isOwner')) { |
|||
function isOwner() |
|||
{ |
|||
return request('_business_info')['users'][auth()->user()->id]['owner'] == true; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Business Permit |
|||
*/ |
|||
|
|||
if (!function_exists('businessAccess')) { |
|||
function businessAccess($ids) |
|||
{ |
|||
return isset(request('_business_info')['info']['users'][$ids['user_id']?? auth()->id()]); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isBusinessOwner')) { |
|||
function isBusinessOwner($ids) |
|||
{ |
|||
return businessAccess($ids) && request('_business_info')['info']['users'][$ids['user_id'] ?? auth()->id()]['level'] == enum('levels.owner.id'); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isAtLeastBusinessAdmin')) { |
|||
function isAtLeastBusinessAdmin($ids) |
|||
{ |
|||
return businessAccess($ids) && request('_business_info')['info']['users'][$ids['user_id'] ?? auth()->id()]['level'] >= enum('levels.admin.id'); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('businessEdit')) { |
|||
function businessEdit($ids) |
|||
{ |
|||
return isBusinessOwner($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('businessUsers')) { |
|||
function businessUsers($ids) |
|||
{ |
|||
return isBusinessOwner($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('businessWorkFlows')) { |
|||
function businessWorkFlows($ids) |
|||
{ |
|||
return isAtLeastBusinessAdmin($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('businessProjects')) { |
|||
function businessProjects($ids) |
|||
{ |
|||
return isBusinessOwner($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('businessTags')) { |
|||
function businessTags($ids) |
|||
{ |
|||
return isAtLeastBusinessAdmin($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('businessStatuses')) { |
|||
function businessStatuses($ids) |
|||
{ |
|||
return isAtLeastBusinessAdmin($ids); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Project Permit |
|||
*/ |
|||
|
|||
if (!function_exists('isInProject')) { |
|||
function isInProject($ids) |
|||
{ |
|||
return isset(request('_business_info')['info']['projects'][$ids['project_id']]['members'][$ids['user_id'] ?? auth()->id()]); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isActiveInProject')) { |
|||
function isActiveInProject($ids) |
|||
{ |
|||
return request('_business_info')['info']['projects'][$ids['project_id']]['members'][$ids['user_id'] ?? auth()->id()]['level'] > 0; |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('projectAccess')) { |
|||
function projectAccess($ids) |
|||
{ |
|||
return isInProject($ids) && isActiveInProject($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isOwnerLevelInProject')) { |
|||
function isOwnerLevelInProject($ids) |
|||
{ |
|||
return request('_business_info')['info']['projects'][$ids['project_id']]['members'][$ids['user_id'] ?? auth()->id()]['level'] == enum('levels.owner.id'); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isAtLeastAdminLevelInProject')) { |
|||
function isAtLeastAdminLevelInProject($ids) |
|||
{ |
|||
return request('_business_info')['info']['projects'][$ids['project_id']]['members'][$ids['user_id'] ?? auth()->id()]['level'] >= enum('levels.admin.id'); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isAtLeastColleagueLevelInProject')) { |
|||
function isAtLeastColleagueLevelInProject($ids) |
|||
{ |
|||
return request('_business_info')['info']['projects'][$ids['project_id']]['members'][$ids['user_id'] ?? auth()->id()]['level'] >= enum('levels.colleague.id'); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isAtLeastGuestLevelInProject')) { |
|||
function isAtLeastGuestLevelInProject($ids) |
|||
{ |
|||
return request('_business_info')['info']['projects'][$ids['project_id']]['members'][$ids['user_id'] ?? auth()->id()]['level'] >= enum('levels.guest.id'); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isDefiniteGuestInProject')) { |
|||
function isDefiniteGuestInProject($ids) |
|||
{ |
|||
return isInProject($ids) && request('_business_info')['info']['projects'][$ids['project_id']]['members'][$ids['user_id'] ?? auth()->id()]['level'] == enum('levels.guest.id'); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isProjectOwner')) { |
|||
function isProjectOwner($ids) |
|||
{ |
|||
return isInProject($ids) && isOwnerLevelInProject($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isProjectAdmin')) { |
|||
function isProjectAdmin($ids) |
|||
{ |
|||
return isInProject($ids) && isAtLeastAdminLevelInProject($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isProjectColleague')) { |
|||
function isProjectColleague($ids) |
|||
{ |
|||
return isInProject($ids) && isAtLeastColleagueLevelInProject($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('isProjectGuest')) { |
|||
function isProjectGuest($ids) |
|||
{ |
|||
return isInProject($ids) && isAtLeastGuestLevelInProject($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('projectEdit')) { |
|||
function projectEdit($ids) |
|||
{ |
|||
return isProjectAdmin($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('projectUsers')) { |
|||
function projectUsers($ids) |
|||
{ |
|||
return isProjectOwner($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('projectSystems')) { |
|||
function projectSystems($ids) |
|||
{ |
|||
return isProjectAdmin($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('projectTasks')) { |
|||
function projectTasks($ids) |
|||
{ |
|||
return isProjectAdmin($ids); |
|||
} |
|||
} |
|||
|
|||
if (!function_exists('projectSprints')) { |
|||
function projectSprints($ids) |
|||
{ |
|||
return isProjectAdmin($ids); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* other |
|||
*/ |
|||
|
|||
if (!function_exists('isActiveUser')) { |
|||
function isActiveUser($ids) |
|||
{ |
|||
return businessAccess($ids) && request('_business_info')['info']['users'][$ids['user_id'] ?? auth()->id()]['level'] > enum('levels.inactive.id'); |
|||
} |
|||
} |
|||
|
@ -0,0 +1 @@ |
|||
<?php
namespace App\HiLib\Jobs;
use App\Jobs\Job;
class AsyncCall extends Job
{
private string $method;
private string $service;
private string $path;
private array $data;
/**
* AsyncCall constructor.
* @param string $method
* @param string $service
* @param string $path
* @param array $data
* @param string $queue
*/
public function __construct(string $method, string $service, string $path, array $data, string $queue)
{
$this->method = $method;
$this->service = $service;
$this->path = $path;
$this->data = $data;
$this->onQueue($queue);
$this->onConnection('database');
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
call($this->method, $this->service, $this->path, $this->data);
}
} |
@ -0,0 +1,83 @@ |
|||
<?php |
|||
|
|||
namespace App\HiLib\Logger; |
|||
|
|||
use DateTimeZone; |
|||
use InvalidArgumentException; |
|||
use Monolog\Logger as Monolog; |
|||
use Monolog\Handler\HandlerInterface; |
|||
use App\HiLib\Logger\LogServiceRecordProcessor; |
|||
|
|||
class CreateCustomLogger |
|||
{ |
|||
protected $levels = [ |
|||
'debug' => Monolog::DEBUG, |
|||
'info' => Monolog::INFO, |
|||
'notice' => Monolog::NOTICE, |
|||
'warning' => Monolog::WARNING, |
|||
'error' => Monolog::ERROR, |
|||
'critical' => Monolog::CRITICAL, |
|||
'alert' => Monolog::ALERT, |
|||
'emergency' => Monolog::EMERGENCY, |
|||
]; |
|||
|
|||
public function __invoke(array $config) |
|||
{ |
|||
if (!is_a($config['handler'], HandlerInterface::class, true)) { |
|||
throw new InvalidArgumentException( |
|||
$config['handler'] . ' must be an instance of ' . HandlerInterface::class |
|||
); |
|||
} |
|||
|
|||
$with = array_merge( |
|||
['level' => $this->level($config)], |
|||
$config['with'] ?? [], |
|||
$config['handler_with'] ?? [] |
|||
); |
|||
|
|||
$handlers = [ |
|||
$this->prepareHandler(app()->make($config['handler'], $with), $config) |
|||
]; |
|||
|
|||
$processors = [ |
|||
new LogServiceRecordProcessor, |
|||
]; |
|||
|
|||
return new Monolog('custom', $handlers, $processors, new DateTimeZone('Asia/Tehran')); |
|||
} |
|||
|
|||
protected function getFallbackChannelName() |
|||
{ |
|||
return app()->bound('env') ? app()->environment() : 'production'; |
|||
} |
|||
|
|||
protected function prepareHandler(HandlerInterface $handler, array $config = []) |
|||
{ |
|||
$isHandlerFormattable = false; |
|||
|
|||
if (Monolog::API === 1) { |
|||
$isHandlerFormattable = true; |
|||
} elseif (Monolog::API === 2 && $handler instanceof FormattableHandlerInterface) { |
|||
$isHandlerFormattable = true; |
|||
} |
|||
|
|||
if ($isHandlerFormattable && !isset($config['formatter'])) { |
|||
$handler->setFormatter($this->formatter()); |
|||
} elseif ($isHandlerFormattable && $config['formatter'] !== 'default') { |
|||
$handler->setFormatter(app()->make($config['formatter'], $config['formatter_with'] ?? [])); |
|||
} |
|||
|
|||
return $handler; |
|||
} |
|||
|
|||
protected function level(array $config) |
|||
{ |
|||
$level = $config['level'] ?? 'debug'; |
|||
|
|||
if (isset($this->levels[$level])) { |
|||
return $this->levels[$level]; |
|||
} |
|||
|
|||
throw new InvalidArgumentException('Invalid log level.'); |
|||
} |
|||
} |
@ -0,0 +1,37 @@ |
|||
<?php |
|||
|
|||
namespace App\HiLib\Logger; |
|||
|
|||
use Throwable; |
|||
use Carbon\Carbon; |
|||
use Ramsey\Uuid\Uuid; |
|||
use Illuminate\Support\Arr; |
|||
use Illuminate\Support\Facades\Auth; |
|||
use Illuminate\Support\Facades\DB; |
|||
|
|||
class LogServiceRecordProcessor |
|||
{ |
|||
public function __invoke($record) |
|||
{ |
|||
try { |
|||
$exception = json_decode($record['message'], true); |
|||
|
|||
return array_merge($record, [ |
|||
'correlation_id' => Uuid::uuid4()->toString(), |
|||
'breadcrumbs' => DB::getQueryLog(), |
|||
'request' => app('request'), |
|||
'message' => Arr::get($exception, 'getMessage', $record['message']), |
|||
'from' => env('CONTAINER_NAME'), |
|||
'trace' => Arr::get($exception, 'getTraceAsString'), |
|||
'name' => Arr::get($exception, 'getName'), |
|||
'code' => Arr::get($exception, 'getCode'), |
|||
'file' => Arr::get($exception, 'getFile'), |
|||
'line' => Arr::get($exception, 'getLine'), |
|||
'user_id' => Auth::hasResolvedGuards() ? Auth::id() : null, |
|||
'created_at' => Carbon::now(), |
|||
]); |
|||
} catch (Throwable $exception) { |
|||
return $record; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
<?php
namespace App\HiLib\Middlewares;
use Closure;
class BindBusinessInfo
{
public function handle($request, Closure $next, $guard = null)
{
$business_id = $request->has('business_id') ? $request->business_id : $request->route('business');
$businessInfo = env('CONTAINER_NAME') == 'hi-user-app' ?
\App\Business::info($business_id) :
get('user', env('USER_URL') . 'actions/businesses/' . $business_id . '/info', []);
$request->merge(['_business_info' => $businessInfo]);
return $next($request);
}
} |
@ -0,0 +1,254 @@ |
|||
<?php |
|||
|
|||
namespace App\HiLib\Models; |
|||
|
|||
use Anik\Amqp\Exchange; |
|||
use Anik\Amqp\Facades\Amqp; |
|||
use PhpAmqpLib\Wire\AMQPTable; |
|||
use Anik\Amqp\PublishableMessage; |
|||
use Illuminate\Http\JsonResponse; |
|||
use Illuminate\Support\Facades\DB; |
|||
use Illuminate\Support\Facades\Auth; |
|||
use Illuminate\Validation\Validator; |
|||
use Illuminate\Database\Eloquent\Collection; |
|||
use Illuminate\Validation\ValidationException; |
|||
use Symfony\Component\HttpFoundation\Response; |
|||
use Illuminate\Database\Eloquent\Model as EloquentModel; |
|||
|
|||
|
|||
class Model extends EloquentModel |
|||
{ |
|||
|
|||
/** |
|||
* Introducing model relationships |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $fillable_relations = []; |
|||
|
|||
/** |
|||
* Models that are ready to change. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $filled_relations = []; |
|||
|
|||
/** |
|||
* Models that are ready to change. |
|||
* |
|||
* @var array |
|||
*/ |
|||
protected $reportable = []; |
|||
|
|||
protected $dirties = []; |
|||
|
|||
protected $action = null; |
|||
|
|||
public const CREATED = 10; |
|||
|
|||
public const UPDATED = 20; |
|||
|
|||
public const DELETED = 30; |
|||
|
|||
public const RESTORED = 40; |
|||
|
|||
protected static function booted() |
|||
{ |
|||
static::created(function ($model) { |
|||
$model->action = static::CREATED; |
|||
}); |
|||
|
|||
static::updated(function ($model) { |
|||
$model->action = static::UPDATED; |
|||
}); |
|||
|
|||
static::deleted(function ($model) { |
|||
$model->action = static::DELETED; |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* @return void |
|||
* @throw \Exception |
|||
*/ |
|||
public function rules() |
|||
{ |
|||
return []; |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* |
|||
* @param array $attributes |
|||
* @return void |
|||
*/ |
|||
public function validate(array $attributes = null) |
|||
{ |
|||
$attributes = $attributes ?? $this->getAttributes(); |
|||
|
|||
/** @var Validator $validator */ |
|||
$validator = app('validator')->make($attributes, $this->rules()); |
|||
|
|||
if ($validator->fails()) { |
|||
throw new ValidationException( |
|||
$validator, |
|||
new JsonResponse($validator->errors()->getMessages(), Response::HTTP_UNPROCESSABLE_ENTITY) |
|||
); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @return void |
|||
*/ |
|||
public function updateRelations() |
|||
{ |
|||
} |
|||
|
|||
/** |
|||
* @param string|null $key |
|||
* @return void |
|||
*/ |
|||
public function getValueOf(?string $key) |
|||
{ |
|||
$values = []; |
|||
|
|||
if ($key && isset($values, $key)) { |
|||
return $values[$key]; |
|||
} |
|||
|
|||
return $values; |
|||
} |
|||
|
|||
protected function makeChanges() |
|||
{ |
|||
if (empty($this->reportable)) { |
|||
return; |
|||
} |
|||
|
|||
$changes = new Collection($this->getDirty()); |
|||
|
|||
// fillable * or field
|
|||
$changes = $changes->filter(function ($value, $key) { |
|||
foreach ($this->reportable as $i => $name) { |
|||
if ($key === $name) { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
}); |
|||
|
|||
if (($changes->isEmpty() && $this->action == static::UPDATED)) { |
|||
return; |
|||
} |
|||
|
|||
return [ |
|||
'original' => $this->getOriginal() + $this->getAttributes(), |
|||
'diff' => $changes->toArray(), |
|||
]; |
|||
|
|||
// return [
|
|||
// 'auth' => Auth::id(),
|
|||
// 'timestamp' => $this->freshTimestamp(),
|
|||
// 'business' => $this->getValueOf('business_id'),
|
|||
// 'info' => \request('_business_info')['info'] ?? null,
|
|||
// 'project' => $this->getValueOf('project_id'),
|
|||
// 'data' => [
|
|||
// 'sprint_id' => $this->getValueOf('sprint_id'),
|
|||
// 'system_id' => $this->getValueOf('system_id'),
|
|||
// 'workflow_id' => $this->getValueOf('workflow_id'),
|
|||
// 'status_id' => $this->getValueOf('status_id'),
|
|||
// 'user_id' => $this->getValueOf('user_id'),
|
|||
// 'table_name' => $this->getTable(),
|
|||
// 'crud_id' => $this->action,
|
|||
// 'original' => $this->getOriginal() + $this->getAttributes(),
|
|||
// 'diff' => $changes->toArray(),
|
|||
// ],
|
|||
// 'from' => env('CONTAINER_NAME'),
|
|||
// ];
|
|||
} |
|||
|
|||
protected function report($changes): void |
|||
{ |
|||
if ($this->action == null){ |
|||
return; |
|||
} |
|||
$payload = [ |
|||
'auth' => Auth::id(), |
|||
'timestamp' => $this->freshTimestamp(), |
|||
'business' => $this->getValueOf('business_id'), |
|||
'info' => \request('_business_info') ?? null, |
|||
'project' => $this->getValueOf('project_id'), |
|||
'data' => [ |
|||
'sprint_id' => $this->getValueOf('sprint_id'), |
|||
'system_id' => $this->getValueOf('system_id'), |
|||
'workflow_id' => $this->getValueOf('workflow_id'), |
|||
'status_id' => $this->getValueOf('status_id'), |
|||
'task_id' => $this->getValueOf('task_id'), |
|||
'subject_id' => $this->getValueOf('subject_id'), |
|||
'user_id' => $this->getValueOf('user_id'), |
|||
'table_name' => $this->getTable(), |
|||
'crud_id' => $this->action, |
|||
'original' => $changes['original'] + $this->getOriginal(), |
|||
'diff' => $changes['diff'], |
|||
], |
|||
'from' => env('CONTAINER_NAME'), |
|||
]; |
|||
|
|||
$message = new PublishableMessage(json_encode($payload)); |
|||
|
|||
$routers = [ |
|||
"activity_exchange" => ["name" => "activity",], |
|||
"notif_exchange" => ["name" => "notif",], |
|||
"socket_exchange" => ["name" => "socket",], |
|||
]; |
|||
|
|||
foreach ($routers as $exchange => $properties) { |
|||
$message->setProperties(["application_headers" => new AMQPTable($properties)]); |
|||
|
|||
$message->setExchange(new Exchange($exchange)); |
|||
|
|||
Amqp::publish($message, ""); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @param array $options |
|||
* @return void |
|||
*/ |
|||
public function save(array $options = []) |
|||
{ |
|||
// The validation function is called first
|
|||
$this->validate(); |
|||
|
|||
// Then, because the relationships are set as attributes in this model
|
|||
// we pre-enter their names in filled_relation attribute and store
|
|||
// them in a temporary variable with a loop.
|
|||
foreach ($this->fillable_relations as $relation) { |
|||
$this->filled_relations[$relation] = $this[$relation]; |
|||
unset($this[$relation]); |
|||
} |
|||
|
|||
// all of its action inside one transaction
|
|||
// so if any of them failed the whole
|
|||
// process rollbacked
|
|||
DB::transaction(function () use ($options) { |
|||
// report to the activity aggregator
|
|||
$changes = $this->makeChanges(); |
|||
|
|||
// save the model with it's attributes
|
|||
parent::save($options); |
|||
|
|||
// save the model with it's relationships
|
|||
$this->updateRelations(); |
|||
|
|||
is_array($changes) ? $this->report($changes) : true; |
|||
}, 3); |
|||
} |
|||
|
|||
public function delete() |
|||
{ |
|||
$changes = $this->makeChanges(); |
|||
parent::delete(); |
|||
is_array($changes) ? $this->report($changes) : true; |
|||
} |
|||
} |
@ -0,0 +1,138 @@ |
|||
<?php |
|||
|
|||
namespace App\HiLib\Models; |
|||
|
|||
use Anik\Amqp\Exchange; |
|||
use Anik\Amqp\Facades\Amqp; |
|||
use PhpAmqpLib\Wire\AMQPTable; |
|||
use Anik\Amqp\PublishableMessage; |
|||
use Illuminate\Support\Facades\Auth; |
|||
use Illuminate\Database\Eloquent\Relations\Pivot; |
|||
|
|||
class ReportableRelation extends Pivot |
|||
{ |
|||
public const CREATED = 10; |
|||
|
|||
public const UPDATED = 20; |
|||
|
|||
public const DELETED = 30; |
|||
|
|||
protected static function booted() |
|||
{ |
|||
static::created(function ($model) { |
|||
$model->action = static::CREATED; |
|||
static::report($model); |
|||
}); |
|||
static::updated(function ($model) { |
|||
$model->action = static::UPDATED; |
|||
static::report($model); |
|||
}); |
|||
static::deleted(function ($model) { |
|||
$model->action = static::DELETED; |
|||
static::report($model); |
|||
}); |
|||
} |
|||
|
|||
public static function report($model) |
|||
{ |
|||
$payload = [ |
|||
'auth' => Auth::id(), |
|||
'timestamp' => $model->freshTimestamp(), |
|||
'business' => $model->pivotParent->getValueOf('business_id'), |
|||
'info' => \request('_business_info') ?? null, |
|||
'project' => $model->pivotParent->getValueOf('project_id'), |
|||
'data' => [ |
|||
'sprint_id' => $model->pivotParent->getValueOf('sprint_id'), |
|||
'system_id' => $model->pivotParent->getValueOf('system_id'), |
|||
'workflow_id' => $model->pivotParent->getValueOf('workflow_id'), |
|||
'status_id' => $model->pivotParent->getValueOf('status_id'), |
|||
'task_id' => $model->pivotParent->getValueOf('task_id'), |
|||
'user_id' => $model->user_id, |
|||
'table_name' => $model->getTable(), |
|||
'crud_id' => $model->action, |
|||
'original' => $model->getOriginal() + $model->getAttributes(), |
|||
'diff' => $model->getChanges(), |
|||
], |
|||
'from' => env('CONTAINER_NAME'), |
|||
]; |
|||
|
|||
$message = new PublishableMessage(json_encode($payload)); |
|||
|
|||
$routers = [ |
|||
"activity_exchange" => ["name" => "activity",], |
|||
"notif_exchange" => ["name" => "notif",], |
|||
"socket_exchange" => ["name" => "socket",], |
|||
]; |
|||
|
|||
foreach ($routers as $exchange => $properties) { |
|||
$message->setProperties(["application_headers" => new AMQPTable($properties)]); |
|||
|
|||
$message->setExchange(new Exchange($exchange)); |
|||
|
|||
Amqp::publish($message, ""); |
|||
} |
|||
} |
|||
|
|||
public function properties() |
|||
{ |
|||
return $properties = [ |
|||
// Message properties
|
|||
'Persistent' => '1', // Marks a message as persistent
|
|||
|
|||
// those familiar with the protocol may choose to use this property instead of Persistent. They control the same thing.
|
|||
// Non-persistent (1) or persistent (2).
|
|||
'DeliveryMode' => '', |
|||
|
|||
// Used to describe the mime-type of the encoding. For example for the often used JSON encoding it is a good practice to set this property to: application/json.
|
|||
// MIME content type.
|
|||
// short string (max. 256 characters)
|
|||
'content_type' => '', |
|||
|
|||
// Commonly used to name a callback queue.
|
|||
// Address to reply to.
|
|||
// short string (max. 256 characters)
|
|||
'reply_to' => '', |
|||
|
|||
// Useful to correlate RPC responses with requests.
|
|||
// Application correlation identifier.
|
|||
// short string (max. 256 characters)
|
|||
'correlation_id' => '', |
|||
|
|||
/** Rarley Used Properties */ |
|||
|
|||
// This defines the message priority
|
|||
// Message priority, 0 to 9
|
|||
'priority' => '', |
|||
|
|||
// This is the message time stamp
|
|||
// Message timestamp.
|
|||
'timestamp' => '', |
|||
|
|||
// This is the broker with whom the user sends the message (by default, it is "guest").
|
|||
// Creating user id.
|
|||
// short string (max. 256 characters)
|
|||
'user_id' => '', |
|||
|
|||
// MIME content encoding.
|
|||
// short string (max. 256 characters)
|
|||
'content_encoding' => '', |
|||
|
|||
// Message expiration specification.
|
|||
// short string (max. 256 characters)
|
|||
'expiration' => '', |
|||
|
|||
// Application message identifier.
|
|||
// short string (max. 256 characters)
|
|||
'message_id' => '', |
|||
|
|||
// Message type name.
|
|||
// short string (max. 256 characters)
|
|||
'type' => '', |
|||
|
|||
// Creating application id.
|
|||
// short string (max. 256 characters)
|
|||
'app_id' => '', |
|||
'cluster_id' => '', |
|||
]; |
|||
} |
|||
} |
@ -0,0 +1 @@ |
|||
<?php
namespace App\HiLib\Providers;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
public function boot()
{
$this->app['auth']->viaRequest('api', function (Request $request) {
// with token
if ($request->bearerToken()) {
return $this->loginUserWithToken($request);
}
// first party
if ($request->getHost() === $container_name = getenv('CONTAINER_NAME')) {
return $this->loginServiceWithSetUser($container_name);
}
// without token
return null;
});
}
public function loginUserWithToken(Request $request): User
{
$attributes = Http::retry(3, 100)
->withToken($request->bearerToken())
->get(env('USER_URL') . 'auth')
->json();
$attributes = Arr::get($attributes, 'data',[]);
// dd($attributes);
return new User($attributes);
}
public function loginServiceWithSetUser(string $container_name): User
{
Auth::setUser($user = new User([
'name' => $container_name,
'is_service' => true,
]));
return $user;
}
} |
@ -0,0 +1,49 @@ |
|||
<?php |
|||
|
|||
namespace App\HiLib\Providers; |
|||
|
|||
use Illuminate\Support\Facades\DB; |
|||
use Illuminate\Support\Stringable; |
|||
use Illuminate\Support\ServiceProvider; |
|||
class HiLibraryServiceProvider extends ServiceProvider |
|||
{ |
|||
|
|||
/** |
|||
* Register any application services. |
|||
* |
|||
* Within the register method, you should only bind things into the service container. |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function register() |
|||
{ |
|||
$this->app->singleton( |
|||
\Illuminate\Contracts\Debug\ExceptionHandler::class, |
|||
\App\HiLib\Exceptions\Handler::class |
|||
); |
|||
|
|||
Stringable::macro('then', function($callback) { |
|||
return new Stringable($callback($this)); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Bootstrap any application services. |
|||
* |
|||
* @return void |
|||
*/ |
|||
public function boot() |
|||
{ |
|||
DB::enableQueryLog(); |
|||
} |
|||
|
|||
/** |
|||
* Get the services provided by the provider. |
|||
* |
|||
* @return array |
|||
*/ |
|||
public function provides() |
|||
{ |
|||
//
|
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue