Merge pull request #8292 from turbo124/v5-develop

Add excludable permissions
This commit is contained in:
David Bomba 2023-02-21 07:51:16 +11:00 committed by GitHub
commit 57d6c13150
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 399 additions and 372 deletions

View File

@ -15,6 +15,7 @@ use App\Models\Account;
use App\Models\BankIntegration; use App\Models\BankIntegration;
use App\Models\BankTransaction; use App\Models\BankTransaction;
use App\Models\BankTransactionRule; use App\Models\BankTransactionRule;
use App\Models\Client;
use App\Models\CompanyGateway; use App\Models\CompanyGateway;
use App\Models\Design; use App\Models\Design;
use App\Models\ExpenseCategory; use App\Models\ExpenseCategory;
@ -62,12 +63,41 @@ class BaseController extends Controller
*/ */
public $forced_index = 'data'; public $forced_index = 'data';
/**
* The calling controller Model Type
*/
protected $entity_type;
/**
* The calling controller Transformer type
*
*/
protected $entity_transformer;
/**
* The serializer in use with Fractal
*
*/
protected $serializer;
/* Grouped permissions when we want to hide columns for particular permission groups*/
private array $client_exclusion_fields = ['balance', 'paid_to_date', 'credit_balance', 'client_hash'];
private array $client_excludable_permissions = ['view_client'];
private array $client_excludable_overrides = ['edit_client', 'edit_all', 'view_invoice', 'view_all', 'edit_invoice'];
/* Grouped permissions when we want to hide columns for particular permission groups*/
/** /**
* Fractal manager. * Fractal manager.
* @var object * @var Manager $manager
*/ */
protected Manager $manager; protected Manager $manager;
/**
* An array of includes to be loaded by default.
*/
private $first_load = [ private $first_load = [
'account', 'account',
'user.company_user', 'user.company_user',
@ -120,6 +150,10 @@ class BaseController extends Controller
'company.task_schedulers', 'company.task_schedulers',
]; ];
/**
* An array of includes to be loaded by default
* when the company is large.
*/
private $mini_load = [ private $mini_load = [
'account', 'account',
'user.company_user', 'user.company_user',
@ -140,11 +174,22 @@ class BaseController extends Controller
'company.task_schedulers', 'company.task_schedulers',
]; ];
/**
* __construct
*
* @return void
*/
public function __construct() public function __construct()
{ {
$this->manager = new Manager(); $this->manager = new Manager();
} }
/**
* Initializes the Manager and transforms
* the required includes
*
* @return void
*/
private function buildManager() private function buildManager()
{ {
$include = ''; $include = '';
@ -172,8 +217,7 @@ class BaseController extends Controller
} }
/** /**
* Catch all fallback route * Catch all fallback route.
* for non-existant route.
*/ */
public function notFound() public function notFound()
{ {
@ -187,7 +231,7 @@ class BaseController extends Controller
* end user has the correct permissions to * end user has the correct permissions to
* view the includes * view the includes
* *
* @param array $includes The includes for the object * @param string $includes The includes for the object
* @return string The filtered array of includes * @return string The filtered array of includes
*/ */
private function filterIncludes(string $includes): string private function filterIncludes(string $includes): string
@ -227,9 +271,10 @@ class BaseController extends Controller
/** /**
* API Error response. * API Error response.
* @param string $message The return error message *
* @param int $httpErrorCode 404/401/403 etc * @param string $message The return error message
* @return Response The JSON response * @param int $httpErrorCode 404/401/403 etc
* @return Response The JSON response
* @throws BindingResolutionException * @throws BindingResolutionException
*/ */
protected function errorResponse($message, $httpErrorCode = 400) protected function errorResponse($message, $httpErrorCode = 400)
@ -245,7 +290,8 @@ class BaseController extends Controller
/** /**
* Refresh API response with latest cahnges * Refresh API response with latest cahnges
* @param Builer $query *
* @param Builder $query
* @property App\Models\User auth()->user() * @property App\Models\User auth()->user()
* @return Builer * @return Builer
*/ */
@ -286,6 +332,10 @@ class BaseController extends Controller
$query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id); $query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);
}); });
} }
if ($user->hasExcludedPermissions($this->client_excludable_permissions, $this->client_excludable_overrides)) {
$query->exclude($this->client_exclusion_fields);
}
}, },
'company.company_gateways' => function ($query) use ($user) { 'company.company_gateways' => function ($query) use ($user) {
$query->whereNotNull('updated_at')->with('gateway'); $query->whereNotNull('updated_at')->with('gateway');
@ -481,12 +531,14 @@ class BaseController extends Controller
); );
if ($query instanceof Builder) { if ($query instanceof Builder) {
//27-10-2022 - enforce unsigned integer
$limit = $this->resolveQueryLimit(); $limit = $this->resolveQueryLimit();
$paginator = $query->paginate($limit); $paginator = $query->paginate($limit);
$query = $paginator->getCollection(); $query = $paginator->getCollection();
$resource = new Collection($query, $transformer, $this->entity_type); $resource = new Collection($query, $transformer, $this->entity_type);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator)); $resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
} else { } else {
$resource = new Collection($query, $transformer, $this->entity_type); $resource = new Collection($query, $transformer, $this->entity_type);
@ -495,7 +547,12 @@ class BaseController extends Controller
return $this->response($this->manager->createData($resource)->toArray()); return $this->response($this->manager->createData($resource)->toArray());
} }
private function resolveQueryLimit() /**
* Returns the per page limit for the query.
*
* @return int
*/
private function resolveQueryLimit(): int
{ {
if (request()->has('per_page')) { if (request()->has('per_page')) {
return abs((int)request()->input('per_page', 20)); return abs((int)request()->input('per_page', 20));
@ -504,6 +561,12 @@ class BaseController extends Controller
return 20; return 20;
} }
/**
* Mini Load Query
*
* @param mixed $query
* @return void
*/
protected function miniLoadResponse($query) protected function miniLoadResponse($query)
{ {
$user = auth()->user(); $user = auth()->user();
@ -587,6 +650,7 @@ class BaseController extends Controller
* able to access multiple companies, then we * able to access multiple companies, then we
* need to pass back the mini load only * need to pass back the mini load only
* *
* @deprecated
* @return bool * @return bool
*/ */
private function complexPermissionsUser(): bool private function complexPermissionsUser(): bool
@ -599,6 +663,12 @@ class BaseController extends Controller
return false; return false;
} }
/**
* Passes back the miniloaded data response
*
* @param mixed $query
* @return void
*/
protected function timeConstrainedResponse($query) protected function timeConstrainedResponse($query)
{ {
$user = auth()->user(); $user = auth()->user();
@ -637,6 +707,10 @@ class BaseController extends Controller
$query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id); $query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);
}); });
} }
if ($user->hasExcludedPermissions($this->client_excludable_permissions, $this->client_excludable_overrides)) {
$query->exclude($this->client_exclusion_fields);
}
}, },
'company.company_gateways' => function ($query) use ($user) { 'company.company_gateways' => function ($query) use ($user) {
$query->whereNotNull('created_at')->with('gateway'); $query->whereNotNull('created_at')->with('gateway');
@ -834,6 +908,12 @@ class BaseController extends Controller
return $this->response($this->manager->createData($resource)->toArray()); return $this->response($this->manager->createData($resource)->toArray());
} }
/**
* List response
*
* @param mixed $query
* @return void
*/
protected function listResponse($query) protected function listResponse($query)
{ {
$this->buildManager(); $this->buildManager();
@ -847,7 +927,6 @@ class BaseController extends Controller
$query->with($includes); $query->with($includes);
if (auth()->user() && ! auth()->user()->hasPermission('view_'.Str::snake(class_basename($this->entity_type)))) { if (auth()->user() && ! auth()->user()->hasPermission('view_'.Str::snake(class_basename($this->entity_type)))) {
//06-10-2022 - some entities do not have assigned_user_id - this becomes an issue when we have a large company and low permission users
if (in_array($this->entity_type, [User::class])) { if (in_array($this->entity_type, [User::class])) {
$query->where('id', auth()->user()->id); $query->where('id', auth()->user()->id);
} elseif (in_array($this->entity_type, [BankTransactionRule::class,CompanyGateway::class, TaxRate::class, BankIntegration::class, Scheduler::class, BankTransaction::class, Webhook::class, ExpenseCategory::class])) { //table without assigned_user_id } elseif (in_array($this->entity_type, [BankTransactionRule::class,CompanyGateway::class, TaxRate::class, BankIntegration::class, Scheduler::class, BankTransaction::class, Webhook::class, ExpenseCategory::class])) { //table without assigned_user_id
@ -863,7 +942,10 @@ class BaseController extends Controller
$query->where('user_id', '=', auth()->user()->id)->orWhere('assigned_user_id', auth()->user()->id); $query->where('user_id', '=', auth()->user()->id)->orWhere('assigned_user_id', auth()->user()->id);
} }
} }
// $query->exclude(['balance','credit_balance','paid_to_date']);
if ($this->entity_type == Client::class && auth()->user()->hasExcludedPermissions($this->client_excludable_permissions, $this->client_excludable_overrides)) {
$query->exclude($this->client_exclusion_fields);
}
if (request()->has('updated_at') && request()->input('updated_at') > 0) { if (request()->has('updated_at') && request()->input('updated_at') > 0) {
$query->where('updated_at', '>=', date('Y-m-d H:i:s', intval(request()->input('updated_at')))); $query->where('updated_at', '>=', date('Y-m-d H:i:s', intval(request()->input('updated_at'))));
@ -886,6 +968,12 @@ class BaseController extends Controller
return $this->response($this->manager->createData($resource)->toArray()); return $this->response($this->manager->createData($resource)->toArray());
} }
/**
* Sorts the response by keys
*
* @param mixed $response
* @return void
*/
protected function response($response) protected function response($response)
{ {
$index = request()->input('index') ?: $this->forced_index; $index = request()->input('index') ?: $this->forced_index;
@ -917,6 +1005,12 @@ class BaseController extends Controller
return response()->make($response, 200, $headers); return response()->make($response, 200, $headers);
} }
/**
* Item Response
*
* @param mixed $item
* @return void
*/
protected function itemResponse($item) protected function itemResponse($item)
{ {
$this->buildManager(); $this->buildManager();
@ -936,7 +1030,12 @@ class BaseController extends Controller
return $this->response($this->manager->createData($resource)->toArray()); return $this->response($this->manager->createData($resource)->toArray());
} }
public static function getApiHeaders() /**
* Returns the API headers.
*
* @return array
*/
public static function getApiHeaders(): array
{ {
return [ return [
'Content-Type' => 'application/json', 'Content-Type' => 'application/json',
@ -945,7 +1044,13 @@ class BaseController extends Controller
]; ];
} }
protected function getRequestIncludes($data) /**
* Returns the parsed relationship includes
*
* @param mixed $data
* @return array
*/
protected function getRequestIncludes($data): array
{ {
/* /*
* Thresholds for displaying large account on first load * Thresholds for displaying large account on first load
@ -972,6 +1077,11 @@ class BaseController extends Controller
return $data; return $data;
} }
/**
* Main entrypoint for the default / route.
*
* @return mixed
*/
public function flutterRoute() public function flutterRoute()
{ {
if ((bool) $this->checkAppSetup() !== false && $account = Account::first()) { if ((bool) $this->checkAppSetup() !== false && $account = Account::first()) {
@ -1037,6 +1147,11 @@ class BaseController extends Controller
return redirect('/setup'); return redirect('/setup');
} }
/**
* Sets the Flutter build to serve
*
* @return void
*/
private function setBuild() private function setBuild()
{ {
$build = ''; $build = '';
@ -1065,6 +1180,12 @@ class BaseController extends Controller
} }
} }
/**
* Checks in a account has a required feature
*
* @param mixed $feature
* @return bool
*/
public function checkFeature($feature) public function checkFeature($feature)
{ {
if (auth()->user()->account->hasFeature($feature)) { if (auth()->user()->account->hasFeature($feature)) {
@ -1074,6 +1195,11 @@ class BaseController extends Controller
return false; return false;
} }
/**
* Feature failure response
*
* @return mixed
*/
public function featureFailure() public function featureFailure()
{ {
return response()->json(['message' => 'Upgrade to a paid plan for this feature.'], 403); return response()->json(['message' => 'Upgrade to a paid plan for this feature.'], 403);

View File

@ -42,9 +42,19 @@ class ContactHashLoginController extends Controller
return redirect($this->setRedirectPath()); return redirect($this->setRedirectPath());
} }
/**
* Generic error page for client portal.
*
* @return void
*/
public function errorPage() public function errorPage()
{ {
return render('generic.error', ['title' => session()->get('title'), 'notification' => session()->get('notification'), 'account' => auth()->guard('contact')?->user()?->user?->account, 'company' => auth()->guard('contact')?->user()?->user?->company]); return render('generic.error', [
'title' => session()->get('title'),
'notification' => session()->get('notification'),
'account' => auth()->guard('contact')?->user()?->user?->account,
'company' => auth()->guard('contact')?->user()?->user?->company
]);
} }
private function setRedirectPath() private function setRedirectPath()

View File

@ -75,8 +75,8 @@ class UserController extends BaseController
* tags={"users"}, * tags={"users"},
* summary="Gets a list of users", * summary="Gets a list of users",
* description="Lists users, search and filters allow fine grained lists to be generated. * description="Lists users, search and filters allow fine grained lists to be generated.
*
Query parameters can be added to performed more fine grained filtering of the users, these are handled by the UserFilters class which defines the methods available", *Query parameters can be added to performed more fine grained filtering of the users, these are handled by the UserFilters class which defines the methods available",
* @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"), * @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"),
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"), * @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
* @OA\Parameter(ref="#/components/parameters/include"), * @OA\Parameter(ref="#/components/parameters/include"),

View File

@ -30,7 +30,7 @@ class ValidCompanyQuantity implements Rule
return auth()->user()->company()->account->companies->count() < 10; return auth()->user()->company()->account->companies->count() < 10;
} }
return auth()->user()->company()->account->companies->count() < auth()->user()->company()->account->hosted_company_count; return auth()->user()->account->isPaid() && auth()->user()->company()->account->companies->count() < 10 ;
} }
/** /**

View File

@ -17,14 +17,10 @@ use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Mail\Admin\EntityFailedSendObject; use App\Mail\Admin\EntityFailedSendObject;
use App\Utils\Traits\Notifications\UserNotifies; use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Bus\Queueable;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class InvoiceFailedEmailNotification class InvoiceFailedEmailNotification
{ {
use UserNotifies, Dispatchable, InteractsWithQueue, Queueable, SerializesModels; use UserNotifies;
public $delay = 7; public $delay = 7;

View File

@ -11,14 +11,12 @@
namespace App\Models; namespace App\Models;
use App\Models\Traits\Excludable;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
class BankIntegration extends BaseModel class BankIntegration extends BaseModel
{ {
use SoftDeletes; use SoftDeletes;
use Filterable; use Filterable;
use Excludable;
protected $fillable = [ protected $fillable = [
'bank_account_name', 'bank_account_name',

View File

@ -11,15 +11,16 @@
namespace App\Models; namespace App\Models;
use App\DataMapper\ClientSettings; use Illuminate\Support\Str;
use App\Jobs\Util\WebhookHandler; use Illuminate\Support\Carbon;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\Jobs\Util\WebhookHandler;
use App\Models\Traits\Excludable;
use App\DataMapper\ClientSettings;
use Illuminate\Database\Eloquent\Model;
use App\Utils\Traits\UserSessionAttributes; use App\Utils\Traits\UserSessionAttributes;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
/** /**
* Class BaseModel * Class BaseModel
@ -33,6 +34,7 @@ class BaseModel extends Model
use MakesHash; use MakesHash;
use UserSessionAttributes; use UserSessionAttributes;
use HasFactory; use HasFactory;
use Excludable;
protected $appends = [ protected $appends = [
'hashed_id', 'hashed_id',

View File

@ -28,6 +28,10 @@ class CompanyGateway extends BaseModel
'deleted_at' => 'timestamp', 'deleted_at' => 'timestamp',
]; ];
protected $with = [
'gateway',
];
protected $fillable = [ protected $fillable = [
'gateway_key', 'gateway_key',
'accepted_credit_cards', 'accepted_credit_cards',

View File

@ -12,12 +12,14 @@
namespace App\Models; namespace App\Models;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\Models\Traits\Excludable;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
class StaticModel extends Model class StaticModel extends Model
{ {
use MakesHash; use MakesHash;
use Excludable;
protected $casts = [ protected $casts = [
'updated_at' => 'timestamp', 'updated_at' => 'timestamp',

View File

@ -392,8 +392,7 @@ class User extends Authenticatable implements MustVerifyEmail
} }
} }
return $this->isOwner() || return $this->isSuperUser() ||
$this->isAdmin() ||
(stripos($this->token()->cu->permissions, $permission) !== false) || (stripos($this->token()->cu->permissions, $permission) !== false) ||
(stripos($this->token()->cu->permissions, $all_permission) !== false) || (stripos($this->token()->cu->permissions, $all_permission) !== false) ||
(stripos($this->token()->cu->permissions, $edit_all) !== false) || (stripos($this->token()->cu->permissions, $edit_all) !== false) ||
@ -410,7 +409,7 @@ class User extends Authenticatable implements MustVerifyEmail
* @param string $permission '["view_all"]' * @param string $permission '["view_all"]'
* @return boolean * @return boolean
*/ */
public function hasExactPermission(string $permission = '___'): bool public function hasExactPermissionAndAll(string $permission = '___'): bool
{ {
$parts = explode('_', $permission); $parts = explode('_', $permission);
$all_permission = '__'; $all_permission = '__';
@ -436,7 +435,7 @@ class User extends Authenticatable implements MustVerifyEmail
public function hasIntersectPermissions(array $permissions = []): bool public function hasIntersectPermissions(array $permissions = []): bool
{ {
foreach ($permissions as $permission) { foreach ($permissions as $permission) {
if ($this->hasExactPermission($permission)) { if ($this->hasExactPermissionAndAll($permission)) {
return true; return true;
} }
} }
@ -444,6 +443,22 @@ class User extends Authenticatable implements MustVerifyEmail
return false; return false;
} }
/**
* Used when we need to match exactly what permission
* the user has, and not aggregate owner and admins.
*
* This method is used when we need to scope down the query
* and display a limited subset.
*
* @param string $permission '["view_all"]'
* @return boolean
*/
public function hasExactPermission(string $permission = '___'): bool
{
return (stripos($this->token()->cu->permissions, $permission) !== false);
}
/** /**
* Used when we need to match a range of permissions * Used when we need to match a range of permissions
* the user * the user
@ -461,7 +476,7 @@ class User extends Authenticatable implements MustVerifyEmail
} }
foreach ($permissions as $permission) { foreach ($permissions as $permission) {
if ($this->hasExactPermission($permission)) { if ($this->hasExactPermissionAndAll($permission)) {
return true; return true;
} }
} }
@ -469,6 +484,43 @@ class User extends Authenticatable implements MustVerifyEmail
return false; return false;
} }
/**
* Used when we need to filter permissions carefully.
*
* For instance, users that have view_client permissions should not
* see the client balance, however if they also have
* view_invoice or view_all etc, then they should be able to see the balance.
*
* First we pass over the excluded permissions and return false if we find a match.
*
* If those permissions are not hit, then we can iterate through the matched_permissions and search for a hit.
*
* Note, returning FALSE here means the user does NOT have the permission we want to exclude
*
* @param array $matched_permission
* @param array $excluded_permissions
* @return bool
*/
public function hasExcludedPermissions(array $matched_permission = [], array $excluded_permissions = []): bool
{
if ($this->isSuperUser()) {
return false;
}
foreach ($excluded_permissions as $permission) {
if ($this->hasExactPermission($permission)) {
return false;
}
}
foreach($matched_permission as $permission) {
if ($this->hasExactPermission($permission)) {
return true;
}
}
return false;
}
public function documents() public function documents()
{ {

View File

@ -1,52 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Providers;
use App\Utils\CssInlinerPlugin;
use Illuminate\Support\ServiceProvider;
class MailCssInlinerServiceProvider extends ServiceProvider
{
// Thanks to @fedeisas/laravel-mail-css-inliner
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$this->publishes([
__DIR__.'/../config/css-inliner.php' => base_path('config/css-inliner.php'),
], 'config');
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
// $this->app->singleton(CssInlinerPlugin::class, function ($app) {
// return new CssInlinerPlugin([]);
// });
// $this->app->singleton(CssInlinerPlugin::class, function ($app) {
// return new CssInlinerPlugin([]);
// });
// $this->app->bind(CssInlinerPlugin::class, function ($app) {
// return new CssInlinerPlugin([]);
// });
}
}

View File

@ -1,140 +0,0 @@
<?php
namespace App\Utils;
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;
class CssInlinerPlugin implements \Swift_Events_SendListener
{
/**
* @var CssToInlineStyles
*/
protected $converter;
/**
* @var string[]
*/
protected $cssCache;
/**
* @var array
*/
protected $options;
/**
* @param array $options options defined in the configuration file.
*/
public function __construct(array $options)
{
$this->converter = new CssToInlineStyles();
$this->options = $options;
}
/**
* @param \Swift_Events_SendEvent $evt
*/
public function beforeSendPerformed(\Swift_Events_SendEvent $evt)
{
$message = $evt->getMessage();
if ($message->getContentType() === 'text/html'
|| ($message->getContentType() === 'multipart/alternative' && $message->getBody())
|| ($message->getContentType() === 'multipart/mixed' && $message->getBody())
) {
[$body, $cssResources] = $this->messageSieve($message->getBody());
$css = $this->concatCss($cssResources);
$message->setBody($this->converter->convert($body, $css));
}
foreach ($message->getChildren() as $part) {
if (strpos($part->getContentType(), 'text/html') === 0) {
[$body, $cssResources] = $this->messageSieve($part->getBody());
$css = $this->concatCss($cssResources);
$part->setBody($this->converter->convert($body, $css));
}
}
}
/**
* Do nothing
*
* @param \Swift_Events_SendEvent $evt
*/
public function sendPerformed(\Swift_Events_SendEvent $evt)
{
// Do Nothing
}
protected function concatCss(array $cssResources): string
{
$output = '';
foreach ($cssResources as $cssResource) {
$output .= $this->fetchCss($cssResource);
}
return $output;
}
protected function fetchCss(string $filename): string
{
if (isset($this->cssCache[$filename])) {
return $this->cssCache[$filename];
}
$fixedFilename = $filename;
// Fix relative protocols on hrefs. Assume https.
if (substr($filename, 0, 2) === '//') {
$fixedFilename = 'https:'.$filename;
}
$content = file_get_contents($fixedFilename);
if (! $content) {
return '';
}
$this->cssCache[$filename] = $content;
return $content;
}
protected function messageSieve(string $message): array
{
$cssResources = [];
// Initialize with config defaults, if any
if (isset($this->options['css-files'])) {
$cssResources = $this->options['css-files'];
}
$dom = new \DOMDocument();
// set error level
$internalErrors = libxml_use_internal_errors(true);
$dom->loadHTML($message);
// Restore error level
libxml_use_internal_errors($internalErrors);
$link_tags = $dom->getElementsByTagName('link');
/** @var \DOMElement $link */
foreach ($link_tags as $link) {
if ($link->getAttribute('rel') === 'stylesheet') {
array_push($cssResources, $link->getAttribute('href'));
}
}
$link_tags = $dom->getElementsByTagName('link');
for ($i = $link_tags->length; --$i >= 0;) {
$link = $link_tags->item($i);
if ($link->getAttribute('rel') === 'stylesheet') {
$link->parentNode->removeChild($link);
}
}
if (count($cssResources)) {
return [$dom->saveHTML(), $cssResources];
}
return [$message, []];
}
}

View File

@ -87,7 +87,6 @@
"symfony/http-client": "^6.0", "symfony/http-client": "^6.0",
"symfony/mailgun-mailer": "^6.1", "symfony/mailgun-mailer": "^6.1",
"symfony/postmark-mailer": "^6.1", "symfony/postmark-mailer": "^6.1",
"tijsverkoyen/css-to-inline-styles": "^2.2",
"turbo124/beacon": "^1.3", "turbo124/beacon": "^1.3",
"twilio/sdk": "^6.40", "twilio/sdk": "^6.40",
"webpatser/laravel-countries": "dev-master#75992ad", "webpatser/laravel-countries": "dev-master#75992ad",

189
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "55a62c4290c3a07d0c38c8e4aeea61e0", "content-hash": "6156afb5e414466a8cd7b5903bbcbc6a",
"packages": [ "packages": [
{ {
"name": "afosto/yaac", "name": "afosto/yaac",
@ -379,16 +379,16 @@
}, },
{ {
"name": "aws/aws-sdk-php", "name": "aws/aws-sdk-php",
"version": "3.258.10", "version": "3.259.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/aws/aws-sdk-php.git", "url": "https://github.com/aws/aws-sdk-php.git",
"reference": "e164c9c5faf3965bd27ff2a4e9b7b3048ba8a337" "reference": "096711644ebe5c956a97ef449fa2cb3b66443c25"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/e164c9c5faf3965bd27ff2a4e9b7b3048ba8a337", "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/096711644ebe5c956a97ef449fa2cb3b66443c25",
"reference": "e164c9c5faf3965bd27ff2a4e9b7b3048ba8a337", "reference": "096711644ebe5c956a97ef449fa2cb3b66443c25",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -467,9 +467,9 @@
"support": { "support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues", "issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.258.10" "source": "https://github.com/aws/aws-sdk-php/tree/3.259.0"
}, },
"time": "2023-02-14T19:21:16+00:00" "time": "2023-02-17T19:21:38+00:00"
}, },
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@ -1504,28 +1504,27 @@
}, },
{ {
"name": "doctrine/lexer", "name": "doctrine/lexer",
"version": "2.1.0", "version": "3.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/lexer.git", "url": "https://github.com/doctrine/lexer.git",
"reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" "reference": "84a527db05647743d50373e0ec53a152f2cde568"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", "url": "https://api.github.com/repos/doctrine/lexer/zipball/84a527db05647743d50373e0ec53a152f2cde568",
"reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", "reference": "84a527db05647743d50373e0ec53a152f2cde568",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/deprecations": "^1.0", "php": "^8.1"
"php": "^7.1 || ^8.0"
}, },
"require-dev": { "require-dev": {
"doctrine/coding-standard": "^9 || ^10", "doctrine/coding-standard": "^10",
"phpstan/phpstan": "^1.3", "phpstan/phpstan": "^1.9",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "phpunit/phpunit": "^9.5",
"psalm/plugin-phpunit": "^0.18.3", "psalm/plugin-phpunit": "^0.18.3",
"vimeo/psalm": "^4.11 || ^5.0" "vimeo/psalm": "^5.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -1562,7 +1561,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/lexer/issues", "issues": "https://github.com/doctrine/lexer/issues",
"source": "https://github.com/doctrine/lexer/tree/2.1.0" "source": "https://github.com/doctrine/lexer/tree/3.0.0"
}, },
"funding": [ "funding": [
{ {
@ -1578,7 +1577,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-12-14T08:49:07+00:00" "time": "2022-12-15T16:57:16+00:00"
}, },
{ {
"name": "dragonmantank/cron-expression", "name": "dragonmantank/cron-expression",
@ -2168,16 +2167,16 @@
}, },
{ {
"name": "google/apiclient-services", "name": "google/apiclient-services",
"version": "v0.287.0", "version": "v0.288.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/googleapis/google-api-php-client-services.git", "url": "https://github.com/googleapis/google-api-php-client-services.git",
"reference": "ed58596d34272a5cd0dc2c0595d9a678b9834880" "reference": "de6cfa1556faf4a23d9ab5844508bb576f44fdd7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/ed58596d34272a5cd0dc2c0595d9a678b9834880", "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/de6cfa1556faf4a23d9ab5844508bb576f44fdd7",
"reference": "ed58596d34272a5cd0dc2c0595d9a678b9834880", "reference": "de6cfa1556faf4a23d9ab5844508bb576f44fdd7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2206,9 +2205,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/googleapis/google-api-php-client-services/issues", "issues": "https://github.com/googleapis/google-api-php-client-services/issues",
"source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.287.0" "source": "https://github.com/googleapis/google-api-php-client-services/tree/v0.288.0"
}, },
"time": "2023-02-12T01:08:11+00:00" "time": "2023-02-18T01:16:11+00:00"
}, },
{ {
"name": "google/auth", "name": "google/auth",
@ -4232,16 +4231,16 @@
}, },
{ {
"name": "league/commonmark", "name": "league/commonmark",
"version": "2.3.8", "version": "2.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/commonmark.git", "url": "https://github.com/thephpleague/commonmark.git",
"reference": "c493585c130544c4e91d2e0e131e6d35cb0cbc47" "reference": "c1e114f74e518daca2729ea8c4bf1167038fa4b5"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c493585c130544c4e91d2e0e131e6d35cb0cbc47", "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/c1e114f74e518daca2729ea8c4bf1167038fa4b5",
"reference": "c493585c130544c4e91d2e0e131e6d35cb0cbc47", "reference": "c1e114f74e518daca2729ea8c4bf1167038fa4b5",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4334,7 +4333,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-12-10T16:02:17+00:00" "time": "2023-02-15T14:07:24+00:00"
}, },
{ {
"name": "league/config", "name": "league/config",
@ -4504,16 +4503,16 @@
}, },
{ {
"name": "league/flysystem", "name": "league/flysystem",
"version": "3.12.2", "version": "3.12.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/flysystem.git", "url": "https://github.com/thephpleague/flysystem.git",
"reference": "f6377c709d2275ed6feaf63e44be7a7162b0e77f" "reference": "81e87e74dd5213795c7846d65089712d2dda90ce"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/f6377c709d2275ed6feaf63e44be7a7162b0e77f", "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/81e87e74dd5213795c7846d65089712d2dda90ce",
"reference": "f6377c709d2275ed6feaf63e44be7a7162b0e77f", "reference": "81e87e74dd5213795c7846d65089712d2dda90ce",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4575,7 +4574,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/thephpleague/flysystem/issues", "issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.12.2" "source": "https://github.com/thephpleague/flysystem/tree/3.12.3"
}, },
"funding": [ "funding": [
{ {
@ -4591,7 +4590,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-01-19T12:02:19+00:00" "time": "2023-02-18T15:32:41+00:00"
}, },
{ {
"name": "league/flysystem-aws-s3-v3", "name": "league/flysystem-aws-s3-v3",
@ -4928,16 +4927,16 @@
}, },
{ {
"name": "livewire/livewire", "name": "livewire/livewire",
"version": "v2.11.2", "version": "v2.11.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/livewire/livewire.git", "url": "https://github.com/livewire/livewire.git",
"reference": "e92233f31dc1b88fb1ac242b32afe1ab7525ee05" "reference": "5ab6266a12c637f645d38a2f0f61f84182f6249d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/livewire/livewire/zipball/e92233f31dc1b88fb1ac242b32afe1ab7525ee05", "url": "https://api.github.com/repos/livewire/livewire/zipball/5ab6266a12c637f645d38a2f0f61f84182f6249d",
"reference": "e92233f31dc1b88fb1ac242b32afe1ab7525ee05", "reference": "5ab6266a12c637f645d38a2f0f61f84182f6249d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -4989,7 +4988,7 @@
"description": "A front-end framework for Laravel.", "description": "A front-end framework for Laravel.",
"support": { "support": {
"issues": "https://github.com/livewire/livewire/issues", "issues": "https://github.com/livewire/livewire/issues",
"source": "https://github.com/livewire/livewire/tree/v2.11.2" "source": "https://github.com/livewire/livewire/tree/v2.11.3"
}, },
"funding": [ "funding": [
{ {
@ -4997,7 +4996,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-01-29T23:45:02+00:00" "time": "2023-02-20T03:52:35+00:00"
}, },
{ {
"name": "microsoft/microsoft-graph", "name": "microsoft/microsoft-graph",
@ -13071,25 +13070,25 @@
}, },
{ {
"name": "beyondcode/laravel-query-detector", "name": "beyondcode/laravel-query-detector",
"version": "1.6.0", "version": "1.7.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/beyondcode/laravel-query-detector.git", "url": "https://github.com/beyondcode/laravel-query-detector.git",
"reference": "8261d80c71c97e994c1021fe5c3bd2a1c27106fc" "reference": "40c7e168fcf7eeb80d8e96f7922e05ab194269c8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/beyondcode/laravel-query-detector/zipball/8261d80c71c97e994c1021fe5c3bd2a1c27106fc", "url": "https://api.github.com/repos/beyondcode/laravel-query-detector/zipball/40c7e168fcf7eeb80d8e96f7922e05ab194269c8",
"reference": "8261d80c71c97e994c1021fe5c3bd2a1c27106fc", "reference": "40c7e168fcf7eeb80d8e96f7922e05ab194269c8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0", "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0",
"php": "^7.1 || ^8.0" "php": "^7.1 || ^8.0"
}, },
"require-dev": { "require-dev": {
"laravel/legacy-factories": "^1.0", "laravel/legacy-factories": "^1.0",
"orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0", "orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0|^8.0",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
}, },
"type": "library", "type": "library",
@ -13125,9 +13124,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/beyondcode/laravel-query-detector/issues", "issues": "https://github.com/beyondcode/laravel-query-detector/issues",
"source": "https://github.com/beyondcode/laravel-query-detector/tree/1.6.0" "source": "https://github.com/beyondcode/laravel-query-detector/tree/1.7.0"
}, },
"time": "2022-02-12T16:23:40+00:00" "time": "2023-02-15T10:37:22+00:00"
}, },
{ {
"name": "brianium/paratest", "name": "brianium/paratest",
@ -13703,30 +13702,30 @@
}, },
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
"version": "1.14.3", "version": "2.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/annotations.git", "url": "https://github.com/doctrine/annotations.git",
"reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af" "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", "url": "https://api.github.com/repos/doctrine/annotations/zipball/e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
"reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", "reference": "e157ef3f3124bbf6fe7ce0ffd109e8a8ef284e7f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/lexer": "^1 || ^2", "doctrine/lexer": "^2 || ^3",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": "^7.1 || ^8.0", "php": "^7.2 || ^8.0",
"psr/cache": "^1 || ^2 || ^3" "psr/cache": "^1 || ^2 || ^3"
}, },
"require-dev": { "require-dev": {
"doctrine/cache": "^1.11 || ^2.0", "doctrine/cache": "^2.0",
"doctrine/coding-standard": "^9 || ^10", "doctrine/coding-standard": "^10",
"phpstan/phpstan": "~1.4.10 || ^1.8.0", "phpstan/phpstan": "^1.8.0",
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
"symfony/cache": "^4.4 || ^5.4 || ^6", "symfony/cache": "^5.4 || ^6",
"vimeo/psalm": "^4.10" "vimeo/psalm": "^4.10"
}, },
"suggest": { "suggest": {
@ -13773,9 +13772,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/annotations/issues", "issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/1.14.3" "source": "https://github.com/doctrine/annotations/tree/2.0.1"
}, },
"time": "2023-02-01T09:20:38+00:00" "time": "2023-02-02T22:02:53+00:00"
}, },
{ {
"name": "doctrine/instantiator", "name": "doctrine/instantiator",
@ -14082,27 +14081,27 @@
}, },
{ {
"name": "friendsofphp/php-cs-fixer", "name": "friendsofphp/php-cs-fixer",
"version": "v3.14.2", "version": "v3.14.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "14f0541651841b63640e7aafad041ad55dc7aa88" "reference": "1b3d9dba63d93b8a202c31e824748218781eae6b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/14f0541651841b63640e7aafad041ad55dc7aa88", "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/1b3d9dba63d93b8a202c31e824748218781eae6b",
"reference": "14f0541651841b63640e7aafad041ad55dc7aa88", "reference": "1b3d9dba63d93b8a202c31e824748218781eae6b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"composer/semver": "^3.3", "composer/semver": "^3.3",
"composer/xdebug-handler": "^3.0.3", "composer/xdebug-handler": "^3.0.3",
"doctrine/annotations": "^1.14.2 || ^2", "doctrine/annotations": "^2",
"doctrine/lexer": "^2", "doctrine/lexer": "^2 || ^3",
"ext-json": "*", "ext-json": "*",
"ext-tokenizer": "*", "ext-tokenizer": "*",
"php": "^7.4 || ^8.0", "php": "^7.4 || ^8.0",
"sebastian/diff": "^4.0", "sebastian/diff": "^4.0 || ^5.0",
"symfony/console": "^5.4 || ^6.0", "symfony/console": "^5.4 || ^6.0",
"symfony/event-dispatcher": "^5.4 || ^6.0", "symfony/event-dispatcher": "^5.4 || ^6.0",
"symfony/filesystem": "^5.4 || ^6.0", "symfony/filesystem": "^5.4 || ^6.0",
@ -14160,7 +14159,7 @@
"description": "A tool to automatically fix PHP code style", "description": "A tool to automatically fix PHP code style",
"support": { "support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.14.2" "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.14.4"
}, },
"funding": [ "funding": [
{ {
@ -14168,7 +14167,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2023-01-29T23:47:01+00:00" "time": "2023-02-09T21:49:13+00:00"
}, },
{ {
"name": "hamcrest/hamcrest-php", "name": "hamcrest/hamcrest-php",
@ -14223,24 +14222,24 @@
}, },
{ {
"name": "laracasts/cypress", "name": "laracasts/cypress",
"version": "3.0.0", "version": "3.0.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/laracasts/cypress.git", "url": "https://github.com/laracasts/cypress.git",
"reference": "9a9e5d25a51d2cbb410393e6a0d9883aa3304bf5" "reference": "dd4e61188d4edaf65ffa18851a5df38d0fa0619a"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/laracasts/cypress/zipball/9a9e5d25a51d2cbb410393e6a0d9883aa3304bf5", "url": "https://api.github.com/repos/laracasts/cypress/zipball/dd4e61188d4edaf65ffa18851a5df38d0fa0619a",
"reference": "9a9e5d25a51d2cbb410393e6a0d9883aa3304bf5", "reference": "dd4e61188d4edaf65ffa18851a5df38d0fa0619a",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"illuminate/support": "^6.0|^7.0|^8.0|^9.0", "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0",
"php": "^8.0" "php": "^8.0"
}, },
"require-dev": { "require-dev": {
"orchestra/testbench": "^6.0|^7.0", "orchestra/testbench": "^6.0|^7.0|^8.0",
"phpunit/phpunit": "^8.0|^9.5.10", "phpunit/phpunit": "^8.0|^9.5.10",
"spatie/laravel-ray": "^1.29" "spatie/laravel-ray": "^1.29"
}, },
@ -14276,9 +14275,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/laracasts/cypress/issues", "issues": "https://github.com/laracasts/cypress/issues",
"source": "https://github.com/laracasts/cypress/tree/3.0.0" "source": "https://github.com/laracasts/cypress/tree/3.0.1"
}, },
"time": "2022-06-27T13:49:35+00:00" "time": "2023-02-16T20:00:16+00:00"
}, },
{ {
"name": "laravel/dusk", "name": "laravel/dusk",
@ -15086,16 +15085,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.9.17", "version": "1.9.18",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "204e459e7822f2c586463029f5ecec31bb45a1f2" "reference": "f2d5cf71be91172a57c649770b73c20ebcffb0bf"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/204e459e7822f2c586463029f5ecec31bb45a1f2", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f2d5cf71be91172a57c649770b73c20ebcffb0bf",
"reference": "204e459e7822f2c586463029f5ecec31bb45a1f2", "reference": "f2d5cf71be91172a57c649770b73c20ebcffb0bf",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -15125,7 +15124,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/phpstan/phpstan/issues", "issues": "https://github.com/phpstan/phpstan/issues",
"source": "https://github.com/phpstan/phpstan/tree/1.9.17" "source": "https://github.com/phpstan/phpstan/tree/1.9.18"
}, },
"funding": [ "funding": [
{ {
@ -15141,7 +15140,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-02-08T12:25:00+00:00" "time": "2023-02-17T15:01:27+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@ -17310,30 +17309,28 @@
}, },
{ {
"name": "zircote/swagger-php", "name": "zircote/swagger-php",
"version": "3.3.7", "version": "3.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/zircote/swagger-php.git", "url": "https://github.com/zircote/swagger-php.git",
"reference": "e8c3bb316e385e93a0c7e8b2aa0681079244c381" "reference": "9d172471e56433b5c7061006b9a766f262a3edfd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/zircote/swagger-php/zipball/e8c3bb316e385e93a0c7e8b2aa0681079244c381", "url": "https://api.github.com/repos/zircote/swagger-php/zipball/9d172471e56433b5c7061006b9a766f262a3edfd",
"reference": "e8c3bb316e385e93a0c7e8b2aa0681079244c381", "reference": "9d172471e56433b5c7061006b9a766f262a3edfd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"doctrine/annotations": "^1.7", "doctrine/annotations": "*",
"ext-json": "*", "ext-json": "*",
"php": ">=7.2", "php": ">=7.2",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"symfony/finder": ">=2.2", "symfony/finder": ">=2.2",
"symfony/yaml": ">=3.3" "symfony/yaml": ">=3.3"
}, },
"require-dev": { "require-dev": {
"composer/package-versions-deprecated": "1.11.99.2", "friendsofphp/php-cs-fixer": "^2.16",
"friendsofphp/php-cs-fixer": "^2.17 || ^3.0", "phpunit/phpunit": ">=8"
"phpunit/phpunit": ">=8.5.14"
}, },
"bin": [ "bin": [
"bin/openapi" "bin/openapi"
@ -17377,9 +17374,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/zircote/swagger-php/issues", "issues": "https://github.com/zircote/swagger-php/issues",
"source": "https://github.com/zircote/swagger-php/tree/3.3.7" "source": "https://github.com/zircote/swagger-php/tree/3.1.0"
}, },
"time": "2023-01-03T21:17:10+00:00" "time": "2020-09-03T20:18:43+00:00"
} }
], ],
"aliases": [], "aliases": [],

View File

@ -201,7 +201,6 @@ return [
App\Providers\MultiDBProvider::class, App\Providers\MultiDBProvider::class,
App\Providers\ClientPortalServiceProvider::class, App\Providers\ClientPortalServiceProvider::class,
App\Providers\NinjaTranslationServiceProvider::class, App\Providers\NinjaTranslationServiceProvider::class,
// App\Providers\MailCssInlinerServiceProvider::class,
], ],
/* /*

View File

@ -1,18 +0,0 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Css Files
|--------------------------------------------------------------------------
|
| Css file of your style for your emails
| The content of these files will be added directly into the inliner
| Use absolute paths, ie. public_path('css/main.css')
|
*/
'css-files' => [],
];

View File

@ -16,6 +16,7 @@ use App\Models\CompanyGateway;
use App\Models\GatewayType; use App\Models\GatewayType;
use App\Models\Invoice; use App\Models\Invoice;
use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\MockAccountData; use Tests\MockAccountData;
use Tests\TestCase; use Tests\TestCase;
@ -26,7 +27,8 @@ use Tests\TestCase;
class CompanyGatewayTest extends TestCase class CompanyGatewayTest extends TestCase
{ {
use MockAccountData; use MockAccountData;
use DatabaseTransactions; // use DatabaseTransactions;
use RefreshDatabase;
protected function setUp() :void protected function setUp() :void
{ {

View File

@ -10,14 +10,17 @@
*/ */
namespace Tests\Feature; namespace Tests\Feature;
use App\DataMapper\CompanySettings; use Tests\TestCase;
use App\Models\Company;
use App\Models\Activity;
use Tests\MockAccountData;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
use App\DataMapper\CompanySettings;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Session;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
use Tests\MockAccountData; use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase; use Illuminate\Foundation\Testing\DatabaseTransactions;
/** /**
* @test * @test
@ -26,8 +29,9 @@ use Tests\TestCase;
class CompanySettingsTest extends TestCase class CompanySettingsTest extends TestCase
{ {
use MakesHash; use MakesHash;
use DatabaseTransactions; // use DatabaseTransactions;
use MockAccountData; use MockAccountData;
use RefreshDatabase;
public function setUp() :void public function setUp() :void
{ {
@ -179,6 +183,7 @@ class CompanySettingsTest extends TestCase
public function testCompanyNullValueMatrixPOST() public function testCompanyNullValueMatrixPOST()
{ {
$settings = CompanySettings::defaults(); $settings = CompanySettings::defaults();
$settings->reset_counter_date = null; $settings->reset_counter_date = null;

View File

@ -217,8 +217,8 @@ trait MockAccountData
$fake_email = $this->faker->email(); $fake_email = $this->faker->email();
$this->account = Account::factory()->create([ $this->account = Account::factory()->create([
'hosted_client_count' => 1000, 'hosted_client_count' => 1000000,
'hosted_company_count' => 1000, 'hosted_company_count' => 1000000,
]); ]);
$this->account->num_users = 3; $this->account->num_users = 3;

View File

@ -75,6 +75,51 @@ class PermissionsTest extends TestCase
$company_token->save(); $company_token->save();
} }
public function testHasExcludedPermissions()
{
$low_cu = CompanyUser::where(['company_id' => $this->company->id, 'user_id' => $this->user->id])->first();
$low_cu->permissions = '["view_client"]';
$low_cu->save();
$this->assertTrue($this->user->hasExcludedPermissions(["view_client"]));
$low_cu = CompanyUser::where(['company_id' => $this->company->id, 'user_id' => $this->user->id])->first();
$low_cu->permissions = 'view_client';
$low_cu->save();
$this->assertTrue($this->user->hasExcludedPermissions(["view_client"]));
}
public function testHasExcludedPermissions2()
{
$low_cu = CompanyUser::where(['company_id' => $this->company->id, 'user_id' => $this->user->id])->first();
$low_cu->permissions = '["view_client","edit_all"]';
$low_cu->save();
$this->assertFalse($this->user->hasExcludedPermissions(["view_client"], ['edit_all']));
$low_cu = CompanyUser::where(['company_id' => $this->company->id, 'user_id' => $this->user->id])->first();
$low_cu->permissions = 'view_client,edit_all';
$low_cu->save();
$this->assertFalse($this->user->hasExcludedPermissions(["view_client"], ['edit_all']));
$low_cu = CompanyUser::where(['company_id' => $this->company->id, 'user_id' => $this->user->id])->first();
$low_cu->permissions = 'view_client,view_all';
$low_cu->save();
$this->assertFalse($this->user->hasExcludedPermissions(["view_client"], ['view_all']));
$low_cu = CompanyUser::where(['company_id' => $this->company->id, 'user_id' => $this->user->id])->first();
$low_cu->permissions = 'view_client,view_invoice';
$low_cu->save();
$this->assertFalse($this->user->hasExcludedPermissions(["view_client"], ['view_invoice']));
}
public function testIntersectPermissions() public function testIntersectPermissions()
{ {
$low_cu = CompanyUser::where(['company_id' => $this->company->id, 'user_id' => $this->user->id])->first(); $low_cu = CompanyUser::where(['company_id' => $this->company->id, 'user_id' => $this->user->id])->first();
@ -212,8 +257,8 @@ class PermissionsTest extends TestCase
public function testExactPermissions() public function testExactPermissions()
{ {
$this->assertTrue($this->user->hasExactPermission("view_client")); $this->assertTrue($this->user->hasExactPermissionAndAll("view_client"));
$this->assertFalse($this->user->hasExactPermission("view_all")); $this->assertFalse($this->user->hasExactPermissionAndAll("view_all"));
} }
public function testMissingPermissions() public function testMissingPermissions()
@ -222,8 +267,8 @@ class PermissionsTest extends TestCase
$low_cu->permissions = '[""]'; $low_cu->permissions = '[""]';
$low_cu->save(); $low_cu->save();
$this->assertFalse($this->user->hasExactPermission("view_client")); $this->assertFalse($this->user->hasExactPermissionAndAll("view_client"));
$this->assertFalse($this->user->hasExactPermission("view_all")); $this->assertFalse($this->user->hasExactPermissionAndAll("view_all"));
} }
public function testViewAllValidPermissions() public function testViewAllValidPermissions()
@ -232,8 +277,8 @@ class PermissionsTest extends TestCase
$low_cu->permissions = '["view_all"]'; $low_cu->permissions = '["view_all"]';
$low_cu->save(); $low_cu->save();
$this->assertTrue($this->user->hasExactPermission("view_client")); $this->assertTrue($this->user->hasExactPermissionAndAll("view_client"));
$this->assertTrue($this->user->hasExactPermission("view_all")); $this->assertTrue($this->user->hasExactPermissionAndAll("view_all"));
} }
public function testReturnTypesOfStripos() public function testReturnTypesOfStripos()