mirror of
https://github.com/pelican-dev/panel.git
synced 2025-05-20 00:34:44 +02:00
Fix translations for activity logs (#907)
* fix translations for activity logs * add backwards compatibility for old logs * update lang file * small cleanup * fix singular/ plural for "file" * fix for "rename" + disable bulk move (because it's not working)
This commit is contained in:
parent
262e2fd09a
commit
37ba62410f
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Filament\Server\Resources\ActivityResource\Pages;
|
||||
|
||||
use App\Filament\Admin\Resources\UserResource\Pages\EditUser;
|
||||
use App\Filament\Server\Resources\ActivityResource;
|
||||
use App\Models\ActivityLog;
|
||||
use App\Models\User;
|
||||
@ -20,12 +21,16 @@ class ListActivities extends ListRecords
|
||||
->columns([
|
||||
TextColumn::make('event')
|
||||
->html()
|
||||
->formatStateUsing(fn ($state, ActivityLog $activityLog) => __('activity.'.str($state)->replace(':', '.'))) // TODO: convert properties to a format that trans likes, see ActivityLogEntry.tsx - wrapProperties
|
||||
->description(fn ($state) => $state),
|
||||
->description(fn ($state) => $state)
|
||||
->formatStateUsing(function ($state, ActivityLog $activityLog) {
|
||||
$properties = $activityLog->wrapProperties();
|
||||
|
||||
return trans_choice('activity.'.str($state)->replace(':', '.'), array_get($properties, 'count', 1), $properties);
|
||||
}),
|
||||
TextColumn::make('user')
|
||||
->state(fn (ActivityLog $activityLog) => $activityLog->actor instanceof User ? $activityLog->actor->username : 'System')
|
||||
->tooltip(fn (ActivityLog $activityLog) => auth()->user()->can('seeIps activityLog') ? $activityLog->ip : '')
|
||||
->url(fn (ActivityLog $activityLog): string => $activityLog->actor instanceof User ? route('filament.admin.resources.users.edit', ['record' => $activityLog->actor]) : ''),
|
||||
->url(fn (ActivityLog $activityLog): string => $activityLog->actor instanceof User ? EditUser::getUrl(['record' => $activityLog->actor], panel: 'admin', tenant: null) : ''),
|
||||
DateTimeColumn::make('timestamp')
|
||||
->since()
|
||||
->sortable(),
|
||||
|
@ -130,13 +130,17 @@ class ListFiles extends ListRecords
|
||||
->required(),
|
||||
])
|
||||
->action(function ($data, File $file, DaemonFileRepository $fileRepository) use ($server) {
|
||||
$files = [['to' => $data['name'], 'from' => $file->name]];
|
||||
|
||||
$fileRepository
|
||||
->setServer($server)
|
||||
->renameFiles($this->path, [['to' => $data['name'], 'from' => $file->name]]);
|
||||
->renameFiles($this->path, $files);
|
||||
|
||||
Activity::event('server:file.rename')
|
||||
->property('directory', $this->path)
|
||||
->property('files', [['to' => $data['name'], 'from' => $file->name]])
|
||||
->property('files', $files)
|
||||
->property('to', $data['name'])
|
||||
->property('from', $file->name)
|
||||
->log();
|
||||
|
||||
Notification::make()
|
||||
@ -204,13 +208,17 @@ class ListFiles extends ListRecords
|
||||
->action(function ($data, File $file, DaemonFileRepository $fileRepository) use ($server) {
|
||||
$location = resolve_path(join_paths($this->path, $data['location']));
|
||||
|
||||
$files = [['to' => $location, 'from' => $file->name]];
|
||||
|
||||
$fileRepository
|
||||
->setServer($server)
|
||||
->renameFiles($this->path, [['to' => $location, 'from' => $file->name]]);
|
||||
->renameFiles($this->path, $files);
|
||||
|
||||
Activity::event('server:file.rename')
|
||||
->property('directory', $this->path)
|
||||
->property('files', [['to' => $location, 'from' => $file->name]])
|
||||
->property('files', $files)
|
||||
->property('to', $location)
|
||||
->property('from', $file->name)
|
||||
->log();
|
||||
|
||||
Notification::make()
|
||||
@ -309,7 +317,7 @@ class ListFiles extends ListRecords
|
||||
|
||||
Activity::event('server:file.decompress')
|
||||
->property('directory', $this->path)
|
||||
->property('files', $file->name)
|
||||
->property('file', $file->name)
|
||||
->log();
|
||||
|
||||
Notification::make()
|
||||
@ -342,6 +350,7 @@ class ListFiles extends ListRecords
|
||||
BulkActionGroup::make([
|
||||
BulkAction::make('move')
|
||||
->authorize(fn () => auth()->user()->can(Permission::ACTION_FILE_UPDATE, $server))
|
||||
->hidden() // TODO
|
||||
->form([
|
||||
TextInput::make('location')
|
||||
->label('File name')
|
||||
@ -366,7 +375,7 @@ class ListFiles extends ListRecords
|
||||
->log();
|
||||
|
||||
Notification::make()
|
||||
->title(count($files) . ' Files were moved from to ' . $location)
|
||||
->title(count($files) . ' Files were moved from ' . $location)
|
||||
->success()
|
||||
->send();
|
||||
}),
|
||||
|
@ -146,13 +146,17 @@ class FileController extends ClientApiController
|
||||
*/
|
||||
public function rename(RenameFileRequest $request, Server $server): JsonResponse
|
||||
{
|
||||
$files = $request->input('files');
|
||||
|
||||
$this->fileRepository
|
||||
->setServer($server)
|
||||
->renameFiles($request->input('root'), $request->input('files'));
|
||||
->renameFiles($request->input('root'), $files);
|
||||
|
||||
Activity::event('server:file.rename')
|
||||
->property('directory', $request->input('root'))
|
||||
->property('files', $request->input('files'))
|
||||
->property('files', $files)
|
||||
->property('to', $files['to'])
|
||||
->property('from', $files['from'])
|
||||
->log();
|
||||
|
||||
return new JsonResponse([], Response::HTTP_NO_CONTENT);
|
||||
@ -210,7 +214,7 @@ class FileController extends ClientApiController
|
||||
|
||||
Activity::event('server:file.decompress')
|
||||
->property('directory', $request->input('root'))
|
||||
->property('files', $request->input('file'))
|
||||
->property('file', $request->input('file'))
|
||||
->log();
|
||||
|
||||
return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT);
|
||||
|
@ -11,6 +11,7 @@ use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Database\Eloquent\Model as IlluminateModel;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* \App\Models\ActivityLog.
|
||||
@ -151,8 +152,8 @@ class ActivityLog extends Model
|
||||
'username' => 'system',
|
||||
]);
|
||||
}
|
||||
|
||||
$event = __('activity.'.str($this->event)->replace(':', '.'));
|
||||
$properties = $this->wrapProperties();
|
||||
$event = trans_choice('activity.'.str($this->event)->replace(':', '.'), array_key_exists('count', $properties) ? $properties['count'] : 1, $properties);
|
||||
|
||||
return "
|
||||
<div style='display: flex; align-items: center;'>
|
||||
@ -166,4 +167,38 @@ class ActivityLog extends Model
|
||||
</div>
|
||||
";
|
||||
}
|
||||
|
||||
public function wrapProperties(): array
|
||||
{
|
||||
if (!$this->properties || $this->properties->isEmpty()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$properties = $this->properties->mapWithKeys(function ($value, $key) {
|
||||
if (!is_array($value)) {
|
||||
// Perform some directory normalization at this point.
|
||||
if ($key === 'directory') {
|
||||
$value = str_replace('//', '/', '/' . trim($value, '/') . '/');
|
||||
}
|
||||
|
||||
return [$key => $value];
|
||||
}
|
||||
|
||||
$first = array_first($value);
|
||||
|
||||
// Backwards compatibility for old logs
|
||||
if (is_array($first)) {
|
||||
return ["{$key}_count" => count($value)];
|
||||
}
|
||||
|
||||
return [$key => $first, "{$key}_count" => count($value)];
|
||||
});
|
||||
|
||||
$keys = $properties->keys()->filter(fn ($key) => Str::endsWith($key, '_count'))->values();
|
||||
if ($keys->containsOneItem()) {
|
||||
$properties = $properties->merge(['count' => $properties->get($keys[0])])->except([$keys[0]]);
|
||||
}
|
||||
|
||||
return $properties->toArray();
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Transformers\Api\Client;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\User;
|
||||
use App\Models\ActivityLog;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
@ -29,7 +28,7 @@ class ActivityLogTransformer extends BaseClientTransformer
|
||||
'is_api' => !is_null($model->api_key_id),
|
||||
'ip' => $this->canViewIP($model->actor) ? $model->ip : null,
|
||||
'description' => $model->description,
|
||||
'properties' => $this->properties($model),
|
||||
'properties' => $model->wrapProperties(),
|
||||
'has_additional_metadata' => $this->hasAdditionalMetadata($model),
|
||||
'timestamp' => $model->timestamp->toAtomString(),
|
||||
];
|
||||
@ -44,42 +43,6 @@ class ActivityLogTransformer extends BaseClientTransformer
|
||||
return $this->item($model->actor, $this->makeTransformer(UserTransformer::class), User::RESOURCE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms any array values in the properties into a countable field for easier
|
||||
* use within the translation outputs.
|
||||
*/
|
||||
protected function properties(ActivityLog $model): object
|
||||
{
|
||||
if (!$model->properties || $model->properties->isEmpty()) {
|
||||
return (object) [];
|
||||
}
|
||||
|
||||
$properties = $model->properties
|
||||
->mapWithKeys(function ($value, $key) use ($model) {
|
||||
if ($key === 'ip' && $model->actor instanceof User && !$model->actor->is($this->request->user())) {
|
||||
return [$key => '[hidden]'];
|
||||
}
|
||||
|
||||
if (!is_array($value)) {
|
||||
// Perform some directory normalization at this point.
|
||||
if ($key === 'directory') {
|
||||
$value = str_replace('//', '/', '/' . trim($value, '/') . '/');
|
||||
}
|
||||
|
||||
return [$key => $value];
|
||||
}
|
||||
|
||||
return [$key => $value, "{$key}_count" => count($value)];
|
||||
});
|
||||
|
||||
$keys = $properties->keys()->filter(fn ($key) => Str::endsWith($key, '_count'))->values();
|
||||
if ($keys->containsOneItem()) {
|
||||
$properties = $properties->merge(['count' => $properties->get($keys[0])])->except([$keys[0]]);
|
||||
}
|
||||
|
||||
return (object) $properties->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if there are any log properties that we've not already exposed
|
||||
* in the response language string and that are not just the IP address or
|
||||
|
@ -15,7 +15,7 @@ return [
|
||||
'checkpoint' => 'Two-factor authentication requested',
|
||||
'recovery-token' => 'Used two-factor recovery token',
|
||||
'token' => 'Solved two-factor challenge',
|
||||
'ip-blocked' => 'Blocked request from unlisted IP address for :identifier',
|
||||
'ip-blocked' => 'Blocked request from unlisted IP address for <b>:identifier</b>',
|
||||
'sftp' => [
|
||||
'fail' => 'Failed SFTP log in',
|
||||
],
|
||||
@ -26,12 +26,12 @@ return [
|
||||
'password-changed' => 'Changed password',
|
||||
],
|
||||
'api-key' => [
|
||||
'create' => 'Created new API key :identifier',
|
||||
'delete' => 'Deleted API key :identifier',
|
||||
'create' => 'Created new API key <b>:identifier</b>',
|
||||
'delete' => 'Deleted API key <b>:identifier</b>',
|
||||
],
|
||||
'ssh-key' => [
|
||||
'create' => 'Added SSH key :fingerprint to account',
|
||||
'delete' => 'Removed SSH key :fingerprint from account',
|
||||
'create' => 'Added SSH key <b>:fingerprint</b> to account',
|
||||
'delete' => 'Removed SSH key <b>:fingerprint</b> from account',
|
||||
],
|
||||
'two-factor' => [
|
||||
'create' => 'Enabled two-factor auth',
|
||||
@ -41,7 +41,7 @@ return [
|
||||
'server' => [
|
||||
'reinstall' => 'Reinstalled server',
|
||||
'console' => [
|
||||
'command' => 'Executed ":command" on the server',
|
||||
'command' => 'Executed "<b>:command</b>" on the server',
|
||||
],
|
||||
'power' => [
|
||||
'start' => 'Started the server',
|
||||
@ -52,7 +52,7 @@ return [
|
||||
'backup' => [
|
||||
'download' => 'Downloaded the <b>:name</b> backup',
|
||||
'delete' => 'Deleted the <b>:name</b> backup',
|
||||
'restore' => 'Restored the <b>:name</b> backup (deleted files: :truncate)',
|
||||
'restore' => 'Restored the <b>:name</b> backup (deleted files: <b>:truncate</b>)',
|
||||
'restore-complete' => 'Completed restoration of the <b>:name</b> backup',
|
||||
'restore-failed' => 'Failed to complete restoration of the <b>:name</b> backup',
|
||||
'start' => 'Started a new backup <b>:name</b>',
|
||||
@ -67,40 +67,32 @@ return [
|
||||
'delete' => 'Deleted database <b>:name</b>',
|
||||
],
|
||||
'file' => [
|
||||
'compress_one' => 'Compressed :directory:file',
|
||||
'compress_other' => 'Compressed :count files in :directory',
|
||||
'read' => 'Viewed the contents of :file',
|
||||
'copy' => 'Created a copy of :file',
|
||||
'create-directory' => 'Created directory :directory<b>:name</b>',
|
||||
'decompress' => 'Decompressed :files in :directory',
|
||||
'delete_one' => 'Deleted :directory:files.0',
|
||||
'delete_other' => 'Deleted :count files in :directory',
|
||||
'download' => 'Downloaded :file',
|
||||
'pull' => 'Downloaded a remote file from :url to :directory',
|
||||
'rename_one' => 'Renamed :directory:files.0.from to :directory:files.0.to',
|
||||
'rename_other' => 'Renamed :count files in :directory',
|
||||
'write' => 'Wrote new content to :file',
|
||||
'compress' => 'Compressed <b>:directory:files</b>|Compressed <b>:count</b> files in <b>:directory</b>',
|
||||
'read' => 'Viewed the contents of <b>:file</b>',
|
||||
'copy' => 'Created a copy of <b>:file</b>',
|
||||
'create-directory' => 'Created directory <b>:directory:name</b>',
|
||||
'decompress' => 'Decompressed <b>:file</b> in <b>:directory</b>',
|
||||
'delete' => 'Deleted <b>:directory:files</b>|Deleted <b>:count</b> files in <b>:directory</b>',
|
||||
'download' => 'Downloaded <b>:file</b>',
|
||||
'pull' => 'Downloaded a remote file from <b>:url</b> to <b>:directory</b>',
|
||||
'rename' => 'Renamed <b>:directory:from</b> to <b>:directory:to</b>|Renamed <b>:count</b> files in <b>:directory</b>',
|
||||
'write' => 'Wrote new content to <b>:file</b>',
|
||||
'upload' => 'Began a file upload',
|
||||
'uploaded' => 'Uploaded :directory:file',
|
||||
'uploaded' => 'Uploaded <b>:directory:file</b>',
|
||||
],
|
||||
'sftp' => [
|
||||
'denied' => 'Blocked SFTP access due to permissions',
|
||||
'create_one' => 'Created :files.0',
|
||||
'create_other' => 'Created :count new files',
|
||||
'write_one' => 'Modified the contents of :files.0',
|
||||
'write_other' => 'Modified the contents of :count files',
|
||||
'delete_one' => 'Deleted :files.0',
|
||||
'delete_other' => 'Deleted :count files',
|
||||
'create-directory_one' => 'Created the :files.0 directory',
|
||||
'create-directory_other' => 'Created :count directories',
|
||||
'rename_one' => 'Renamed :files.0.from to :files.0.to',
|
||||
'rename_other' => 'Renamed or moved :count files',
|
||||
'create' => 'Created <b>:files</b>|Created <b>:count</b> new files',
|
||||
'write' => 'Modified the contents of <b>:files</b>|Modified the contents of <b>:count</b> files',
|
||||
'delete' => 'Deleted <b>:files</b>|Deleted <b>:count</b> files',
|
||||
'create-directory' => 'Created the <b>:files</b> directory|Created <b>:count</b> directories',
|
||||
'rename' => 'Renamed <b>:from</b> to <b>:to</b>|Renamed or moved <b>:count</b> files',
|
||||
],
|
||||
'allocation' => [
|
||||
'create' => 'Added :allocation to the server',
|
||||
'notes' => 'Updated the notes for :allocation from "<b>:old</b>" to "<b>:new</b>"',
|
||||
'primary' => 'Set :allocation as the primary server allocation',
|
||||
'delete' => 'Deleted the :allocation allocation',
|
||||
'create' => 'Added <b>:allocation</b> to the server',
|
||||
'notes' => 'Updated the notes for <b>:allocation</b> from "<b>:old</b>" to "<b>:new</b>"',
|
||||
'primary' => 'Set <b>:allocation</b> as the primary server allocation',
|
||||
'delete' => 'Deleted the <b>:allocation</b> allocation',
|
||||
],
|
||||
'schedule' => [
|
||||
'create' => 'Created the <b>:name</b> schedule',
|
||||
@ -114,8 +106,8 @@ return [
|
||||
'delete' => 'Deleted a task for the <b>:name</b> schedule',
|
||||
],
|
||||
'settings' => [
|
||||
'rename' => 'Renamed the server from <b>:old</b> to <b>:new</b>',
|
||||
'description' => 'Changed the server description from <b>:old</b> to <b>:new</b>',
|
||||
'rename' => 'Renamed the server from "<b>:old</b>" to "<b>:new</b>"',
|
||||
'description' => 'Changed the server description from "<b>:old</b>" to "<b>:new</b>"',
|
||||
],
|
||||
'startup' => [
|
||||
'edit' => 'Changed the <b>:variable</b> variable from "<b>:old</b>" to "<b>:new</b>"',
|
||||
|
Loading…
x
Reference in New Issue
Block a user