Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ A curated list of plugins for the [Pelican Panel](https://pelican.dev). Feel fre
- [Legal Pages](/legal-pages) - Adds legal pages (Imprint, Privacy Policy, ToS) to the panel
- [MCLogs Uploader](/mclogs-uploader) - Upload console logs to mclo.gs
- [Minecraft Modrinth](/minecraft-modrinth) - Download Minecraft mods & plugins from Modrinth
- [PasteFox Share](/pastefox-share) - Share console logs via pastefox.com
- [Player Counter](/player-counter) - Show connected players count for game servers
- [Register](/register) - Enable user self-registration on all panels
- [Robo Avatars](/robo-avatars) - Adds RoboHash as avatar provider
Expand Down
42 changes: 42 additions & 0 deletions pastefox-share/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# PasteFox Share (by FlexKleks)

Share console logs via [pastefox.com](https://pastefox.com) with one click.

## Features

- One-click log sharing from server console
- Optional API key for extended features (without API key, pastes expire after 7 days)
- Configurable visibility (PUBLIC/PRIVATE - requires API key)
- Visual effects (Matrix, Confetti, Glitch, etc.)
- Theme selection (Light/Dark)
- Password protection support
- Fetches up to 5000 log lines

## Configuration

1. Go to **Admin → Plugins**
2. Find **PasteFox Share** and click the **Settings** (gear icon) button
3. Configure the following settings:

| Setting | Description |
|------------|----------------------------------------------------|
| API Key | Optional - Get from https://pastefox.com/dashboard |
| Visibility | PUBLIC or PRIVATE (requires API key) |
| Effect | Visual effect for the paste |
| Theme | Light or Dark theme |
| Password | Optional password protection |

### Without API Key
- Pastes expire after 7 days
- Always public visibility

### With API Key
- No expiration limit
- Private pastes available
- Password protection

## Usage

1. Open a server console
2. Click the **"Share Logs"** button in the header
3. Copy the generated link from the notification
9 changes: 9 additions & 0 deletions pastefox-share/config/pastefox-share.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

return [
'api_key' => env('PASTEFOX_API_KEY'),
'visibility' => env('PASTEFOX_VISIBILITY', 'PUBLIC'),
'effect' => env('PASTEFOX_EFFECT', 'NONE'),
'theme' => env('PASTEFOX_THEME', 'dark'),
'password' => env('PASTEFOX_PASSWORD'),
];
40 changes: 40 additions & 0 deletions pastefox-share/lang/en/messages.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

return [
'share_logs' => 'Share Logs',
'share_file' => 'Share',
'uploaded' => 'Logs uploaded to PasteFox',
'file_uploaded' => 'File uploaded to PasteFox',
'upload_failed' => 'Upload failed',
'api_key_missing' => 'PasteFox API key not configured. Add it in the plugin settings.',
'expires_7_days' => '⚠️ Without API key, paste expires in 7 days',

// Settings
'settings_saved' => 'Settings saved',
'section_api' => 'API Configuration',
'section_api_description' => 'Without API key, pastes expire after 7 days and are always public.',
'section_paste' => 'Paste Settings',
'api_key' => 'API Key',
'api_key_helper' => 'Optional - Get your API key from https://pastefox.com/dashboard',
'visibility' => 'Visibility',
'visibility_public' => 'Public',
'visibility_private' => 'Private (requires API key)',
'visibility_helper' => 'Private pastes require an API key',
'effect' => 'Visual Effect',
'effect_none' => 'None',
'effect_matrix' => 'Matrix Rain',
'effect_glitch' => 'Glitch',
'effect_confetti' => 'Confetti',
'effect_scratch' => 'Scratch Card',
'effect_puzzle' => 'Puzzle Reveal',
'effect_slots' => 'Slot Machine',
'effect_shake' => 'Shake',
'effect_fireworks' => 'Fireworks',
'effect_typewriter' => 'Typewriter',
'effect_blur' => 'Blur Reveal',
'theme' => 'Theme',
'theme_dark' => 'Dark',
'theme_light' => 'Light',
'password' => 'Password Protection',
'password_helper' => 'Optional - 4-100 characters',
];
15 changes: 15 additions & 0 deletions pastefox-share/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"id": "pastefox-share",
"name": "PasteFox Share",
"author": "FlexKleks",
"version": "1.0.0",
"description": "Share console logs via pastefox.com",
"category": "plugin",
"url": "https://github.com/pelican-dev/plugins/tree/main/pastefox-share",
"update_url": null,
"namespace": "FlexKleks\\PasteFoxShare",
"class": "PasteFoxSharePlugin",
"panels": ["admin", "server"],
"panel_version": null,
"composer_packages": null
}
115 changes: 115 additions & 0 deletions pastefox-share/src/Filament/Components/Actions/UploadLogsAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

namespace FlexKleks\PasteFoxShare\Filament\Components\Actions;

use App\Models\Server;
use Exception;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Filament\Notifications\Notification;
use Filament\Support\Enums\Size;
use Illuminate\Support\Facades\Http;

class UploadLogsAction extends Action
{
public static function getDefaultName(): ?string
{
return 'upload_logs_pastefox';
}

protected function setUp(): void
{
parent::setUp();

$this->hidden(function () {
/** @var Server $server */
$server = Filament::getTenant();

return $server->retrieveStatus()->isOffline();
});

$this->label(fn () => trans('pastefox-share::messages.share_logs'));

$this->icon('tabler-share');

$this->color('primary');

$this->size(Size::ExtraLarge);

$this->action(function () {
/** @var Server $server */
$server = Filament::getTenant();

try {
$logs = Http::daemon($server->node)
->get("/api/servers/{$server->uuid}/logs", [
'size' => 5000,
])
->throw()
->json('data');

$logs = is_array($logs) ? implode(PHP_EOL, $logs) : $logs;

$apiKey = config('pastefox-share.api_key');
$hasApiKey = filled($apiKey);

$headers = ['Content-Type' => 'application/json'];

$payload = [
'content' => $logs,
'title' => 'Console Logs: ' . $server->name . ' - ' . now()->format('Y-m-d H:i:s'),
'language' => 'log',
'effect' => config('pastefox-share.effect'),
'theme' => config('pastefox-share.theme'),
];

if ($hasApiKey) {
$headers['X-API-Key'] = $apiKey;
$payload['visibility'] = config('pastefox-share.visibility');

$password = config('pastefox-share.password');
if (filled($password)) {
$payload['password'] = $password;
}
}

$response = Http::withHeaders($headers)
->post('https://pastefox.com/api/pastes', $payload)
->timeout(30)
->connectTimeout(5)
->throw()
->json();

if ($response['success']) {
$url = 'https://pastefox.com/'.$response['data']['slug'];

$body = $url;
if (!$hasApiKey) {
$body .= "\n".trans('pastefox-share::messages.expires_7_days');
}

Notification::make()
->title(trans('pastefox-share::messages.uploaded'))
->body($body)
->persistent()
->success()
->send();
} else {
Notification::make()
->title(trans('pastefox-share::messages.upload_failed'))
->body($response['error'] ?? 'Unknown error')
->danger()
->send();
}
} catch (Exception $exception) {
report($exception);

Notification::make()
->title(trans('pastefox-share::messages.upload_failed'))
->body($exception->getMessage())
->danger()
->send();
}
});
}
}
104 changes: 104 additions & 0 deletions pastefox-share/src/PasteFoxSharePlugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace FlexKleks\PasteFoxShare;

use App\Contracts\Plugins\HasPluginSettings;
use App\Traits\EnvironmentWriterTrait;
use Filament\Contracts\Plugin;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Panel;
use Filament\Schemas\Components\Section;

class PasteFoxSharePlugin implements HasPluginSettings, Plugin
{
use EnvironmentWriterTrait;

public function getId(): string
{
return 'pastefox-share';
}

public function register(Panel $panel): void {}

public function boot(Panel $panel): void {}

public function getSettingsForm(): array
{
return [
Section::make(trans('pastefox-share::messages.section_api'))
->description(trans('pastefox-share::messages.section_api_description'))
->schema([
TextInput::make('api_key')
->label(trans('pastefox-share::messages.api_key'))
->password()
->revealable()
->helperText(trans('pastefox-share::messages.api_key_helper'))
->default(fn () => config('pastefox-share.api_key')),
]),

Section::make(trans('pastefox-share::messages.section_paste'))
->schema([
Select::make('visibility')
->label(trans('pastefox-share::messages.visibility'))
->options([
'PUBLIC' => trans('pastefox-share::messages.visibility_public'),
'PRIVATE' => trans('pastefox-share::messages.visibility_private'),
])
->default(fn () => config('pastefox-share.visibility', 'PUBLIC'))
->helperText(trans('pastefox-share::messages.visibility_helper')),

Select::make('effect')
->label(trans('pastefox-share::messages.effect'))
->options([
'NONE' => trans('pastefox-share::messages.effect_none'),
'MATRIX' => trans('pastefox-share::messages.effect_matrix'),
'GLITCH' => trans('pastefox-share::messages.effect_glitch'),
'CONFETTI' => trans('pastefox-share::messages.effect_confetti'),
'SCRATCH' => trans('pastefox-share::messages.effect_scratch'),
'PUZZLE' => trans('pastefox-share::messages.effect_puzzle'),
'SLOTS' => trans('pastefox-share::messages.effect_slots'),
'SHAKE' => trans('pastefox-share::messages.effect_shake'),
'FIREWORKS' => trans('pastefox-share::messages.effect_fireworks'),
'TYPEWRITER' => trans('pastefox-share::messages.effect_typewriter'),
'BLUR' => trans('pastefox-share::messages.effect_blur'),
])
->default(fn () => config('pastefox-share.effect', 'NONE')),

Select::make('theme')
->label(trans('pastefox-share::messages.theme'))
->options([
'dark' => trans('pastefox-share::messages.theme_dark'),
'light' => trans('pastefox-share::messages.theme_light'),
])
->default(fn () => config('pastefox-share.theme', 'dark')),

TextInput::make('password')
->label(trans('pastefox-share::messages.password'))
->password()
->revealable()
->minLength(4)
->maxLength(100)
->helperText(trans('pastefox-share::messages.password_helper'))
->default(fn () => config('pastefox-share.password')),
]),
];
}

public function saveSettings(array $data): void
{
$this->writeToEnvironment([
'PASTEFOX_API_KEY' => $data['api_key'] ?? '',
'PASTEFOX_VISIBILITY' => $data['visibility'] ?? 'PUBLIC',
'PASTEFOX_EFFECT' => $data['effect'] ?? 'NONE',
'PASTEFOX_THEME' => $data['theme'] ?? 'dark',
'PASTEFOX_PASSWORD' => $data['password'] ?? '',
]);

Notification::make()
->title(trans('pastefox-share::messages.settings_saved'))
->success()
->send();
}
}
18 changes: 18 additions & 0 deletions pastefox-share/src/Providers/PasteFoxSharePluginProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace FlexKleks\PasteFoxShare\Providers;

use App\Enums\HeaderActionPosition;
use App\Filament\Server\Pages\Console;
use FlexKleks\PasteFoxShare\Filament\Components\Actions\UploadLogsAction;
use Illuminate\Support\ServiceProvider;

class PasteFoxSharePluginProvider extends ServiceProvider
{
public function register(): void
{
Console::registerCustomHeaderActions(HeaderActionPosition::Before, UploadLogsAction::make());
}

public function boot(): void {}
}