added module activator

This commit is contained in:
Denis Duliçi 2023-10-25 12:40:52 +03:00
parent 1eb9c6d9bf
commit 4e858302b5
16 changed files with 528 additions and 339 deletions

View File

@ -3,6 +3,7 @@
namespace App\Exceptions\Trackers; namespace App\Exceptions\Trackers;
use App\Traits\Trackers as Base; use App\Traits\Trackers as Base;
use Akaunting\Version\Version;
use Throwable; use Throwable;
class Bugsnag class Bugsnag
@ -11,7 +12,7 @@ class Bugsnag
public static function beforeSend(Throwable $e): void public static function beforeSend(Throwable $e): void
{ {
app('bugsnag')->setAppVersion(version('short')); app('bugsnag')->setAppVersion(Version::short());
$tags = static::getTrackerTags(); $tags = static::getTrackerTags();

View File

@ -2,6 +2,7 @@
namespace App\Exceptions\Trackers; namespace App\Exceptions\Trackers;
use Akaunting\Version\Version;
use App\Traits\Trackers as Base; use App\Traits\Trackers as Base;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Sentry\Event; use Sentry\Event;
@ -14,7 +15,7 @@ class Sentry
public static function beforeSend(Event $event, ?EventHint $hint): ?Event public static function beforeSend(Event $event, ?EventHint $hint): ?Event
{ {
$event->setRelease(version('short')); $event->setRelease(Version::short());
$tags = static::getTrackerTags(); $tags = static::getTrackerTags();

View File

@ -52,25 +52,23 @@ class Settings extends Component
public function addSettingsOfModulesFromJsonFile($menu): void public function addSettingsOfModulesFromJsonFile($menu): void
{ {
// Get enabled modules // Get enabled modules
$enabled_modules = Module::enabled()->get(); $enabled_modules = module()->allEnabled();
$order = 110; $order = 110;
foreach ($enabled_modules as $module) { foreach ($enabled_modules as $module) {
$m = module($module->alias); // Check if the module has settings
if (empty($module->get('settings'))) {
// Check if the module exists and has settings
if (!$m || empty($m->get('settings'))) {
continue; continue;
} }
if ($this->user->cannot('read-' . $m->getAlias() . '-settings')) { if ($this->user->cannot('read-' . $module->getAlias() . '-settings')) {
continue; continue;
} }
$menu->route('settings.module.edit', $m->getName(), ['alias' => $m->getAlias()], $m->get('setting_order', $order), [ $menu->route('settings.module.edit', $module->getName(), ['alias' => $module->getAlias()], $module->get('setting_order', $order), [
'icon' => $m->get('icon', 'custom-akaunting'), 'icon' => $module->get('icon', 'custom-akaunting'),
'search_keywords' => $m->getDescription(), 'search_keywords' => $module->getDescription(),
]); ]);
$order += 10; $order += 10;

View File

@ -2,15 +2,14 @@
namespace App\Http\Middleware; namespace App\Http\Middleware;
use App\Traits\Companies;
use App\Traits\Users; use App\Traits\Users;
use Closure; use Closure;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
class IdentifyCompany class IdentifyCompany
{ {
use Users; use Companies, Users;
public $request;
/** /**
* Handle an incoming request. * Handle an incoming request.
@ -57,44 +56,4 @@ class IdentifyCompany
return $next($this->request); return $next($this->request);
} }
protected function getCompanyId()
{
if ($company_id = company_id()) {
return $company_id;
}
if ($this->request->isApi()) {
return $this->getCompanyIdFromApi();
}
return $this->getCompanyIdFromWeb();
}
protected function getCompanyIdFromWeb()
{
return $this->getCompanyIdFromRoute() ?: ($this->getCompanyIdFromQuery() ?: $this->getCompanyIdFromHeader());
}
protected function getCompanyIdFromApi()
{
$company_id = $this->getCompanyIdFromQuery() ?: $this->getCompanyIdFromHeader();
return $company_id ?: $this->getFirstCompanyOfUser()?->id;
}
protected function getCompanyIdFromRoute()
{
return (int) $this->request->route('company_id');
}
protected function getCompanyIdFromQuery()
{
return (int) $this->request->query('company_id');
}
protected function getCompanyIdFromHeader()
{
return (int) $this->request->header('X-Company');
}
} }

View File

@ -36,9 +36,8 @@ trait Cloud
]); ]);
} }
// @deprecated 3.1
public function isCloud() public function isCloud()
{ {
return request()->isCloudHost(); return request()->getHost() == config('cloud.host', 'app.akaunting.com');
} }
} }

62
app/Traits/Companies.php Normal file
View File

@ -0,0 +1,62 @@
<?php
namespace App\Traits;
use App\Traits\Users;
trait Companies
{
use Users;
public $request = null;
public function getCompanyId()
{
if ($company_id = company_id()) {
return $company_id;
}
$request = $this->request ?: request();
if ($this->isCompanyApiRequest($request)) {
return $this->getCompanyIdFromApi($request);
}
return $this->getCompanyIdFromWeb($request);
}
public function getCompanyIdFromWeb($request)
{
return $this->getCompanyIdFromRoute($request) ?: ($this->getCompanyIdFromQuery($request) ?: $this->getCompanyIdFromHeader($request));
}
public function getCompanyIdFromApi($request)
{
$company_id = $this->getCompanyIdFromQuery($request) ?: $this->getCompanyIdFromHeader($request);
return $company_id ?: $this->getFirstCompanyOfUser()?->id;
}
public function getCompanyIdFromRoute($request)
{
$route_id = (int) $request->route('company_id');
$segment_id = (int) $request->segment(1);
return $route_id ?: $segment_id;
}
public function getCompanyIdFromQuery($request)
{
return (int) $request->query('company_id');
}
public function getCompanyIdFromHeader($request)
{
return (int) $request->header('X-Company');
}
public function isCompanyApiRequest($request)
{
return $request->is(config('api.prefix') . '/*');
}
}

View File

@ -3,6 +3,7 @@
namespace App\Traits; namespace App\Traits;
use App\Models\Module\Module; use App\Models\Module\Module;
use App\Traits\Cloud;
use App\Traits\SiteApi; use App\Traits\SiteApi;
use App\Utilities\Date; use App\Utilities\Date;
use App\Utilities\Info; use App\Utilities\Info;
@ -415,29 +416,7 @@ trait Modules
return false; return false;
} }
if (request()->isCloudHost()) { return module($alias)->enabled();
static $modules;
if (empty($modules)) {
$modules = Cache::get('cloud.companies.' . company_id() . '.modules.installed', []);
}
if (in_array($alias, $modules)) {
return true;
}
return false;
}
if (module($alias)->disabled()) {
return false;
}
if (! Module::alias($alias)->enabled()->first()) {
return false;
}
return true;
} }
public function moduleIsDisabled($alias): bool public function moduleIsDisabled($alias): bool
@ -445,6 +424,23 @@ trait Modules
return ! $this->moduleIsEnabled($alias); return ! $this->moduleIsEnabled($alias);
} }
public function loadSubscriptions()
{
$key = 'apps.subscriptions';
return Cache::remember($key, Date::now()->addHours(6), function () {
$data = [];
if (! is_cloud()) {
$data['headers'] = [
'X-Akaunting-Modules' => implode(',', module()->getAvailable()),
];
}
return (array) static::getResponseData('GET', 'apps/subscriptions', $data);
});
}
public function loadSuggestions() public function loadSuggestions()
{ {
$key = 'apps.suggestions'; $key = 'apps.suggestions';
@ -496,6 +492,17 @@ trait Modules
}); });
} }
public function getSubscription($alias)
{
$data = $this->loadSubscriptions();
if (! empty($data) && array_key_exists($alias, $data)) {
return $data[$alias];
}
return false;
}
public function getSuggestions($path) public function getSuggestions($path)
{ {
$data = $this->loadSuggestions(); $data = $this->loadSuggestions();

View File

@ -3,6 +3,7 @@
namespace App\Traits; namespace App\Traits;
use App\Utilities\Info; use App\Utilities\Info;
use Akaunting\Version\Version;
use Exception; use Exception;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException; use GuzzleHttp\Exception\ConnectException;
@ -20,7 +21,7 @@ trait SiteApi
'Authorization' => 'Bearer ' . setting('apps.api_key'), 'Authorization' => 'Bearer ' . setting('apps.api_key'),
'Accept' => 'application/json', 'Accept' => 'application/json',
'Referer' => app()->runningInConsole() ? config('app.url') : url('/'), 'Referer' => app()->runningInConsole() ? config('app.url') : url('/'),
'Akaunting' => version('short'), 'Akaunting' => Version::short(),
'Language' => language()->getShortCode(), 'Language' => language()->getShortCode(),
'Information' => json_encode(Info::all()), 'Information' => json_encode(Info::all()),
]; ];

View File

@ -2,10 +2,10 @@
namespace App\Utilities; namespace App\Utilities;
use Akaunting\Version\Version;
use App\Models\Common\Company; use App\Models\Common\Company;
use App\Models\Common\Contact; use App\Models\Common\Contact;
use App\Models\Document\Document; use App\Models\Document\Document;
use App\Traits\Cloud;
use Composer\InstalledVersions; use Composer\InstalledVersions;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@ -20,7 +20,7 @@ class Info
'ip' => static::ip(), 'ip' => static::ip(),
]; ];
if (! empty($info) || request()->isCloudHost()) { if (! empty($info) || is_cloud()) {
return array_merge($info, $basic); return array_merge($info, $basic);
} }
@ -44,7 +44,7 @@ class Info
} }
$versions = [ $versions = [
'akaunting' => version('short'), 'akaunting' => Version::short(),
'laravel' => InstalledVersions::getPrettyVersion('laravel/framework'), 'laravel' => InstalledVersions::getPrettyVersion('laravel/framework'),
'php' => static::phpVersion(), 'php' => static::phpVersion(),
'mysql' => static::mysqlVersion(), 'mysql' => static::mysqlVersion(),

View File

@ -0,0 +1,145 @@
<?php
namespace App\Utilities;
use Akaunting\Module\Contracts\ActivatorInterface;
use Akaunting\Module\Module;
use App\Models\Module\Module as Model;
use App\Traits\Companies;
use App\Traits\Modules;
use Illuminate\Cache\CacheManager as Cache;
use Illuminate\Config\Repository as Config;
use Illuminate\Container\Container;
class ModuleActivator implements ActivatorInterface
{
use Companies, Modules;
public Cache $cache;
public Config $config;
public array $statuses;
public int $company_id;
public function __construct(Container $app)
{
$this->cache = $app['cache'];
$this->config = $app['config'];
$this->statuses = $this->getStatuses();
}
public function is(Module $module, bool $active): bool
{
if (! isset($this->statuses[$module->getAlias()])) {
if (empty($this->company_id)) {
$company_id = $this->getCompanyId();
if (empty($company_id)) {
return false;
}
$this->company_id = $company_id;
}
$model = Model::companyId($this->company_id)->alias($module->getAlias())->get('enabled')->first();
$status = $model ? $model->enabled : false;
$this->setActive($module, $status);
}
return $this->statuses[$module->getAlias()] === $active;
}
public function enable(Module $module): void
{
$this->setActive($module, true);
}
public function disable(Module $module): void
{
$this->setActive($module, false);
}
public function setActive(Module $module, bool $active): void
{
$this->statuses[$module->getAlias()] = $active;
Model::alias($module->getAlias())->updateOrCreate([
'enabled' => $active,
], [
'company_id' => $this->company_id,
'alias' => $module->getAlias(),
'created_from' => 'core::activator',
]);
$this->flushCache();
}
public function delete(Module $module): void
{
if (! isset($this->statuses[$module->getAlias()])) {
return;
}
unset($this->statuses[$module->getAlias()]);
Model::alias($module->getAlias())->delete();
$this->flushCache();
}
public function getStatuses(): array
{
if (! $this->config->get('module.cache.enabled')) {
return $this->readDatabase();
}
$key = $this->config->get('module.cache.key') . '.statuses';
$lifetime = $this->config->get('module.cache.lifetime');
return $this->cache->remember($key, $lifetime, function () {
return $this->readDatabase();
});
}
public function readDatabase(): array
{
$company_id = $this->getCompanyId();
if (empty($company_id)) {
return [];
}
$this->company_id = $company_id;
$modules = Model::companyId($this->company_id)->pluck('enabled', 'alias')->toArray();
foreach ($modules as $alias => $enabled) {
$subscription = $this->getSubscription($alias);
if (! is_object($subscription)) {
continue;
}
$modules[$alias] = $subscription->status;
}
return $modules;
}
public function reset(): void
{
$this->statuses = [];
$this->flushCache();
}
public function flushCache(): void
{
$key = $this->config->get('module.cache.key') . '.statuses';
$this->cache->forget($key);
}
}

View File

@ -114,7 +114,7 @@ class Reports
return true; return true;
} }
if (Module::alias($alias)->enabled()->first()) { if (module_is_enabled($alias)) {
return true; return true;
} }

View File

@ -156,7 +156,7 @@ class Widgets
return true; return true;
} }
if (Module::alias($alias)->enabled()->first()) { if (module_is_enabled($alias)) {
return true; return true;
} }

View File

@ -1,6 +1,7 @@
<?php <?php
use App\Models\Common\Company; use App\Models\Common\Company;
use App\Traits\Cloud;
use App\Traits\DateTime; use App\Traits\DateTime;
use App\Traits\Sources; use App\Traits\Sources;
use App\Traits\Modules; use App\Traits\Modules;
@ -95,9 +96,7 @@ if (! function_exists('module_is_enabled')) {
*/ */
function module_is_enabled(string $alias): bool function module_is_enabled(string $alias): bool
{ {
$module = new class() { $module = new class() { use Modules; };
use Modules;
};
return $module->moduleIsEnabled($alias); return $module->moduleIsEnabled($alias);
} }
@ -129,9 +128,7 @@ if (! function_exists('source_name')) {
*/ */
function source_name(string|null $alias = null): string function source_name(string|null $alias = null): string
{ {
$tmp = new class() { $tmp = new class() { use Sources; };
use Sources;
};
return $tmp->getSourceName(null, $alias); return $tmp->getSourceName(null, $alias);
} }
@ -307,3 +304,12 @@ if (! function_exists('search_string_value')) {
return $search->getSearchStringValue($name, $default, $input); return $search->getSearchStringValue($name, $default, $input);
} }
} }
if (! function_exists('is_cloud')) {
function is_cloud(): bool
{
$cloud = new class() { use Cloud; };
return $cloud->isCloud();
}
}

View File

@ -32,7 +32,7 @@
"akaunting/laravel-firewall": "^2.0", "akaunting/laravel-firewall": "^2.0",
"akaunting/laravel-language": "^1.0", "akaunting/laravel-language": "^1.0",
"akaunting/laravel-menu": "^3.0", "akaunting/laravel-menu": "^3.0",
"akaunting/laravel-module": "^3.0", "akaunting/laravel-module": "^4.0",
"akaunting/laravel-money": "^5.0", "akaunting/laravel-money": "^5.0",
"akaunting/laravel-mutable-observer": "^2.0", "akaunting/laravel-mutable-observer": "^2.0",
"akaunting/laravel-setting": "^1.2", "akaunting/laravel-setting": "^1.2",

494
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -187,4 +187,14 @@ return [
'composer' => 'register', 'composer' => 'register',
], ],
/*
|--------------------------------------------------------------------------
| Activator
|--------------------------------------------------------------------------
|
| Here is the activator class.
|
*/
'activator' => env('MODULE_ACTIVATOR', \App\Utilities\ModuleActivator::class),
]; ];