'boolean', 'readonly' => 'boolean', 'ui' => 'object', ]; /** * Validation rules * * @param null $existing * @param bool $validateConfig * * @return array */ public static function rules($existing = null, $validateConfig = false) { $unique = Rule::unique('settings')->ignore($existing); return [ 'key' => ['required', $unique], 'config.*' => ($validateConfig ? ['required', 'valid_variable'] : []), ]; } /** * @return array */ public static function messages() { return [ 'config.*.valid_variable' => trans('environmentVariables.validation.name.invalid_variable_name'), ]; } /** * Get setting by key * * @param string $key * * @return Setting|null * @throws \Exception */ public static function byKey(string $key) { $settingCache = SettingCacheFactory::getSettingsCache(); $settingKey = $settingCache->createKey([ 'key' => $key, ]); $exists = $settingCache->has($settingKey); // if the setting is not in the cache, get it from the database and store it in the cache if ($exists) { $setting = $settingCache->get($settingKey); } else { $setting = (new self)->where('key', $key)->first(); $settingCache->set($settingKey, $setting); } return $setting; } /** * Get config by key * * @param $key * * @return array|null * @throws \Exception */ public static function configByKey($key) { $setting = self::byKey($key); return $setting instanceof self ? $setting->config : null; } public function scopeHidden($query) { return $query->where('hidden', true); } public function scopeNotHidden($query) { return $query->where('hidden', false); } public function getGroupAttribute() { if ($this->attributes['group'] === null) { return $this->attributes['group'] = 'System'; } return $this->attributes['group'] = $this->attributes['group']; } public function getConfigAttribute() { switch ($this->format) { case 'text': case 'textarea': case 'file': case 'choice': case 'range': return $this->attributes['config'] = $this->attributes['config']; case 'boolean': return $this->attributes['config'] = (bool) $this->attributes['config']; case 'object': if (is_string($this->attributes['config'])) { return $this->attributes['config'] = json_decode($this->attributes['config']); } elseif (is_object($this->attributes['config'])) { return $this->attributes['config']; } case 'array': case 'checkboxes': default: if (is_string($this->attributes['config'])) { return $this->attributes['config'] = json_decode($this->attributes['config'], true); } elseif (is_array($this->attributes['config'])) { return $this->attributes['config']; } } } /** * PMQL value alias for fulltext field * * @param string $value * * @return callable */ public function valueAliasFullText($value, $expression) { return function ($query) use ($value) { $this->scopeFilter($query, $value); }; } /** * Filter settings with a string * * @param $query * * @param $filter string */ public function scopeFilter($query, $filter) { $filter = '%' . mb_strtolower($filter) . '%'; $query->where(function ($query) use ($filter) { $query->where(DB::raw('LOWER(`key`)'), 'like', $filter) ->orWhere(DB::raw('LOWER(`name`)'), 'like', $filter) ->orWhere(DB::raw('LOWER(`helper`)'), 'like', $filter) ->orWhere(DB::raw('LOWER(`group`)'), 'like', $filter); }); return $query; } /** * Filter settings groups with a string * * @param $query * * @param $filter string */ public function notHiddenGroups($query, $filter) { $filter = '%' . mb_strtolower($filter) . '%'; $query->where(function ($query) use ($filter) { $query->where(DB::raw('LOWER(`group`)'), 'like', $filter); }); return $query; } /** * @return bool * @throws \Exception */ public static function loginIsDefault() { return stripos(self::getLogin(), 'processmaker-login') !== false; } /** * @return string * @throws \Exception */ public static function getLogin() { // default login $url = asset(config('app.settings.login_logo_path')); //custom login $setting = self::byKey('css-override'); if ($setting) { $mediaFile = $setting->getMedia(self::COLLECTION_CSS_LOGIN); foreach ($mediaFile as $media) { $url = $media->getFullUrl(); } } return $url . '?id=' . bin2hex(random_bytes(16)); } /** * @return string * @throws \Exception */ public static function getLogo() { // default logo $url = asset(config('app.settings.main_logo_path')); // custom logo if (config()->has($key = 'css-override')) { $setting = self::byKey($key); if ($setting instanceof self) { $mediaFile = $setting->getMedia(self::COLLECTION_CSS_LOGO); foreach ($mediaFile as $media) { $url = $media->getFullUrl(); } } } return $url; } /** * @return string * @throws \Exception */ public static function getIcon() { // default icon $url = asset(config('app.settings.icon_path')); // custom icon if (config()->has($key = 'css-override')) { $setting = self::byKey($key); if ($setting instanceof self) { $mediaFile = $setting->getMedia(self::COLLECTION_CSS_ICON); foreach ($mediaFile as $media) { $url = $media->getFullUrl(); } } } return $url . '?id=' . bin2hex(random_bytes(16)); } /** * @return string * @throws \Exception */ public static function getFavicon() { // default icon $url = asset(config('app.settings.favicon_path')); // custom icon if (config()->has($key = 'css-override')) { $setting = self::byKey($key); if ($setting instanceof self) { $mediaFile = $setting->getMedia(self::COLLECTION_CSS_FAVICON); foreach ($mediaFile as $media) { $url = $media->getFullUrl(); } } } return $url . '?id=' . bin2hex(random_bytes(16)); } /** * Get the groups related to the specific group_id * * @param int menuId * * @return array */ public static function groupsByMenu($menuId) { $query = self::query() ->select('group') ->groupBy('group') ->where('group_id', $menuId) ->orderBy('group', 'ASC') ->notHidden() ->pluck('group'); $response = $query->toArray(); $result = []; foreach ($response as &$value) { // Technical debts: we need to add int key to identify a group, currently this is a label $result[] = [ 'id' => $value, 'name' => $value, ]; } return $result; } /** * Update the group_id related to Settings * @param string $settingsGroup * @param null|int $id */ public static function updateSettingsGroup($settingsGroup, $id) { self::where('group', $settingsGroup)->whereNull('group_id')->chunk( 50, function ($settings) use ($id) { foreach ($settings as $setting) { if ($id !== null) { $setting->group_id = $id; $setting->save(); } } } ); } /** * Update the group_id related to Settings * @param string $settingsGroup * @param null|int $id */ public static function updateAllSettingsGroupId() { self::whereNull('group_id')->chunk(100, function ($settings) { $defaultId = SettingsMenus::EMAIL_MENU_GROUP; foreach ($settings as $setting) { // Define the value of 'menu_group' based on 'group' switch ($setting->group) { case 'Actions By Email': case 'Email Default Settings': $id = SettingsMenus::getId(SettingsMenus::EMAIL_MENU_GROUP); break; case 'Log-In Options': // Log-In and Password case 'LDAP': case 'SSO': // Single Sign-On case 'SCIM': case 'Session Control': case 'SSO - Auth0': case 'SSO - Atlassian': case 'SSO - Facebook': case 'SSO - GitHub': case 'SSO - Google': case 'SSO - Keycloak': case 'SSO - Microsoft': case 'SSO - SAML': $id = SettingsMenus::getId(SettingsMenus::LOG_IN_AUTH_MENU_GROUP); break; case 'User Signals': case 'Users': // Additional Properties $id = SettingsMenus::getId(SettingsMenus::USER_SETTINGS_MENU_GROUP); break; case 'IDP': // Intelligent Document Processing case 'DocuSign': case 'Plaid': case 'External Integrations': // Enterprise Integrations $id = SettingsMenus::getId(SettingsMenus::INTEGRATIONS_MENU_GROUP); break; case 'System': // System not related with settings menu $id = null; break; case 'Devlink': $id = null; break; default: // The default value if (preg_match('/^Email Server/', $setting->group)) { $id = SettingsMenus::getId(SettingsMenus::EMAIL_MENU_GROUP); } else { $id = SettingsMenus::getId($defaultId); } break; } if ($id !== null) { $setting->group_id = $id; $setting->save(); Log::info("Settings group {$setting->group} = {$setting->group_id} updated successfully"); } } }); } /** * Get the label used in grafana reports * * @return string */ public function getPrometheusMetricLabel(): string { return 'settings.' . $this->key; } }