Files
Heimdall/app/Setting.php
T
KodeStar ad9baffa62 Only offer pinned tags as the default tag
The default_tag dropdown was populated from every tag (type=1), but the
dashboard taglist only renders pinned tags. Selecting an unpinned tag as the
default therefore triggered a click on a taglist entry that does not exist,
silently doing nothing. Filter the option queries in both Setting accessors to
pinned tags so only selectable tags are offered, and assert an unpinned tag is
excluded.

Also drop the unused $data['default_tag'] assignment in ItemController: the
taglist partial reads the setting directly via Setting::fetch(), so the view
variable was never consumed.
2026-07-08 18:26:19 +01:00

315 lines
11 KiB
PHP

<?php
namespace App;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Http\Request;
use Illuminate\Session\SessionManager;
use Illuminate\Session\Store;
use enshrined\svgSanitize\Sanitizer;
/**
* App\Setting
*
* @mixin Builder
* @property int $id
* @property int $group_id
* @property string $key
* @property string $type
* @property string|null $options
* @property string $label
* @property string|null $value
* @property string $order
* @property int $system
* @property-read mixed $edit_value
* @property-read mixed $list_value
* @property-read \App\SettingGroup|null $group
* @property-read \Illuminate\Database\Eloquent\Collection|\App\User[] $users
* @property-read int|null $users_count
* @method static Builder|Setting newModelQuery()
* @method static Builder|Setting newQuery()
* @method static Builder|Setting query()
* @method static Builder|Setting whereGroupId($value)
* @method static Builder|Setting whereId($value)
* @method static Builder|Setting whereKey($value)
* @method static Builder|Setting whereLabel($value)
* @method static Builder|Setting whereOptions($value)
* @method static Builder|Setting whereOrder($value)
* @method static Builder|Setting whereSystem($value)
* @method static Builder|Setting whereType($value)
* @method static Builder|Setting whereValue($value)
*/
class Setting extends Model
{
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'settings';
protected $fillable = [
'id', 'group_id', 'key', 'type', 'options', 'label', 'value', 'order', 'system',
];
/**
* Tell the Model this Table doesn't support timestamps.
*
* @var bool
*/
public $timestamps = false;
/**
* Cache storage for Settings.
*
* @var array
*/
protected static $cache = [];
public static function getInput(Request $request): object
{
$image = $request->file('value');
if ($image && $image->getClientOriginalExtension() === 'svg') {
$sanitizer = new Sanitizer();
$sanitizedSvg = $sanitizer->sanitize(file_get_contents($image->getRealPath()));
// Verify that the sanitization removed malicious content
if (strpos($sanitizedSvg, '<script>') !== false) {
throw new \Exception('SVG contains malicious content and cannot be uploaded.');
}
// Save the sanitized SVG back to the file
file_put_contents($image->getRealPath(), $sanitizedSvg);
}
return (object) [
'value' => $request->input('value'),
'image' => $image,
];
}
public function getListValueAttribute()
{
if ((bool) $this->system === true) {
$value = self::_fetch($this->key);
} else {
$value = self::fetch($this->key);
}
$this->value = $value;
switch ($this->type) {
case 'image':
if (! empty($this->value)) {
$value = '<a href="'.asset('storage/'.$this->value).'" title="'.
__('app.settings.view').
'" target="_blank">'.
__('app.settings.view').
'</a>';
} else {
$value = __('app.options.none');
}
break;
case 'boolean':
if ((bool) $this->value === true) {
$value = __('app.options.yes');
} else {
$value = __('app.options.no');
}
break;
case 'select':
if (! empty($this->value) && $this->value !== 'none') {
$options = (array) json_decode($this->options);
if ($this->key === 'search_provider') {
$options = Search::providers()->pluck('name', 'id')->toArray();
} elseif ($this->key === 'default_tag') {
$options = [];
$tags = Item::where('type', 1)->where('id', '>', 0)->pinned()->orderBy('title', 'asc')->get();
foreach ($tags as $tag) {
$options[$tag->tag_url] = $tag->title;
}
}
$value = (array_key_exists($this->value, $options))
? __($options[$this->value])
: __('app.options.none');
} else {
$value = __('app.options.none');
}
break;
default:
$value = __($this->value);
break;
}
return $value;
}
public function getEditValueAttribute()
{
if ((bool) $this->system === true) {
$value = self::_fetch($this->key);
} else {
$value = self::fetch($this->key);
}
$this->value = $value;
switch ($this->type) {
case 'image':
$value = '';
if (isset($this->value) && !empty($this->value)) {
$value .= '<a class="setting-view-image" href="' .
asset('storage/' . $this->value) .
'" title="' .
__('app.settings.view') .
'" target="_blank"><img src="' .
asset('storage/' .
$this->value) .
'" /></a>';
}
$value .= '<input type="file" name="value" class="form-control" />';
if (isset($this->value) && !empty($this->value)) {
$value .= '<a class="settinglink" href="' .
route('settings.clear', $this->id) .
'" title="' .
__('app.settings.remove') .
'">' .
__('app.settings.reset') .
'</a>';
}
break;
case 'boolean':
$checked = false;
if (isset($this->value) && (bool)$this->value === true) {
$checked = true;
}
$set_checked = ($checked) ? ' checked="checked"' : '';
$value = '
<input type="hidden" name="value" value="0" />
<label class="switch">
<input type="checkbox" name="value" value="1"' . $set_checked . ' />
<span class="slider round"></span>
</label>';
break;
case 'select':
$options = json_decode($this->options);
if ($this->key === 'search_provider') {
$options = Search::providers()->pluck('name', 'id');
} elseif ($this->key === 'default_tag') {
$options = ['' => 'app.options.none'];
$tags = Item::where('type', 1)->where('id', '>', 0)->pinned()->orderBy('title', 'asc')->get();
foreach ($tags as $tag) {
$options[$tag->tag_url] = $tag->title;
}
}
$value = '<select name="value" class="form-control">';
foreach ($options as $key => $opt) {
$value .= '<option value="' . $key . '" ' . (($this->value == $key) ? 'selected' : '') . '>' . __($opt) . '</option>';
}
$value .= '</select>';
break;
case 'textarea':
$value = '<textarea name="value" class="form-control" cols="44" rows="15">' . htmlspecialchars($this->value, ENT_QUOTES, 'UTF-8') . '</textarea>';
break;
default:
$value = '<input type="text" name="value" class="form-control" value="' . htmlspecialchars($this->value, ENT_QUOTES, 'UTF-8') . '" />';
break;
}
return $value;
}
public function group(): BelongsTo
{
return $this->belongsTo(\App\SettingGroup::class, 'group_id');
}
/**
*
* @return mixed
*/
public static function fetch(string $key)
{
$user = self::user();
return self::_fetch($key, $user);
}
// @codingStandardsIgnoreStart
/**
*
* @return mixed
*/
public static function _fetch(string $key, $user = null)
{
// @codingStandardsIgnoreEnd
//$cachekey = ($user === null) ? $key : $key.'-'.$user->id;
//if (Setting::cached($cachekey)) {
// return Setting::$cache[$cachekey];
//} else {
$find = self::where('key', '=', $key)->first();
if (! is_null($find)) {
if ((bool) $find->system === true) { // if system variable use global value
$value = $find->value;
} else { // not system variable so use user specific value
// check if user specified value has been set
//print_r($user);
$usersetting = $user->settings()->where('id', $find->id)->first();
//print_r($user->settings);
//die(var_dump($usersetting));
//->pivot->value;
//echo "user: ".$user->id." --- ".$usersettings;
if (isset($usersetting) && ! empty($usersetting)) {
$value = $usersetting->pivot->uservalue;
} else { // if not get default from base setting
//$user->settings()->save($find, ['value' => $find->value]);
//$has_setting = $user->settings()->where('id', $find->id)->exists();
//if($has_setting) {
// $user->settings()->updateExistingPivot($find->id, ['uservalue' => (string)$find->value]);
//} else {
// $user->settings()->save($find, ['uservalue' => (string)$find->value]);
//}
$value = $find->value;
}
}
//Setting::add($cachekey, $value);
return $value;
} else {
return false;
}
//}
}
/**
* @param $value
*/
public static function add(string $key, $value)
{
self::$cache[$key] = $value;
}
public static function cached(string $key): bool
{
return array_key_exists($key, self::$cache);
}
/**
* The users that belong to the setting.
*/
public function users(): BelongsToMany
{
return $this->belongsToMany(\App\User::class)->using(\App\SettingUser::class)->withPivot('uservalue');
}
/**
* @return \Illuminate\Contracts\Foundation\Application|SessionManager|Store|mixed
*/
public static function user()
{
return User::currentUser();
}
}