mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-04-18 00:02:15 +00:00
Merge branch 'fraud-prevention-mechanism'
# Conflicts: # public/chunks/admin.js # public/chunks/payments/settings.js # public/chunks/platform.js # public/chunks/settings.js # public/chunks/status-check.js # public/css/tailwind.css # public/js/main.js # public/mix-manifest.json # src/App/Providers/AppServiceProvider.php # tests/Domain/Admin/AdminTest.php
This commit is contained in:
@@ -27,6 +27,49 @@ class AppServiceProvider extends ServiceProvider
|
||||
// TODO: temporary
|
||||
config()->set('session.lifetime', 15120);
|
||||
|
||||
// Set subscription config
|
||||
$this->setSubscriptionConfig();
|
||||
|
||||
// Set app locale
|
||||
$this->setLocale();
|
||||
|
||||
// Get all migrations with all directories
|
||||
$this->setMigrations();
|
||||
}
|
||||
|
||||
private function setMigrations(): void
|
||||
{
|
||||
$mainPath = database_path('migrations');
|
||||
$directories = glob($mainPath . '/*', GLOB_ONLYDIR);
|
||||
|
||||
$this->loadMigrationsFrom(
|
||||
array_merge([$mainPath], $directories)
|
||||
);
|
||||
}
|
||||
|
||||
private function setSubscriptionConfig(): void
|
||||
{
|
||||
if (app()->runningUnitTests()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = getAllSettings();
|
||||
|
||||
config([
|
||||
'subscription.metered_billing.fraud_prevention_mechanism' => [
|
||||
'usage_bigger_than_balance' => [
|
||||
'active' => isset($settings->usage_bigger_than_balance) ? intval($settings->usage_bigger_than_balance) : true,
|
||||
],
|
||||
'limit_usage_in_new_accounts' => [
|
||||
'active' => isset($settings->limit_usage_in_new_accounts) ? intval($settings->limit_usage_in_new_accounts) : true,
|
||||
'amount' => isset($settings->limit_usage_in_new_accounts_amount) ? intval($settings->limit_usage_in_new_accounts_amount) : 20,
|
||||
],
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
private function setLocale(): void
|
||||
{
|
||||
try {
|
||||
$app_locale = get_settings('language') ?? 'en';
|
||||
} catch (\PDOException $e) {
|
||||
@@ -38,21 +81,5 @@ class AppServiceProvider extends ServiceProvider
|
||||
|
||||
// Set locale for carbon dates
|
||||
setlocale(LC_TIME, $app_locale . '_' . mb_strtoupper($app_locale));
|
||||
|
||||
// Get all migrations with all directories
|
||||
$this->loadMigrationsFrom(
|
||||
$this->get_migration_paths()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function get_migration_paths(): array
|
||||
{
|
||||
$mainPath = database_path('migrations');
|
||||
$directories = glob($mainPath . '/*', GLOB_ONLYDIR);
|
||||
|
||||
return array_merge([$mainPath], $directories);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ namespace App\Users\Models;
|
||||
|
||||
use ByteUnits\Metric;
|
||||
use Illuminate\Support\Str;
|
||||
use BadMethodCallException;
|
||||
use Domain\Files\Models\File;
|
||||
use Domain\Folders\Models\Folder;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
@@ -196,10 +197,14 @@ class User extends Authenticatable implements MustVerifyEmail
|
||||
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
if (str_starts_with($method, 'can')) {
|
||||
return resolve(RestrictionsManager::class)
|
||||
->driver()
|
||||
->$method($this, ...$parameters);
|
||||
try {
|
||||
if (str_starts_with($method, 'can') || str_starts_with($method, 'get')) {
|
||||
return resolve(RestrictionsManager::class)
|
||||
->driver()
|
||||
->$method($this, ...$parameters);
|
||||
}
|
||||
} catch (BadMethodCallException $e) {
|
||||
return parent::__call($method, $parameters);
|
||||
}
|
||||
|
||||
return parent::__call($method, $parameters);
|
||||
|
||||
@@ -69,6 +69,7 @@ class UserResource extends JsonResource
|
||||
'canCreateFolder' => $this->canCreateFolder(),
|
||||
'canCreateTeamFolder' => $this->canCreateTeamFolder(),
|
||||
'canInviteTeamMembers' => $this->canInviteTeamMembers(),
|
||||
'reason' => $this->getRestrictionReason(),
|
||||
],
|
||||
$this->mergeWhen($isFixedSubscription, fn () => [
|
||||
'limitations' => $this->limitations->summary(),
|
||||
|
||||
@@ -47,4 +47,9 @@ class DefaultRestrictionsEngine implements RestrictionsEngine
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getRestrictionReason(User $user): string|null
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,4 +43,9 @@ class FixedBillingRestrictionsEngine implements RestrictionsEngine
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getRestrictionReason(User $user): string|null
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,26 +8,46 @@ class MeteredBillingRestrictionsEngine implements RestrictionsEngine
|
||||
{
|
||||
public function canUpload(User $user, int $fileSize = 0): bool
|
||||
{
|
||||
// Check the count of the dunning emails
|
||||
if ($this->getDunningSequenceCount($user) === 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disable upload when user has more than 3 failed payments
|
||||
return ! ($user->failedPayments()->count() >= 3);
|
||||
return $this->checkFailedPayments($user);
|
||||
}
|
||||
|
||||
public function canDownload(User $user): bool
|
||||
{
|
||||
// Check the count of the dunning emails
|
||||
if ($this->getDunningSequenceCount($user) === 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disable download when user has more than 3 failed payments
|
||||
return ! ($user->failedPayments()->count() >= 3);
|
||||
return $this->checkFailedPayments($user);
|
||||
}
|
||||
|
||||
public function canCreateFolder(User $user): bool
|
||||
{
|
||||
// Check the count of the dunning emails
|
||||
if ($this->getDunningSequenceCount($user) === 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disable create folder when user has more than 3 failed payments
|
||||
return ! ($user->failedPayments()->count() >= 3);
|
||||
return $this->checkFailedPayments($user);
|
||||
}
|
||||
|
||||
public function canCreateTeamFolder(User $user): bool
|
||||
{
|
||||
// Check the count of the dunning emails
|
||||
if ($this->getDunningSequenceCount($user) === 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disable create folder when user has more than 3 failed payments
|
||||
return ! ($user->failedPayments()->count() >= 3);
|
||||
return $this->checkFailedPayments($user);
|
||||
}
|
||||
|
||||
public function canInviteTeamMembers(User $user, array $newInvites = []): bool
|
||||
@@ -37,7 +57,38 @@ class MeteredBillingRestrictionsEngine implements RestrictionsEngine
|
||||
|
||||
public function canVisitShared(User $user): bool
|
||||
{
|
||||
// Check the count of the dunning emails
|
||||
if ($this->getDunningSequenceCount($user) === 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disable share visit when user has more than 3 failed payments
|
||||
return ! ($user->failedPayments()->count() >= 3);
|
||||
return $this->checkFailedPayments($user);
|
||||
}
|
||||
|
||||
public function getRestrictionReason(User $user): string|null
|
||||
{
|
||||
if ($this->getDunningSequenceCount($user) === 3) {
|
||||
return match ($user->dunning->type) {
|
||||
'limit_usage_in_new_accounts' => 'Please make your first payment to cover your usage.',
|
||||
'usage_bigger_than_balance' => 'Please increase your account balance higher than your monthly usage.',
|
||||
};
|
||||
}
|
||||
|
||||
if (! $this->checkFailedPayments($user)) {
|
||||
return 'Please update your credit card to pay your usage.';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getDunningSequenceCount(User $user): int
|
||||
{
|
||||
return cache()->remember("dunning-count.$user->id", 3600, fn () => $user?->dunning->sequence ?? 0);
|
||||
}
|
||||
|
||||
private function checkFailedPayments(User $user): bool
|
||||
{
|
||||
return cache()->remember("failed-payments-count.$user->id", 3600, fn () => !($user->failedPayments()->count() >= 3));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,4 +16,6 @@ interface RestrictionsEngine
|
||||
public function canInviteTeamMembers(User $user, array $newInvites = []): bool;
|
||||
|
||||
public function canVisitShared(User $user): bool;
|
||||
|
||||
public function getRestrictionReason(User $user): string|null;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
namespace Domain\Subscriptions\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use VueFileManager\Subscription\Domain\DunningEmails\Models\Dunning;
|
||||
|
||||
class DunningEmailToCoverAccountUsageNotification extends Notification implements ShouldQueue
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public function __construct(
|
||||
private Dunning $dunning
|
||||
) {
|
||||
}
|
||||
|
||||
public function via(): array
|
||||
{
|
||||
return ['mail', 'database', 'broadcast'];
|
||||
}
|
||||
|
||||
public function toMail(): MailMessage
|
||||
{
|
||||
$message = $this->dunningMessages();
|
||||
$index = $this->dunning->sequence - 1;
|
||||
|
||||
return (new MailMessage)
|
||||
->subject($message[$this->dunning->type][$index]['subject'])
|
||||
->greeting(__('Hi there'))
|
||||
->line($message[$this->dunning->type][$index]['line'])
|
||||
->action(__t('show_billing'), url('/user/settings/billing'))
|
||||
->salutation(__('Regards'));
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
$message = $this->dunningMessages();
|
||||
$index = $this->dunning->sequence - 1;
|
||||
|
||||
return [
|
||||
'category' => 'payment-alert',
|
||||
'title' => $message[$this->dunning->type][$index]['subject'],
|
||||
'description' => __t('dunning_notification_description'),
|
||||
'action' => [
|
||||
'type' => 'route',
|
||||
'params' => [
|
||||
'route' => __t('billing'),
|
||||
'button' => __t('show_billing'),
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function dunningMessages(): array
|
||||
{
|
||||
return [
|
||||
'limit_usage_in_new_accounts' => [
|
||||
[
|
||||
'subject' => __t('limit_usage_in_new_accounts_1_subject'),
|
||||
'line' => __t('limit_usage_in_new_accounts_1_line'),
|
||||
],
|
||||
[
|
||||
'subject' => __t('limit_usage_in_new_accounts_2_subject'),
|
||||
'line' => __t('limit_usage_in_new_accounts_2_line'),
|
||||
],
|
||||
[
|
||||
'subject' => __t('limit_usage_in_new_accounts_3_subject'),
|
||||
'line' => __t('limit_usage_in_new_accounts_3_line'),
|
||||
],
|
||||
],
|
||||
'usage_bigger_than_balance' => [
|
||||
[
|
||||
'subject' => __t("usage_bigger_than_balance_1_subject"),
|
||||
'line' => __t('usage_bigger_than_balance_1_line'),
|
||||
],
|
||||
[
|
||||
'subject' => __t('usage_bigger_than_balance_2_subject'),
|
||||
'line' => __t('usage_bigger_than_balance_2_line'),
|
||||
],
|
||||
[
|
||||
'subject' => __t('usage_bigger_than_balance_3_subject'),
|
||||
'line' => __t('usage_bigger_than_balance_3_line'),
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user