Lint commands

pull/6396/head
Daniel Supernault 7 months ago
parent 7f6a6cf563
commit d1799a0833
No known key found for this signature in database
GPG Key ID: 23740873EE6F76A1

@ -6,28 +6,29 @@ use Illuminate\Database\Eloquent\Model;
class AccountInterstitial extends Model
{
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $casts = [
'read_at' => 'datetime',
'appeal_requested_at' => 'datetime'
];
/**
* The attributes that should be mutated to dates.
*
* @var array
*/
protected $casts = [
'read_at' => 'datetime',
'appeal_requested_at' => 'datetime',
];
public const JSON_MESSAGE = 'Please use web browser to proceed.';
public const JSON_MESSAGE = 'Please use web browser to proceed.';
public function user()
{
return $this->belongsTo(User::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
public function status()
{
if($this->item_type != 'App\Status') {
return;
}
return $this->hasOne(Status::class, 'id', 'item_id');
}
public function status()
{
if ($this->item_type != 'App\Status') {
return;
}
return $this->hasOne(Status::class, 'id', 'item_id');
}
}

@ -6,11 +6,10 @@ use Illuminate\Database\Eloquent\Model;
class AccountLog extends Model
{
protected $fillable = ['*'];
protected $fillable = ['*'];
public function user()
{
return $this->belongsTo(User::class);
return $this->belongsTo(User::class);
}
}

@ -7,18 +7,18 @@ use Illuminate\Database\Eloquent\Model;
class Activity extends Model
{
protected $casts = [
'processed_at' => 'datetime'
'processed_at' => 'datetime',
];
protected $fillable = ['data', 'to_id', 'from_id', 'object_type'];
public function toProfile()
{
return $this->belongsTo(Profile::class, 'to_id');
}
public function toProfile()
{
return $this->belongsTo(Profile::class, 'to_id');
}
public function fromProfile()
{
return $this->belongsTo(Profile::class, 'from_id');
}
public function fromProfile()
{
return $this->belongsTo(Profile::class, 'from_id');
}
}

@ -17,9 +17,9 @@ class Avatar extends Model
protected $casts = [
'deleted_at' => 'datetime',
'last_fetched_at' => 'datetime',
'last_processed_at' => 'datetime'
'last_processed_at' => 'datetime',
];
protected $guarded = [];
protected $visible = [
@ -31,6 +31,6 @@ class Avatar extends Model
public function profile()
{
return $this->belongsTo(Profile::class);
return $this->belongsTo(Profile::class);
}
}

@ -6,16 +6,15 @@ use Illuminate\Database\Eloquent\Model;
class Bookmark extends Model
{
protected $fillable = ['profile_id', 'status_id'];
protected $fillable = ['profile_id', 'status_id'];
public function status()
{
return $this->belongsTo(Status::class);
}
public function status()
{
return $this->belongsTo(Status::class);
}
public function profile()
{
return $this->belongsTo(Profile::class);
}
public function profile()
{
return $this->belongsTo(Profile::class);
}
}

@ -8,28 +8,28 @@ class Circle extends Model
{
protected $fillable = [
'profile_id',
'name',
'description',
'bcc',
'scope',
'active'
'name',
'description',
'bcc',
'scope',
'active',
];
public function members()
{
return $this->hasManyThrough(
Profile::class,
CircleProfile::class,
'circle_id',
'id',
'id',
'profile_id'
);
return $this->hasManyThrough(
Profile::class,
CircleProfile::class,
'circle_id',
'id',
'id',
'profile_id'
);
}
public function owner()
{
return $this->belongsTo(Profile::class, 'profile_id');
return $this->belongsTo(Profile::class, 'profile_id');
}
public function url()

@ -7,7 +7,7 @@ use Illuminate\Database\Eloquent\Model;
class CircleProfile extends Model
{
protected $fillable = [
'circle_id',
'profile_id'
'circle_id',
'profile_id',
];
}

@ -2,13 +2,11 @@
namespace App;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;
use App\HasSnowflakePrimary;
class Collection extends Model
{
use HasSnowflakePrimary;
use HasSnowflakePrimary;
/**
* Indicates if the IDs are auto-incrementing.
@ -21,10 +19,10 @@ class Collection extends Model
public $dates = ['published_at'];
public function profile()
{
return $this->belongsTo(Profile::class);
}
public function profile()
{
return $this->belongsTo(Profile::class);
}
public function items()
{

@ -3,28 +3,27 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\HasSnowflakePrimary;
class CollectionItem extends Model
{
use HasSnowflakePrimary;
use HasSnowflakePrimary;
public $fillable = [
'collection_id',
'object_type',
'object_id',
'order'
'order',
];
/**
* Indicates if the IDs are auto-incrementing.
*
* @var bool
*/
public $incrementing = false;
public function collection()
{
return $this->belongsTo(Collection::class);
}
public function collection()
{
return $this->belongsTo(Collection::class);
}
}

@ -2,13 +2,14 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\User;
use App\Models\DefaultDomainBlock;
use App\Models\UserDomainBlock;
use function Laravel\Prompts\text;
use App\User;
use Illuminate\Console\Command;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\progress;
use function Laravel\Prompts\text;
class AddUserDomainBlock extends Command
{
@ -34,42 +35,44 @@ class AddUserDomainBlock extends Command
$domain = text('Enter domain you want to block');
$domain = strtolower($domain);
$domain = $this->validateDomain($domain);
if(!$domain) {
if (! $domain) {
$this->error('Invalid domain');
return;
}
$this->processBlocks($domain);
return;
}
protected function validateDomain($domain)
{
if(!strpos($domain, '.')) {
if (! strpos($domain, '.')) {
return;
}
if(str_starts_with($domain, 'https://')) {
if (str_starts_with($domain, 'https://')) {
$domain = str_replace('https://', '', $domain);
}
if(str_starts_with($domain, 'http://')) {
if (str_starts_with($domain, 'http://')) {
$domain = str_replace('http://', '', $domain);
}
$domain = strtolower(parse_url('https://' . $domain, PHP_URL_HOST));
$domain = strtolower(parse_url('https://'.$domain, PHP_URL_HOST));
$valid = filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME|FILTER_NULL_ON_FAILURE);
if(!$valid) {
$valid = filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME | FILTER_NULL_ON_FAILURE);
if (! $valid) {
return;
}
if($domain === config('pixelfed.domain.app')) {
if ($domain === config('pixelfed.domain.app')) {
$this->error('Invalid domain');
return;
}
$confirmed = confirm('Are you sure you want to block ' . $domain . '?');
if(!$confirmed) {
$confirmed = confirm('Are you sure you want to block '.$domain.'?');
if (! $confirmed) {
return;
}
@ -79,7 +82,7 @@ class AddUserDomainBlock extends Command
protected function processBlocks($domain)
{
DefaultDomainBlock::updateOrCreate([
'domain' => $domain
'domain' => $domain,
]);
progress(
label: 'Updating user domain blocks...',
@ -90,17 +93,17 @@ class AddUserDomainBlock extends Command
protected function performTask($user, $domain)
{
if(!$user->profile_id || $user->delete_after) {
if (! $user->profile_id || $user->delete_after) {
return;
}
if($user->status != null && $user->status != 'disabled') {
if ($user->status != null && $user->status != 'disabled') {
return;
}
UserDomainBlock::updateOrCreate([
'profile_id' => $user->profile_id,
'domain' => $domain
'domain' => $domain,
]);
}
}

@ -2,9 +2,10 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Avatar;
use Cache, DB;
use Cache;
use DB;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
class AvatarDefaultMigration extends Command
@ -43,7 +44,7 @@ class AvatarDefaultMigration extends Command
$this->info('Running avatar migration...');
$count = Avatar::whereChangeCount(0)->count();
if($count == 0) {
if ($count == 0) {
$this->info('Found no avatars needing to be migrated!');
exit;
}
@ -51,29 +52,29 @@ class AvatarDefaultMigration extends Command
$bar = $this->output->createProgressBar($count);
$this->info("Found {$count} avatars that may need to be migrated");
Avatar::whereChangeCount(0)->chunk(50, function($avatars) use ($bar) {
foreach($avatars as $avatar) {
if( $avatar->media_path == 'public/avatars/default.png' ||
Avatar::whereChangeCount(0)->chunk(50, function ($avatars) use ($bar) {
foreach ($avatars as $avatar) {
if ($avatar->media_path == 'public/avatars/default.png' ||
$avatar->thumb_path == 'public/avatars/default.png' ||
$avatar->media_path == 'public/avatars/default.jpg' ||
$avatar->media_path == 'public/avatars/default.jpg' ||
$avatar->thumb_path == 'public/avatars/default.jpg'
) {
continue;
}
if(Str::endsWith($avatar->media_path, '/avatar.svg') == false) {
if (Str::endsWith($avatar->media_path, '/avatar.svg') == false) {
// do not modify non-default avatars
continue;
}
DB::transaction(function() use ($avatar, $bar) {
if(is_file(storage_path('app/' . $avatar->media_path))) {
@unlink(storage_path('app/' . $avatar->media_path));
DB::transaction(function () use ($avatar, $bar) {
if (is_file(storage_path('app/'.$avatar->media_path))) {
@unlink(storage_path('app/'.$avatar->media_path));
}
if(is_file(storage_path('app/' . $avatar->thumb_path))) {
@unlink(storage_path('app/' . $avatar->thumb_path));
if (is_file(storage_path('app/'.$avatar->thumb_path))) {
@unlink(storage_path('app/'.$avatar->thumb_path));
}
$avatar->media_path = 'public/avatars/default.jpg';
@ -81,7 +82,7 @@ class AvatarDefaultMigration extends Command
$avatar->change_count = $avatar->change_count + 1;
$avatar->save();
Cache::forget('avatar:' . $avatar->profile_id);
Cache::forget('avatar:'.$avatar->profile_id);
$bar->advance();
});
}

@ -2,16 +2,15 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Avatar;
use App\Jobs\AvatarPipeline\RemoteAvatarFetch;
use App\Profile;
use App\User;
use Cache;
use Storage;
use App\Services\AccountService;
use App\Util\Lexer\PrettyNumber;
use Cache;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use App\Jobs\AvatarPipeline\RemoteAvatarFetch;
use Storage;
class AvatarStorage extends Command
{
@ -30,8 +29,11 @@ class AvatarStorage extends Command
protected $description = 'Manage avatar storage';
public $found = 0;
public $notFetched = 0;
public $fixed = 0;
public $missing = 0;
/**
@ -47,32 +49,32 @@ class AvatarStorage extends Command
[
'Local',
Avatar::whereNull('is_remote')->count(),
PrettyNumber::size(Avatar::whereNull('is_remote')->sum('size'))
PrettyNumber::size(Avatar::whereNull('is_remote')->sum('size')),
],
[
'Remote',
Avatar::whereIsRemote(true)->count(),
PrettyNumber::size(Avatar::whereIsRemote(true)->sum('size'))
PrettyNumber::size(Avatar::whereIsRemote(true)->sum('size')),
],
[
'Cached (CDN)',
Avatar::whereNotNull('cdn_url')->count(),
PrettyNumber::size(Avatar::whereNotNull('cdn_url')->sum('size'))
PrettyNumber::size(Avatar::whereNotNull('cdn_url')->sum('size')),
],
[
'Uncached',
Avatar::whereNull('cdn_url')->count(),
PrettyNumber::size(Avatar::whereNull('cdn_url')->sum('size'))
PrettyNumber::size(Avatar::whereNull('cdn_url')->sum('size')),
],
[
'------------',
'----------',
'-----'
'-----',
],
[
'Total',
Avatar::count(),
PrettyNumber::size(Avatar::sum('size'))
PrettyNumber::size(Avatar::sum('size')),
],
];
$this->table(
@ -82,21 +84,21 @@ class AvatarStorage extends Command
$this->line(' ');
if((bool) config_cache('pixelfed.cloud_storage')) {
if ((bool) config_cache('pixelfed.cloud_storage')) {
$this->info('✅ - Cloud storage configured');
$this->line(' ');
}
if(config('instance.avatar.local_to_cloud')) {
if (config('instance.avatar.local_to_cloud')) {
$this->info('✅ - Store avatars on cloud filesystem');
$this->line(' ');
}
if((bool) config_cache('pixelfed.cloud_storage') && config('instance.avatar.local_to_cloud')) {
if ((bool) config_cache('pixelfed.cloud_storage') && config('instance.avatar.local_to_cloud')) {
$disk = Storage::disk(config_cache('filesystems.cloud'));
$exists = $disk->exists('cache/avatars/default.jpg');
$state = $exists ? '✅' : '❌';
$msg = $state . ' - Cloud default avatar exists';
$msg = $state.' - Cloud default avatar exists';
$this->info($msg);
}
@ -105,14 +107,14 @@ class AvatarStorage extends Command
'Cancel',
'Upload default avatar to cloud',
'Move local avatars to cloud',
'Re-fetch remote avatars'
'Re-fetch remote avatars',
] : [
'Cancel',
'Re-fetch remote avatars'
];
'Re-fetch remote avatars',
];
$this->missing = Profile::where('created_at', '<', now()->subDays(1))->doesntHave('avatar')->count();
if($this->missing != 0) {
if ($this->missing != 0) {
$options[] = 'Fix missing avatars';
}
@ -147,7 +149,7 @@ class AvatarStorage extends Command
protected function uploadDefaultAvatar()
{
if(!$this->confirm('Are you sure you want to upload the default avatar to the cloud storage disk?')) {
if (! $this->confirm('Are you sure you want to upload the default avatar to the cloud storage disk?')) {
return;
}
$disk = Storage::disk(config_cache('filesystems.cloud'));
@ -159,35 +161,37 @@ class AvatarStorage extends Command
protected function uploadAvatarsToCloud()
{
if(!(bool) config_cache('pixelfed.cloud_storage') || !config('instance.avatar.local_to_cloud')) {
if (! (bool) config_cache('pixelfed.cloud_storage') || ! config('instance.avatar.local_to_cloud')) {
$this->error('Enable cloud storage and avatar cloud storage to perform this action');
return;
}
$confirm = $this->confirm('Are you sure you want to move local avatars to cloud storage?');
if(!$confirm) {
if (! $confirm) {
$this->error('Aborted action');
return;
}
$disk = Storage::disk(config_cache('filesystems.cloud'));
if($disk->missing('cache/avatars/default.jpg')) {
if ($disk->missing('cache/avatars/default.jpg')) {
$disk->put('cache/avatars/default.jpg', Storage::get('public/avatars/default.jpg'));
}
Avatar::whereNull('is_remote')->chunk(5, function($avatars) use($disk) {
foreach($avatars as $avatar) {
if($avatar->media_path === 'public/avatars/default.jpg') {
Avatar::whereNull('is_remote')->chunk(5, function ($avatars) use ($disk) {
foreach ($avatars as $avatar) {
if ($avatar->media_path === 'public/avatars/default.jpg') {
$avatar->cdn_url = $disk->url('cache/avatars/default.jpg');
$avatar->save();
} else {
if(!$avatar->media_path || !Str::of($avatar->media_path)->startsWith('public/avatars/')) {
if (! $avatar->media_path || ! Str::of($avatar->media_path)->startsWith('public/avatars/')) {
continue;
}
$ext = pathinfo($avatar->media_path, PATHINFO_EXTENSION);
$newPath = 'cache/avatars/' . $avatar->profile_id . '/avatar_' . strtolower(Str::random(6)) . '.' . $ext;
$newPath = 'cache/avatars/'.$avatar->profile_id.'/avatar_'.strtolower(Str::random(6)).'.'.$ext;
$existing = Storage::disk('local')->get($avatar->media_path);
if(!$existing) {
if (! $existing) {
continue;
}
$newMediaPath = $disk->put($newPath, $existing);
@ -196,20 +200,21 @@ class AvatarStorage extends Command
$avatar->save();
}
Cache::forget('avatar:' . $avatar->profile_id);
Cache::forget(AccountService::CACHE_KEY . $avatar->profile_id);
Cache::forget('avatar:'.$avatar->profile_id);
Cache::forget(AccountService::CACHE_KEY.$avatar->profile_id);
}
});
}
protected function refetchRemoteAvatars()
{
if(!$this->confirm('Are you sure you want to refetch all remote avatars? This could take a while.')) {
if (! $this->confirm('Are you sure you want to refetch all remote avatars? This could take a while.')) {
return;
}
if((bool) config_cache('pixelfed.cloud_storage') == false && config_cache('federation.avatars.store_local') == false) {
if ((bool) config_cache('pixelfed.cloud_storage') == false && config_cache('federation.avatars.store_local') == false) {
$this->error('You have cloud storage disabled and local avatar storage disabled, we cannot refetch avatars.');
return;
}
@ -218,22 +223,22 @@ class AvatarStorage extends Command
->whereNull('user_id')
->count();
$this->info('Found ' . $count . ' remote avatars to re-fetch');
$this->info('Found '.$count.' remote avatars to re-fetch');
$this->line(' ');
$bar = $this->output->createProgressBar($count);
Profile::has('avatar')
->with('avatar')
->whereNull('user_id')
->chunk(50, function($profiles) use($bar) {
foreach($profiles as $profile) {
$avatar = $profile->avatar;
$avatar->last_fetched_at = null;
$avatar->save();
RemoteAvatarFetch::dispatch($profile)->onQueue('low');
$bar->advance();
}
});
->chunk(50, function ($profiles) use ($bar) {
foreach ($profiles as $profile) {
$avatar = $profile->avatar;
$avatar->last_fetched_at = null;
$avatar->save();
RemoteAvatarFetch::dispatch($profile)->onQueue('low');
$bar->advance();
}
});
$this->line(' ');
$this->line(' ');
$this->info('Finished dispatching avatar refetch jobs!');
@ -244,45 +249,45 @@ class AvatarStorage extends Command
protected function incr($name)
{
switch($name) {
switch ($name) {
case 'found':
$this->found = $this->found + 1;
break;
break;
case 'notFetched':
$this->notFetched = $this->notFetched + 1;
break;
break;
case 'fixed':
$this->fixed++;
break;
break;
}
}
protected function fixMissingAvatars()
{
if(!$this->confirm('Are you sure you want to fix missing avatars?')) {
if (! $this->confirm('Are you sure you want to fix missing avatars?')) {
return;
}
$this->info('Found ' . $this->missing . ' accounts with missing profiles');
$this->info('Found '.$this->missing.' accounts with missing profiles');
Profile::where('created_at', '<', now()->subDays(1))
->doesntHave('avatar')
->chunk(50, function($profiles) {
foreach($profiles as $profile) {
->chunk(50, function ($profiles) {
foreach ($profiles as $profile) {
Avatar::updateOrCreate([
'profile_id' => $profile->id
'profile_id' => $profile->id,
], [
'media_path' => 'public/avatars/default.jpg',
'is_remote' => $profile->domain == null && $profile->private_key == null
'is_remote' => $profile->domain == null && $profile->private_key == null,
]);
$this->incr('fixed');
}
});
});
$this->line(' ');
$this->line(' ');
$this->info('Fixed ' . $this->fixed . ' accounts with a blank avatar');
$this->info('Fixed '.$this->fixed.' accounts with a blank avatar');
}
}

@ -2,11 +2,11 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Cache;
use Storage;
use App\Avatar;
use App\Jobs\AvatarPipeline\AvatarStorageCleanup;
use Cache;
use Illuminate\Console\Command;
use Storage;
class AvatarStorageDeepClean extends Command
{
@ -25,6 +25,7 @@ class AvatarStorageDeepClean extends Command
protected $description = 'Cleanup avatar storage';
protected $shouldKeepRunning = true;
protected $counter = 0;
/**
@ -45,30 +46,30 @@ class AvatarStorageDeepClean extends Command
$storage = [
'cloud' => (bool) config_cache('pixelfed.cloud_storage'),
'local' => boolval(config_cache('federation.avatars.store_local'))
'local' => boolval(config_cache('federation.avatars.store_local')),
];
if(!$storage['cloud'] && !$storage['local']) {
if (! $storage['cloud'] && ! $storage['local']) {
$this->error('Remote avatars are not cached locally, there is nothing to purge. Aborting...');
exit;
}
$start = 0;
if(!$this->confirm('Are you sure you want to proceed?')) {
if (! $this->confirm('Are you sure you want to proceed?')) {
$this->error('Aborting...');
exit;
}
if(!$this->activeCheck()) {
if (! $this->activeCheck()) {
$this->info('Found existing deep cleaning job');
if(!$this->confirm('Do you want to continue where you left off?')) {
if (! $this->confirm('Do you want to continue where you left off?')) {
$this->error('Aborting...');
exit;
} else {
$start = Cache::has('cmd:asdp') ? (int) Cache::get('cmd:asdp') : (int) Storage::get('avatar-deep-clean.json');
if($start && $start < 1 || $start > PHP_INT_MAX) {
if ($start && $start < 1 || $start > PHP_INT_MAX) {
$this->error('Error fetching cached value');
$this->error('Aborting...');
exit;
@ -79,7 +80,7 @@ class AvatarStorageDeepClean extends Command
$count = Avatar::whereNotNull('cdn_url')->where('is_remote', true)->where('id', '>', $start)->count();
$bar = $this->output->createProgressBar($count);
foreach(Avatar::whereNotNull('cdn_url')->where('is_remote', true)->where('id', '>', $start)->lazyById(10, 'id') as $avatar) {
foreach (Avatar::whereNotNull('cdn_url')->where('is_remote', true)->where('id', '>', $start)->lazyById(10, 'id') as $avatar) {
usleep(random_int(50, 1000));
$this->counter++;
$this->handleAvatar($avatar);
@ -91,14 +92,14 @@ class AvatarStorageDeepClean extends Command
protected function updateCache($id)
{
Cache::put('cmd:asdp', $id);
if($this->counter % 5 === 0) {
if ($this->counter % 5 === 0) {
Storage::put('avatar-deep-clean.json', $id);
}
}
protected function activeCheck()
{
if(Storage::exists('avatar-deep-clean.json') || Cache::has('cmd:asdp')) {
if (Storage::exists('avatar-deep-clean.json') || Cache::has('cmd:asdp')) {
return false;
}

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Http\File;
use Illuminate\Console\Command;
use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;
use Spatie\Backup\BackupDestination\BackupDestination;
@ -40,37 +40,39 @@ class BackupToCloud extends Command
*/
public function handle()
{
$localDisk = Storage::disk('local');
$cloudDisk = Storage::disk('backup');
$backupDestination = new BackupDestination($localDisk, '', 'local');
$localDisk = Storage::disk('local');
$cloudDisk = Storage::disk('backup');
$backupDestination = new BackupDestination($localDisk, '', 'local');
if (
empty(config('filesystems.disks.backup.key')) ||
empty(config('filesystems.disks.backup.secret')) ||
empty(config('filesystems.disks.backup.endpoint')) ||
empty(config('filesystems.disks.backup.region')) ||
empty(config('filesystems.disks.backup.bucket'))
) {
$this->error('Backup disk not configured.');
$this->error('See https://docs.pixelfed.org/technical-documentation/env.html#filesystem for more information.');
return Command::FAILURE;
}
if(
empty(config('filesystems.disks.backup.key')) ||
empty(config('filesystems.disks.backup.secret')) ||
empty(config('filesystems.disks.backup.endpoint')) ||
empty(config('filesystems.disks.backup.region')) ||
empty(config('filesystems.disks.backup.bucket'))
) {
$this->error('Backup disk not configured.');
$this->error('See https://docs.pixelfed.org/technical-documentation/env.html#filesystem for more information.');
return Command::FAILURE;
}
$newest = $backupDestination->newestBackup();
$name = $newest->path();
$parts = explode('/', $name);
$fileName = array_pop($parts);
$storagePath = 'backups';
$path = storage_path('app/'.$name);
$file = $cloudDisk->putFileAs($storagePath, new File($path), $fileName, 'private');
$this->info('Backup file successfully saved!');
$url = $cloudDisk->url($file);
$this->table(
['Name', 'URL'],
[
[$fileName, $url],
],
);
$newest = $backupDestination->newestBackup();
$name = $newest->path();
$parts = explode('/', $name);
$fileName = array_pop($parts);
$storagePath = 'backups';
$path = storage_path('app/'. $name);
$file = $cloudDisk->putFileAs($storagePath, new File($path), $fileName, 'private');
$this->info("Backup file successfully saved!");
$url = $cloudDisk->url($file);
$this->table(
['Name', 'URL'],
[
[$fileName, $url]
],
);
return Command::SUCCESS;
return Command::SUCCESS;
}
}

@ -2,9 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\User;
use App\Services\EmailService;
use App\User;
use Illuminate\Console\Command;
class BannedEmailCheck extends Command
{
@ -39,12 +39,12 @@ class BannedEmailCheck extends Command
*/
public function handle()
{
$users = User::whereNull('status')->get()->filter(function($u) {
$users = User::whereNull('status')->get()->filter(function ($u) {
return EmailService::isBanned($u->email) == true;
});
foreach($users as $user) {
$this->info('Found banned domain: ' . $user->email . PHP_EOL);
foreach ($users as $user) {
$this->info('Found banned domain: '.$user->email.PHP_EOL);
}
}
}

@ -2,10 +2,11 @@
namespace App\Console\Commands;
use App\Services\ConfigCacheService;
use Illuminate\Console\Command;
use function Laravel\Prompts\info;
use function Laravel\Prompts\confirm;
use App\Services\ConfigCacheService;
use function Laravel\Prompts\info;
class CaptchaToggleCommand extends Command
{
@ -32,8 +33,9 @@ class CaptchaToggleCommand extends Command
info($captchaEnabled ? 'Captcha is enabled' : 'Captcha is not enabled');
if(!$captchaEnabled) {
if (! $captchaEnabled) {
info('Enable the Captcha from the admin settings dashboard.');
return;
}
@ -45,7 +47,7 @@ class CaptchaToggleCommand extends Command
hint: 'Select an option to proceed.'
);
if($confirmed) {
if ($confirmed) {
ConfigCacheService::put('captcha.enabled', false);
}
}

@ -2,7 +2,6 @@
namespace App\Console\Commands;
use DB;
use App\Jobs\ImageOptimizePipeline\ImageOptimize;
use App\Media;
use Illuminate\Console\Command;
@ -42,7 +41,7 @@ class CatchUnoptimizedMedia extends Command
{
$hasLimit = (bool) config('media.image_optimize.catch_unoptimized_media_hour_limit');
Media::whereNull('processed_at')
->when($hasLimit, function($q, $hasLimit) {
->when($hasLimit, function ($q, $hasLimit) {
$q->where('created_at', '>', now()->subHours(1));
})->whereNull('remote_url')
->whereNotNull('status_id')
@ -52,9 +51,11 @@ class CatchUnoptimizedMedia extends Command
'image/jpeg',
'image/png',
])
->chunk(50, function($medias) {
->chunk(50, function ($medias) {
foreach ($medias as $media) {
if ($media->skip_optimize) continue;
if ($media->skip_optimize) {
continue;
}
ImageOptimize::dispatch($media);
}
});

@ -2,10 +2,10 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Media;
use App\Services\MediaStorageService;
use App\Util\Lexer\PrettyNumber;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@ -36,20 +36,22 @@ class CloudMediaMigrate extends Command
public function handle()
{
$enabled = (bool) config_cache('pixelfed.cloud_storage');
if(!$enabled) {
if (! $enabled) {
$this->error('Cloud storage not enabled. Exiting...');
return;
}
if(!$this->confirm('Are you sure you want to proceed?')) {
if (! $this->confirm('Are you sure you want to proceed?')) {
return;
}
$limit = $this->option('limit');
$hugeMode = $this->option('huge');
if($limit > 500 && !$hugeMode) {
if ($limit > 500 && ! $hugeMode) {
$this->error('Max limit exceeded, use a limit lower than 500 or run again with the --huge flag');
return;
}
@ -64,19 +66,22 @@ class CloudMediaMigrate extends Command
->orderByDesc('size')
->take($limit)
->get()
->each(function($media) use($bar) {
if(Storage::disk('local')->exists($media->media_path)) {
->each(function ($media) use ($bar) {
if (Storage::disk('local')->exists($media->media_path)) {
$this->totalSize = $this->totalSize + $media->size;
try {
MediaStorageService::store($media);
} catch (FileNotFoundException $e) {
$this->error('Error migrating media ' . $media->id . ' to cloud storage: ' . $e->getMessage());
$this->error('Error migrating media '.$media->id.' to cloud storage: '.$e->getMessage());
return;
} catch (NotFoundHttpException $e) {
$this->error('Error migrating media ' . $media->id . ' to cloud storage: ' . $e->getMessage());
$this->error('Error migrating media '.$media->id.' to cloud storage: '.$e->getMessage());
return;
} catch (\Exception $e) {
$this->error('Error migrating media ' . $media->id . ' to cloud storage: ' . $e->getMessage());
$this->error('Error migrating media '.$media->id.' to cloud storage: '.$e->getMessage());
return;
}
}
@ -86,11 +91,12 @@ class CloudMediaMigrate extends Command
$bar->finish();
$this->line(' ');
$this->info('Finished!');
if($this->totalSize) {
$this->info('Uploaded ' . PrettyNumber::size($this->totalSize) . ' of media to cloud storage!');
if ($this->totalSize) {
$this->info('Uploaded '.PrettyNumber::size($this->totalSize).' of media to cloud storage!');
$this->line(' ');
$this->info('These files are still stored locally, and will be automatically removed.');
}
return Command::SUCCESS;
}
}

@ -84,8 +84,8 @@ class CuratedOnboardingCommand extends Command
->orWhereLike('email', "%{$value}%");
})->get()
->mapWithKeys(fn ($user) => [
$user->id => "{$user->username} ({$user->email})",
])
$user->id => "{$user->username} ({$user->email})",
])
->all()
: []
);

@ -38,18 +38,18 @@ class DatabaseSessionGarbageCollector extends Command
*/
public function handle()
{
if(config('session.driver') !== 'database') {
return Command::SUCCESS;
}
DB::transaction(function() {
DB::table('sessions')->whereNull('user_id')->delete();
});
DB::transaction(function() {
$ts = now()->subMonths(3)->timestamp;
DB::table('sessions')->where('last_activity', '<', $ts)->delete();
});
if (config('session.driver') !== 'database') {
return Command::SUCCESS;
}
DB::transaction(function () {
DB::table('sessions')->whereNull('user_id')->delete();
});
DB::transaction(function () {
$ts = now()->subMonths(3)->timestamp;
DB::table('sessions')->where('last_activity', '<', $ts)->delete();
});
return Command::SUCCESS;
}

@ -2,13 +2,13 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\User;
use App\Models\DefaultDomainBlock;
use App\Models\UserDomainBlock;
use function Laravel\Prompts\text;
use Illuminate\Console\Command;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\progress;
use function Laravel\Prompts\text;
class DeleteUserDomainBlock extends Command
{
@ -34,41 +34,42 @@ class DeleteUserDomainBlock extends Command
$domain = text('Enter domain you want to unblock');
$domain = strtolower($domain);
$domain = $this->validateDomain($domain);
if(!$domain) {
if (! $domain) {
$this->error('Invalid domain');
return;
}
$this->processUnblocks($domain);
return;
}
protected function validateDomain($domain)
{
if(!strpos($domain, '.')) {
if (! strpos($domain, '.')) {
return;
}
if(str_starts_with($domain, 'https://')) {
if (str_starts_with($domain, 'https://')) {
$domain = str_replace('https://', '', $domain);
}
if(str_starts_with($domain, 'http://')) {
if (str_starts_with($domain, 'http://')) {
$domain = str_replace('http://', '', $domain);
}
$domain = strtolower(parse_url('https://' . $domain, PHP_URL_HOST));
$domain = strtolower(parse_url('https://'.$domain, PHP_URL_HOST));
$valid = filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME|FILTER_NULL_ON_FAILURE);
if(!$valid) {
$valid = filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME | FILTER_NULL_ON_FAILURE);
if (! $valid) {
return;
}
if($domain === config('pixelfed.domain.app')) {
if ($domain === config('pixelfed.domain.app')) {
return;
}
$confirmed = confirm('Are you sure you want to unblock ' . $domain . '?');
if(!$confirmed) {
$confirmed = confirm('Are you sure you want to unblock '.$domain.'?');
if (! $confirmed) {
return;
}
@ -78,8 +79,9 @@ class DeleteUserDomainBlock extends Command
protected function processUnblocks($domain)
{
DefaultDomainBlock::whereDomain($domain)->delete();
if(!UserDomainBlock::whereDomain($domain)->count()) {
if (! UserDomainBlock::whereDomain($domain)->count()) {
$this->info('No results found!');
return;
}
progress(

@ -27,7 +27,7 @@ class ExportLanguages extends Command
*/
public function __construct()
{
parent::__construct();
parent::__construct();
}
/**
@ -37,38 +37,39 @@ class ExportLanguages extends Command
*/
public function handle()
{
if(config('app.env') !== 'local') {
$this->error('This command is meant for development purposes and should only be run in a local environment');
return Command::FAILURE;
}
if (config('app.env') !== 'local') {
$this->error('This command is meant for development purposes and should only be run in a local environment');
$path = base_path('resources/lang');
$langs = [];
return Command::FAILURE;
}
foreach (new \DirectoryIterator($path) as $io) {
$name = $io->getFilename();
$skip = ['vendor'];
if($io->isDot() || in_array($name, $skip)) {
continue;
}
$path = base_path('resources/lang');
$langs = [];
if($io->isDir()) {
array_push($langs, $name);
}
}
foreach (new \DirectoryIterator($path) as $io) {
$name = $io->getFilename();
$skip = ['vendor'];
if ($io->isDot() || in_array($name, $skip)) {
continue;
}
$exportDir = resource_path('assets/js/i18n/');
$exportDirAlt = public_path('_lang/');
if ($io->isDir()) {
array_push($langs, $name);
}
}
foreach($langs as $lang) {
$strings = \Lang::get('web', [], $lang);
$json = json_encode($strings, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
$path = "{$exportDir}{$lang}.json";
file_put_contents($path, $json);
$pathAlt = "{$exportDirAlt}{$lang}.json";
file_put_contents($pathAlt, $json);
}
$exportDir = resource_path('assets/js/i18n/');
$exportDirAlt = public_path('_lang/');
return Command::SUCCESS;
foreach ($langs as $lang) {
$strings = \Lang::get('web', [], $lang);
$json = json_encode($strings, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
$path = "{$exportDir}{$lang}.json";
file_put_contents($path, $json);
$pathAlt = "{$exportDirAlt}{$lang}.json";
file_put_contents($pathAlt, $json);
}
return Command::SUCCESS;
}
}

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\FailedJob;
use Illuminate\Console\Command;
class FailedJobGC extends Command
{
@ -38,9 +38,9 @@ class FailedJobGC extends Command
*/
public function handle()
{
FailedJob::chunk(50, function($jobs) {
foreach($jobs as $job) {
if($job->failed_at->lt(now()->subHours(48))) {
FailedJob::chunk(50, function ($jobs) {
foreach ($jobs as $job) {
if ($job->failed_at->lt(now()->subHours(48))) {
$job->delete();
}
}

@ -2,40 +2,36 @@
namespace App\Console\Commands;
use App\Avatar;
use App\Bookmark;
use App\Collection;
use App\DirectMessage;
use App\Follower;
use App\FollowRequest;
use App\HashtagFollow;
use App\Like;
use App\Media;
use App\MediaTag;
use App\Mention;
use App\Models\Conversation;
use App\Models\Portfolio;
use App\Models\UserPronoun;
use App\Profile;
use App\Report;
use App\ReportComment;
use App\ReportLog;
use App\Status;
use App\StatusArchived;
use App\StatusHashtag;
use App\StatusView;
use App\Story;
use App\StoryView;
use App\User;
use App\UserFilter;
use Cache;
use DB;
use Illuminate\Console\Command;
use App\{
Avatar,
Bookmark,
Collection,
DirectMessage,
FollowRequest,
Follower,
HashtagFollow,
Like,
Media,
MediaTag,
Mention,
Profile,
Report,
ReportComment,
ReportLog,
StatusArchived,
StatusHashtag,
StatusView,
Status,
Story,
StoryView,
User,
UserFilter
};
use App\Models\{
Conversation,
Portfolio,
UserPronoun
};
use DB, Cache;
class FixDuplicateProfiles extends Command
{
/**
@ -76,16 +72,16 @@ class FixDuplicateProfiles extends Command
->havingRaw('COUNT(*) > 1')
->pluck('username');
foreach($duplicates as $dupe) {
foreach ($duplicates as $dupe) {
$ids = Profile::whereNull('domain')->whereUsername($dupe)->pluck('id');
if(!$ids || $ids->count() != 2) {
if (! $ids || $ids->count() != 2) {
continue;
}
$id = $ids->first();
$oid = $ids->last();
$user = User::whereUsername($dupe)->first();
if($user) {
if ($user) {
$user->profile_id = $id;
$user->save();
} else {
@ -156,17 +152,17 @@ class FixDuplicateProfiles extends Command
protected function checkFollowers($id, $oid)
{
$f = Follower::whereProfileId($oid)->pluck('following_id');
foreach($f as $fo) {
foreach ($f as $fo) {
Follower::updateOrCreate([
'profile_id' => $id,
'following_id' => $fo
'following_id' => $fo,
]);
}
$f = Follower::whereFollowingId($oid)->pluck('profile_id');
foreach($f as $fo) {
foreach ($f as $fo) {
Follower::updateOrCreate([
'profile_id' => $fo,
'following_id' => $id
'following_id' => $id,
]);
}
}
@ -250,5 +246,4 @@ class FixDuplicateProfiles extends Command
{
UserPronoun::whereProfileId($oid)->update(['profile_id' => $id]);
}
}

@ -2,13 +2,9 @@
namespace App\Console\Commands;
use App\Hashtag;
use App\StatusHashtag;
use Illuminate\Console\Command;
use DB;
use App\{
Hashtag,
Status,
StatusHashtag
};
class FixHashtags extends Command
{
@ -51,18 +47,37 @@ class FixHashtags extends Command
$this->info(' /_/ /_/_/|_|\___/_/_/ \___/\__,_/ ');
$this->info(' ');
$this->info(' ');
$this->info('Pixelfed version: ' . config('pixelfed.version'));
$this->info('Pixelfed version: '.config('pixelfed.version'));
$this->info(' ');
$this->info('Running Fix Hashtags command');
$this->info(' ');
$this->info('Found '.Hashtag::count().' total hashtags!');
$count = 0;
foreach (Hashtag::lazyById(100, 'id') as $tag) {
$slug = str_slug($tag->name, '-', false);
if ($slug === $tag->slug) {
continue;
}
$count = Hashtag::whereName($tag->name)->where('slug', '===', $slug)->count();
if (! $count) {
continue;
}
$this->info($count.':'.$tag->slug.' : '.str_slug($tag->name, '-', false));
}
$this->info('Found '.$count.' broken tags');
return;
$missingCount = StatusHashtag::doesntHave('profile')->doesntHave('status')->count();
if($missingCount > 0) {
if ($missingCount > 0) {
$this->info("Found {$missingCount} orphaned StatusHashtag records to delete ...");
$this->info(' ');
$bar = $this->output->createProgressBar($missingCount);
$bar->start();
foreach(StatusHashtag::doesntHave('profile')->doesntHave('status')->get() as $tag) {
foreach (StatusHashtag::doesntHave('profile')->doesntHave('status')->get() as $tag) {
$tag->delete();
$bar->advance();
}
@ -72,17 +87,17 @@ class FixHashtags extends Command
$this->info(' ');
$this->info('Found no orphaned hashtags to delete!');
}
$this->info(' ');
$count = StatusHashtag::whereNull('status_visibility')->count();
if($count > 0) {
if ($count > 0) {
$this->info("Found {$count} hashtags to fix ...");
$this->info(' ');
} else {
$this->info('Found no hashtags to fix!');
$this->info(' ');
return;
}
@ -90,17 +105,17 @@ class FixHashtags extends Command
$bar->start();
StatusHashtag::with('status')
->whereNull('status_visibility')
->chunk(50, function($tags) use($bar) {
foreach($tags as $tag) {
if(!$tag->status || !$tag->status->scope) {
continue;
->whereNull('status_visibility')
->chunk(50, function ($tags) use ($bar) {
foreach ($tags as $tag) {
if (! $tag->status || ! $tag->status->scope) {
continue;
}
$tag->status_visibility = $tag->status->scope;
$tag->save();
$bar->advance();
}
$tag->status_visibility = $tag->status->scope;
$tag->save();
$bar->advance();
}
});
});
$bar->finish();
$this->info(' ');

@ -2,9 +2,9 @@
namespace App\Console\Commands;
use App\Like;
use App\Status;
use Illuminate\Console\Command;
use App\{Like, Status};
use DB;
class FixLikes extends Command
{
@ -41,10 +41,11 @@ class FixLikes extends Command
{
$chunk = 100;
$limit = Like::select('status_id')->groupBy('status_id')->count();
if($limit > 1000) {
if($this->confirm('We have found more than 1000 records to update, this may take a few moments. Are you sure you want to continue?') == false) {
if ($limit > 1000) {
if ($this->confirm('We have found more than 1000 records to update, this may take a few moments. Are you sure you want to continue?') == false) {
$this->error('Cancelling command...');
return;
}
}
@ -56,11 +57,11 @@ class FixLikes extends Command
$bar->start();
Like::selectRaw('count(id) as count, status_id')
->groupBy(['status_id','id'])
->chunk($chunk, function($likes) use($bar) {
foreach($likes as $like) {
->groupBy(['status_id', 'id'])
->chunk($chunk, function ($likes) use ($bar) {
foreach ($likes as $like) {
$s = Status::find($like['status_id']);
if($s && $s->likes_count == 0) {
if ($s && $s->likes_count == 0) {
$s->likes_count = $like['count'];
$s->save();
}

@ -2,12 +2,12 @@
namespace App\Console\Commands;
use App\Jobs\ImageOptimizePipeline\ImageOptimize;
use App\Jobs\MediaPipeline\MediaFixLocalFilesystemCleanupPipeline;
use App\Media;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use App\Media;
use League\Flysystem\MountManager;
use App\Jobs\ImageOptimizePipeline\ImageOptimize;
use App\Jobs\MediaPipeline\MediaFixLocalFilesystemCleanupPipeline;
class FixMediaDriver extends Command
{
@ -32,13 +32,15 @@ class FixMediaDriver extends Command
*/
public function handle()
{
if(config('filesystems.default') !== 'local') {
if (config('filesystems.default') !== 'local') {
$this->error('Invalid default filesystem, set FILESYSTEM_DRIVER=local to proceed');
return Command::SUCCESS;
}
if((bool) config_cache('pixelfed.cloud_storage') == false) {
if ((bool) config_cache('pixelfed.cloud_storage') == false) {
$this->error('Cloud storage not enabled, exiting...');
return Command::SUCCESS;
}
@ -58,8 +60,9 @@ class FixMediaDriver extends Command
$this->info(' ');
$this->error(' Remember, FILESYSTEM_DRIVER=local must remain set or you will break things!');
if(!$this->confirm('Are you sure you want to perform this command?')) {
if (! $this->confirm('Are you sure you want to perform this command?')) {
$this->info('Exiting...');
return Command::SUCCESS;
}
@ -80,27 +83,27 @@ class FixMediaDriver extends Command
$bar = $this->output->createProgressBar(Media::whereNotNull('status_id')->whereNull('cdn_url')->count());
$bar->start();
foreach(Media::whereNotNull('status_id')->whereNull('cdn_url')->lazyById(20) as $media) {
if($cloud->exists($media->media_path)) {
if($optimize === 'yes') {
foreach (Media::whereNotNull('status_id')->whereNull('cdn_url')->lazyById(20) as $media) {
if ($cloud->exists($media->media_path)) {
if ($optimize === 'yes') {
$mountManager->copy(
's3://' . $media->media_path,
'local://' . $media->media_path
's3://'.$media->media_path,
'local://'.$media->media_path
);
sleep(1);
if(empty($media->original_sha256)) {
if (empty($media->original_sha256)) {
$hash = \hash_file('sha256', Storage::disk('local')->path($media->media_path));
$media->original_sha256 = $hash;
$media->save();
sleep(1);
}
if(
if (
$media->mime &&
in_array($media->mime, [
'image/jpg',
'image/jpeg',
'image/png',
'image/webp'
'image/webp',
])
) {
ImageOptimize::dispatch($media);
@ -122,13 +125,14 @@ class FixMediaDriver extends Command
$this->info('Successfully fixed media paths and cleared cached!');
if($optimize === 'yes') {
if ($optimize === 'yes') {
MediaFixLocalFilesystemCleanupPipeline::dispatch()->delay(now()->addMinutes(15))->onQueue('default');
$this->line(' ');
$this->info('A cleanup job has been dispatched to delete media stored locally, it may take a few minutes to process!');
}
$this->line(' ');
return Command::SUCCESS;
}
}

@ -2,18 +2,17 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Jobs\AvatarPipeline\CreateAvatar;
use App\Follower;
use App\Jobs\AvatarPipeline\CreateAvatar;
use App\Jobs\FollowPipeline\FollowPipeline;
use App\Models\DefaultDomainBlock;
use App\Models\UserDomainBlock;
use App\Profile;
use App\User;
use App\UserSetting;
use App\Services\UserFilterService;
use App\Models\DefaultDomainBlock;
use App\Models\UserDomainBlock;
use App\Jobs\FollowPipeline\FollowPipeline;
use DB;
use App\Services\FollowerService;
use Illuminate\Console\Command;
use function Laravel\Prompts\search;
class FixMissingUserProfile extends Command
@ -44,35 +43,38 @@ class FixMissingUserProfile extends Command
: []
);
if(!$id) {
if (! $id) {
$this->error('Found none');
}
$user = User::find($id);
if($user->profile) {
if ($user->profile) {
$this->error('Already has profile');
return;
}
if(in_array($user->status, ['deleted', 'delete'])) {
if (in_array($user->status, ['deleted', 'delete'])) {
$this->error('User has deleted account');
return;
}
if(Profile::whereUsername($user->username)->exists()) {
if (Profile::whereUsername($user->username)->exists()) {
$this->error('Already has profile');
return;
}
if (empty($user->profile)) {
$profile = DB::transaction(function() use($user) {
$profile = new Profile();
$profile = DB::transaction(function () use ($user) {
$profile = new Profile;
$profile->user_id = $user->id;
$profile->username = $user->username;
$profile->name = $user->name;
$pkiConfig = [
'digest_alg' => 'sha512',
'digest_alg' => 'sha512',
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
];
@ -85,11 +87,11 @@ class FixMissingUserProfile extends Command
$profile->public_key = $pki_public;
$profile->save();
$this->applyDefaultDomainBlocks($user);
return $profile;
});
DB::transaction(function() use($user, $profile) {
DB::transaction(function () use ($user, $profile) {
$user = User::findOrFail($user->id);
$user->profile_id = $profile->id;
$user->save();
@ -97,18 +99,18 @@ class FixMissingUserProfile extends Command
CreateAvatar::dispatch($profile);
});
if((bool) config_cache('account.autofollow') == true) {
if ((bool) config_cache('account.autofollow') == true) {
$names = config_cache('account.autofollow_usernames');
$names = explode(',', $names);
if(!$names || !last($names)) {
if (! $names || ! last($names)) {
return;
}
$profiles = Profile::whereIn('username', $names)->get();
if($profiles) {
foreach($profiles as $p) {
if ($profiles) {
foreach ($profiles as $p) {
$follower = new Follower;
$follower->profile_id = $profile->id;
$follower->following_id = $p->id;
@ -121,9 +123,9 @@ class FixMissingUserProfile extends Command
}
if (empty($user->settings)) {
DB::transaction(function() use($user) {
DB::transaction(function () use ($user) {
UserSetting::firstOrCreate([
'user_id' => $user->id
'user_id' => $user->id,
]);
});
}
@ -131,19 +133,19 @@ class FixMissingUserProfile extends Command
protected function applyDefaultDomainBlocks($user)
{
if($user->profile_id == null) {
if ($user->profile_id == null) {
return;
}
$defaultDomainBlocks = DefaultDomainBlock::pluck('domain')->toArray();
if(!$defaultDomainBlocks || !count($defaultDomainBlocks)) {
if (! $defaultDomainBlocks || ! count($defaultDomainBlocks)) {
return;
}
foreach($defaultDomainBlocks as $domain) {
foreach ($defaultDomainBlocks as $domain) {
UserDomainBlock::updateOrCreate([
'profile_id' => $user->profile_id,
'domain' => strtolower(trim($domain))
'domain' => strtolower(trim($domain)),
]);
}
}

@ -2,9 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Profile;
use App\Status;
use Illuminate\Console\Command;
class FixRemotePostCount extends Command
{
@ -39,8 +39,8 @@ class FixRemotePostCount extends Command
*/
public function handle()
{
Profile::whereNotNull('domain')->chunk(50, function($profiles) {
foreach($profiles as $profile) {
Profile::whereNotNull('domain')->chunk(50, function ($profiles) {
foreach ($profiles as $profile) {
$count = Status::whereNull(['in_reply_to_id', 'reblog_of_id'])->whereProfileId($profile->id)->count();
$this->info("Checking {$profile->id} {$profile->username} - found {$count} statuses");
$profile->status_count = $count;

@ -2,9 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Profile;
use App\Services\AccountService;
use Illuminate\Console\Command;
class FixStatusCount extends Command
{
@ -39,7 +38,7 @@ class FixStatusCount extends Command
*/
public function handle()
{
if(!$this->confirm('Are you sure you want to run the fix status command?')) {
if (! $this->confirm('Are you sure you want to run the fix status command?')) {
return;
}
$this->line(' ');
@ -51,7 +50,7 @@ class FixStatusCount extends Command
$resync = $this->option('resync');
$resync24hours = false;
if($resync) {
if ($resync) {
$resyncChoices = ['Only resync accounts that havent been synced in 24 hours', 'Resync all accounts'];
$rsc = $this->choice(
'Do you want to resync all accounts, or just accounts that havent been resynced for 24 hours?',
@ -59,7 +58,7 @@ class FixStatusCount extends Command
0
);
$rsci = array_search($rsc, $resyncChoices);
if($rsci === 0) {
if ($rsci === 0) {
$resync24hours = true;
$nulls = ['status', 'domain', 'last_fetched_at'];
} else {
@ -70,7 +69,7 @@ class FixStatusCount extends Command
$remote = $this->option('remote');
if($remote) {
if ($remote) {
$ni = array_search('domain', $nulls);
unset($nulls[$ni]);
$ni = array_search('last_fetched_at', $nulls);
@ -79,7 +78,7 @@ class FixStatusCount extends Command
$remoteOnly = $this->option('remote-only');
if($remoteOnly) {
if ($remoteOnly) {
$ni = array_search('domain', $nulls);
unset($nulls[$ni]);
$ni = array_search('last_fetched_at', $nulls);
@ -91,9 +90,9 @@ class FixStatusCount extends Command
$nulls = array_values($nulls);
foreach(
Profile::when($resync24hours, function($query, $resync24hours) use($nulls) {
if(in_array('domain', $nulls)) {
foreach (
Profile::when($resync24hours, function ($query, $resync24hours) use ($nulls) {
if (in_array('domain', $nulls)) {
return $query->whereNull('domain')
->whereNull('last_fetched_at')
->orWhere('last_fetched_at', '<', now()->subHours(24));
@ -102,31 +101,30 @@ class FixStatusCount extends Command
->orWhere('last_fetched_at', '<', now()->subHours(24));
}
})
->when($remoteOnly, function($query, $remoteOnly) {
return $query->whereNull('last_fetched_at')
->orWhere('last_fetched_at', '<', now()->subHours(24));
})
->whereNull($nulls)
->lazyById(50, 'id') as $profile
->when($remoteOnly, function ($query, $remoteOnly) {
return $query->whereNull('last_fetched_at')
->orWhere('last_fetched_at', '<', now()->subHours(24));
})
->whereNull($nulls)
->lazyById(50, 'id') as $profile
) {
$ogc = $profile->status_count;
$upc = $profile->statuses()
->getQuery()
->whereIn('scope', ['public', 'private', 'unlisted'])
->count();
if($ogc != $upc) {
->getQuery()
->whereIn('scope', ['public', 'private', 'unlisted'])
->count();
if ($ogc != $upc) {
$profile->status_count = $upc;
$profile->last_fetched_at = $now;
$profile->save();
AccountService::del($profile->id);
if($dlog) {
$this->info($profile->id . ':' . $profile->username . ' : ' . $upc);
if ($dlog) {
$this->info($profile->id.':'.$profile->username.' : '.$upc);
}
} else {
$profile->last_fetched_at = $now;
$profile->save();
if($dlog) {
$this->info($profile->id . ':' . $profile->username . ' : ' . $upc);
if ($dlog) {
$this->info($profile->id.':'.$profile->username.' : '.$upc);
}
}
}

@ -2,10 +2,11 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\{Profile, User};
use DB;
use App\Profile;
use App\User;
use App\Util\Lexer\RestrictedNames;
use DB;
use Illuminate\Console\Command;
class FixUsernames extends Command
{
@ -52,67 +53,67 @@ class FixUsernames extends Command
$restricted = RestrictedNames::get();
$users = User::chunk(100, function($users) use($affected, $restricted) {
foreach($users as $user) {
if($user->is_admin || $user->status == 'deleted') {
$users = User::chunk(100, function ($users) use ($affected, $restricted) {
foreach ($users as $user) {
if ($user->is_admin || $user->status == 'deleted') {
continue;
}
if(in_array(strtolower($user->username), array_map('strtolower', $restricted))) {
if (in_array(strtolower($user->username), array_map('strtolower', $restricted))) {
$affected->push($user);
}
$val = str_replace(['-', '_', '.'], '', $user->username);
if(!ctype_alnum($val)) {
$this->info('Found invalid username: ' . $user->username);
if (! ctype_alnum($val)) {
$this->info('Found invalid username: '.$user->username);
$affected->push($user);
}
}
});
if($affected->count() > 0) {
$this->info('Found: ' . $affected->count() . ' affected usernames');
if ($affected->count() > 0) {
$this->info('Found: '.$affected->count().' affected usernames');
$opts = [
'Random replace (assigns random username)',
'Best try replace (assigns alpha numeric username)',
'Manual replace (manually set username)',
'Skip (do not replace. Use at your own risk)'
'Skip (do not replace. Use at your own risk)',
];
foreach($affected as $u) {
foreach ($affected as $u) {
$old = $u->username;
$this->info("Found user: {$old}");
$opt = $this->choice('Select fix method:', $opts, 3);
switch ($opt) {
case $opts[0]:
$new = "user_" . str_random(6);
$this->info('New username: ' . $new);
$new = 'user_'.str_random(6);
$this->info('New username: '.$new);
break;
case $opts[1]:
$new = htmlspecialchars($old, ENT_QUOTES, 'UTF-8');
if(strlen($new) < 6) {
$new = $new . '_' . str_random(4);
if (strlen($new) < 6) {
$new = $new.'_'.str_random(4);
}
$this->info('New username: ' . $new);
$this->info('New username: '.$new);
break;
case $opts[2]:
$new = $this->ask('Enter new username:');
$this->info('New username: ' . $new);
$this->info('New username: '.$new);
break;
case $opts[3]:
$new = false;
break;
default:
$new = "user_" . str_random(6);
$new = 'user_'.str_random(6);
break;
}
if($new) {
DB::transaction(function() use($u, $new) {
if ($new) {
DB::transaction(function () use ($u, $new) {
$profile = $u->profile;
$profile->username = $new;
$u->username = $new;
@ -120,10 +121,10 @@ class FixUsernames extends Command
$profile->save();
});
}
$this->info('Selected: ' . $opt);
$this->info('Selected: '.$opt);
}
$this->info('Fixed ' . $affected->count() . ' usernames!');
$this->info('Fixed '.$affected->count().' usernames!');
} else {
$this->info('No restricted usernames found!');
}
@ -140,23 +141,24 @@ class FixUsernames extends Command
$count = $profiles->count();
if($count > 0) {
if ($count > 0) {
$this->info("Found {$count} remote usernames to fix ...");
$this->line(' ');
} else {
$this->info('No remote fixes found!');
$this->line(' ');
return;
}
foreach($profiles as $p) {
foreach ($profiles as $p) {
$this->info("Fixed $p->username => $p->webfinger");
$p->username = $p->webfinger ?? "@{$p->username}@{$p->domain}";
if(Profile::whereUsername($p->username)->exists()) {
if (Profile::whereUsername($p->username)->exists()) {
return;
}
$p->save();
}
if($count > 0) {
if ($count > 0) {
$this->line(' ');
}

@ -2,72 +2,73 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
use App\Models\InstanceActor;
use Cache;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Schema;
class GenerateInstanceActor extends Command
{
protected $signature = 'instance:actor';
protected $description = 'Generate instance actor';
protected $signature = 'instance:actor';
protected $description = 'Generate instance actor';
public function __construct()
{
parent::__construct();
}
public function __construct()
{
parent::__construct();
}
public function handle()
{
if (Schema::hasTable('instance_actors') == false) {
$this->line(' ');
$this->error('Missing instance_actors table.');
$this->info('Run "php artisan migrate" and try again.');
$this->line(' ');
exit;
}
public function handle()
{
if(Schema::hasTable('instance_actors') == false) {
$this->line(' ');
$this->error('Missing instance_actors table.');
$this->info('Run "php artisan migrate" and try again.');
$this->line(' ');
exit;
}
if (InstanceActor::exists()) {
$actor = InstanceActor::whereNotNull('public_key')
->whereNotNull('private_key')
->firstOrFail();
Cache::rememberForever(InstanceActor::PKI_PUBLIC, function () use ($actor) {
return $actor->public_key;
});
if(InstanceActor::exists()) {
$actor = InstanceActor::whereNotNull('public_key')
->whereNotNull('private_key')
->firstOrFail();
Cache::rememberForever(InstanceActor::PKI_PUBLIC, function() use($actor) {
return $actor->public_key;
});
Cache::rememberForever(InstanceActor::PKI_PRIVATE, function () use ($actor) {
return $actor->private_key;
});
$this->info('Instance actor succesfully generated. You do not need to run this command again.');
Cache::rememberForever(InstanceActor::PKI_PRIVATE, function() use($actor) {
return $actor->private_key;
});
$this->info('Instance actor succesfully generated. You do not need to run this command again.');
return;
}
return;
}
$pkiConfig = [
'digest_alg' => 'sha512',
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
];
$pki = openssl_pkey_new($pkiConfig);
openssl_pkey_export($pki, $pki_private);
$pki_public = openssl_pkey_get_details($pki);
$pki_public = $pki_public['key'];
$pkiConfig = [
'digest_alg' => 'sha512',
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
];
$pki = openssl_pkey_new($pkiConfig);
openssl_pkey_export($pki, $pki_private);
$pki_public = openssl_pkey_get_details($pki);
$pki_public = $pki_public['key'];
$actor = new InstanceActor();
$actor->public_key = $pki_public;
$actor->private_key = $pki_private;
$actor->save();
$actor = new InstanceActor;
$actor->public_key = $pki_public;
$actor->private_key = $pki_private;
$actor->save();
Cache::rememberForever(InstanceActor::PKI_PUBLIC, function() use($actor) {
return $actor->public_key;
});
Cache::rememberForever(InstanceActor::PKI_PUBLIC, function () use ($actor) {
return $actor->public_key;
});
Cache::rememberForever(InstanceActor::PKI_PRIVATE, function() use($actor) {
return $actor->private_key;
});
Cache::rememberForever(InstanceActor::PKI_PRIVATE, function () use ($actor) {
return $actor->private_key;
});
$this->info('Instance actor succesfully generated. You do not need to run this command again.');
$this->info('Instance actor succesfully generated. You do not need to run this command again.');
return 0;
}
return 0;
}
}

@ -2,10 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Hashtag;
use App\StatusHashtag;
use DB;
use Illuminate\Console\Command;
class HashtagCachedCountUpdate extends Command
{
@ -31,19 +30,20 @@ class HashtagCachedCountUpdate extends Command
$limit = $this->option('limit');
$tags = Hashtag::whereNull('cached_count')->limit($limit)->get();
$count = count($tags);
if(!$count) {
if (! $count) {
return;
}
$bar = $this->output->createProgressBar($count);
$bar->start();
foreach($tags as $tag) {
foreach ($tags as $tag) {
$count = DB::table('status_hashtags')->whereHashtagId($tag->id)->count();
if(!$count) {
if (! $count) {
$tag->cached_count = 0;
$tag->saveQuietly();
$bar->advance();
continue;
}
$tag->cached_count = $count;
@ -52,6 +52,6 @@ class HashtagCachedCountUpdate extends Command
}
$bar->finish();
$this->line(' ');
return;
}
}

@ -2,14 +2,15 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Hashtag;
use App\StatusHashtag;
use App\Models\HashtagRelated;
use App\Services\HashtagRelatedService;
use App\StatusHashtag;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
use function Laravel\Prompts\multiselect;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\multiselect;
class HashtagRelatedGenerate extends Command implements PromptsForMissingInput
{
@ -46,30 +47,30 @@ class HashtagRelatedGenerate extends Command implements PromptsForMissingInput
{
$tag = $this->argument('tag');
$hashtag = Hashtag::whereName($tag)->orWhere('slug', $tag)->first();
if(!$hashtag) {
if (! $hashtag) {
$this->error('Hashtag not found, aborting...');
exit;
}
$exists = HashtagRelated::whereHashtagId($hashtag->id)->exists();
if($exists) {
if ($exists) {
$confirmed = confirm('Found existing related tags, do you want to regenerate them?');
if(!$confirmed) {
if (! $confirmed) {
$this->error('Aborting...');
exit;
}
}
$this->info('Looking up #' . $tag . '...');
$this->info('Looking up #'.$tag.'...');
$tags = StatusHashtag::whereHashtagId($hashtag->id)->count();
if(!$tags || $tags < 100) {
if (! $tags || $tags < 100) {
$this->error('Not enough posts found to generate related hashtags!');
exit;
}
$this->info('Found ' . $tags . ' posts that use that hashtag');
$this->info('Found '.$tags.' posts that use that hashtag');
$related = collect(HashtagRelatedService::fetchRelatedTags($tag));
$selected = multiselect(
@ -78,15 +79,15 @@ class HashtagRelatedGenerate extends Command implements PromptsForMissingInput
required: true,
);
$filtered = $related->filter(fn($i) => in_array($i['name'], $selected))->all();
$agg_score = $related->filter(fn($i) => in_array($i['name'], $selected))->sum('related_count');
$filtered = $related->filter(fn ($i) => in_array($i['name'], $selected))->all();
$agg_score = $related->filter(fn ($i) => in_array($i['name'], $selected))->sum('related_count');
HashtagRelated::updateOrCreate([
'hashtag_id' => $hashtag->id,
], [
'related_tags' => array_values($filtered),
'agg_score' => $agg_score,
'last_calculated_at' => now()
'last_calculated_at' => now(),
]);
$this->info('Finished!');

@ -1,9 +1,10 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Place;
use DB;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
class ImportCities extends Command
@ -24,7 +25,6 @@ class ImportCities extends Command
/**
* Checksum of city dataset.
*
*/
const CHECKSUM = 'e203c0247538788b2a91166c7cf4b95f58291d998f514e9306d315aa72b09e48bfd3ddf310bf737afc4eefadca9083b8ff796c67796c6bd8e882a3d268bd16af';
@ -54,7 +54,7 @@ class ImportCities extends Command
'TZ' => 'Tanzania',
'US' => 'USA',
'VE' => 'Venezuela',
'XK' => 'Kosovo'
'XK' => 'Kosovo',
];
/**
@ -77,16 +77,18 @@ class ImportCities extends Command
ini_set('memory_limit', '256M');
$path = storage_path('app/cities.json');
if(hash_file('sha512', $path) !== self::CHECKSUM) {
if (hash_file('sha512', $path) !== self::CHECKSUM) {
$this->error('Invalid or corrupt storage/app/cities.json data.');
$this->line('');
$this->info('Run the following command to fix:');
$this->info('git checkout storage/app/cities.json');
return;
}
if (!is_file($path)) {
if (! is_file($path)) {
$this->error('Missing storage/app/cities.json file!');
return;
}
@ -102,20 +104,20 @@ class ImportCities extends Command
$this->line('');
$this->info("Found {$cityCount} cities to insert ...");
$this->line('');
$bar = $this->output->createProgressBar($cityCount);
$bar->start();
$buffer = [];
$count = 0;
foreach ($cities as $city) {
$buffer[] = [
"name" => $city->name,
"slug" => Str::slug($city->name),
"country" => $this->codeToCountry($city->country),
"lat" => $city->lat,
"long" => $city->lng
'name' => $city->name,
'slug' => Str::slug($city->name),
'country' => $this->codeToCountry($city->country),
'lat' => $city->lat,
'long' => $city->lng,
];
$count++;
@ -134,9 +136,9 @@ class ImportCities extends Command
$this->line('');
$this->line('');
$this->info('Successfully imported ' . $cityCount . ' entries!');
$this->info('Successfully imported '.$cityCount.' entries!');
$this->line('');
return;
}
private function insertBuffer($buffer)
@ -147,12 +149,13 @@ class ImportCities extends Command
private function codeToCountry($code)
{
$countries = $this->countries;
if(isset($countries[$code])) {
if (isset($countries[$code])) {
return $countries[$code];
}
$country = (new \League\ISO3166\ISO3166)->alpha2($code);
$this->countries[$code] = $country['name'];
return $this->countries[$code];
}
}

@ -21,7 +21,6 @@ class ImportEmojis extends Command
{--overwrite : Overwrite existing emojis}
{--disabled : Import all emojis as disabled}';
/**
* The console command description.
*
@ -38,8 +37,9 @@ class ImportEmojis extends Command
{
$path = $this->argument('path');
if (!file_exists($path) || !mime_content_type($path) == 'application/x-tar') {
if (! file_exists($path) || ! mime_content_type($path) == 'application/x-tar') {
$this->error('Path does not exist or is not a tarfile');
return Command::FAILURE;
}
@ -52,8 +52,9 @@ class ImportEmojis extends Command
foreach (new \RecursiveIteratorIterator($tar) as $entry) {
$this->line("Processing {$entry->getFilename()}");
if (!$entry->isFile() || !$this->isImage($entry) || !$this->isEmoji($entry->getPathname())) {
if (! $entry->isFile() || ! $this->isImage($entry) || ! $this->isEmoji($entry->getPathname())) {
$failed++;
continue;
}
@ -73,20 +74,21 @@ class ImportEmojis extends Command
$customEmoji = CustomEmoji::whereShortcode($shortcode)->first();
if ($customEmoji && !$this->option('overwrite')) {
if ($customEmoji && ! $this->option('overwrite')) {
$skipped++;
continue;
}
$emoji = $customEmoji ?? new CustomEmoji();
$emoji = $customEmoji ?? new CustomEmoji;
$emoji->shortcode = $shortcode;
$emoji->domain = config('pixelfed.domain.app');
$emoji->disabled = $this->option('disabled');
$emoji->save();
$fileName = $emoji->id . '.' . $extension;
$fileName = $emoji->id.'.'.$extension;
Storage::putFileAs('public/emoji', $entry->getPathname(), $fileName);
$emoji->media_path = 'emoji/' . $fileName;
$emoji->media_path = 'emoji/'.$fileName;
$emoji->save();
$imported++;
Cache::forget('pf:custom_emoji');
@ -96,7 +98,7 @@ class ImportEmojis extends Command
$this->line("Skipped: {$skipped}");
$this->line("Failed: {$failed}");
//delete file
// delete file
unlink(str_replace('.tar.gz', '.tar', $path));
return Command::SUCCESS;
@ -105,6 +107,7 @@ class ImportEmojis extends Command
private function isImage($file)
{
$image = getimagesize($file->getPathname());
return $image !== false;
}

@ -2,12 +2,11 @@
namespace App\Console\Commands;
use App\Models\ImportPost;
use App\User;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
use App\User;
use App\Models\ImportPost;
use App\Services\ImportService;
class ImportRemoveDeletedAccounts extends Command
{
@ -32,7 +31,7 @@ class ImportRemoveDeletedAccounts extends Command
*/
public function handle()
{
$skipMinId = Cache::remember(self::CACHE_KEY, 864000, function() {
$skipMinId = Cache::remember(self::CACHE_KEY, 864000, function () {
return 1;
});
@ -43,13 +42,13 @@ class ImportRemoveDeletedAccounts extends Command
->limit(500)
->pluck('id');
if(!$deletedIds || !$deletedIds->count()) {
if (! $deletedIds || ! $deletedIds->count()) {
return;
}
foreach($deletedIds as $did) {
if(Storage::exists('imports/' . $did)) {
Storage::deleteDirectory('imports/' . $did);
foreach ($deletedIds as $did) {
if (Storage::exists('imports/'.$did)) {
Storage::deleteDirectory('imports/'.$did);
}
ImportPost::where('user_id', $did)->delete();

@ -2,11 +2,9 @@
namespace App\Console\Commands;
use App\User;
use Illuminate\Console\Command;
use App\Models\ImportPost;
use Storage;
use App\Services\ImportService;
use App\User;
class ImportUploadCleanStorage extends Command
{
@ -31,10 +29,10 @@ class ImportUploadCleanStorage extends Command
{
$dirs = Storage::allDirectories('imports');
foreach($dirs as $dir) {
foreach ($dirs as $dir) {
$uid = last(explode('/', $dir));
$skip = User::whereNull('status')->find($uid);
if(!$skip) {
if (! $skip) {
Storage::deleteDirectory($dir);
}
}

@ -2,10 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\ImportPost;
use Storage;
use App\Services\ImportService;
use Illuminate\Console\Command;
class ImportUploadGarbageCollection extends Command
{
@ -28,17 +27,17 @@ class ImportUploadGarbageCollection extends Command
*/
public function handle()
{
if(!config('import.instagram.enabled')) {
if (! config('import.instagram.enabled')) {
return;
}
$ips = ImportPost::whereNull('status_id')->where('skip_missing_media', true)->take(100)->get();
if(!$ips->count()) {
if (! $ips->count()) {
return;
}
foreach($ips as $ip) {
foreach ($ips as $ip) {
$pid = $ip->profile_id;
$ip->delete();
ImportService::getPostCount($pid, true);

@ -2,9 +2,10 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\ImportPost;
use App\Jobs\ImportPipeline\ImportMediaToCloudPipeline;
use App\Models\ImportPost;
use Illuminate\Console\Command;
use function Laravel\Prompts\progress;
class ImportUploadMediaToCloudStorage extends Command
@ -28,11 +29,12 @@ class ImportUploadMediaToCloudStorage extends Command
*/
public function handle()
{
if(
if (
(bool) config('import.instagram.storage.cloud.enabled') === false ||
(bool) config_cache('pixelfed.cloud_storage') === false
) {
$this->error('Aborted. Cloud storage is not enabled for IG imports.');
return;
}
@ -44,7 +46,7 @@ class ImportUploadMediaToCloudStorage extends Command
$posts = ImportPost::whereUploadedToS3(false)->take($limit)->get();
foreach($posts as $post) {
foreach ($posts as $post) {
ImportMediaToCloudPipeline::dispatch($post)->onQueue('low');
$progress->advance();
}

@ -4,7 +4,7 @@ namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Redis;
use \PDO;
use PDO;
class Installer extends Command
{
@ -68,7 +68,7 @@ class Installer extends Command
$this->info(' Welcome to the Pixelfed Installer!');
$this->info(' ');
$this->info(' ');
$this->info('Pixelfed version: ' . config('pixelfed.version'));
$this->info('Pixelfed version: '.config('pixelfed.version'));
$this->line(' ');
$this->installerSteps();
}
@ -99,7 +99,7 @@ class Installer extends Command
{
if (file_exists(base_path('.env')) &&
filesize(base_path('.env')) !== 0 &&
!$this->option('dangerously-overwrite-env')
! $this->option('dangerously-overwrite-env')
) {
$this->line('');
$this->error('Existing .env File Found - Installation Aborted');
@ -113,7 +113,7 @@ class Installer extends Command
{
$this->line('');
$this->info('Creating .env if required');
if (!file_exists(app()->environmentFilePath())) {
if (! file_exists(app()->environmentFilePath())) {
copy(base_path('.env.example'), app()->environmentFilePath());
}
}
@ -148,10 +148,11 @@ class Installer extends Command
}
}
if (!empty($missing)) {
if (! empty($missing)) {
$continue = $this->choice('Some extensions are missing. Do you wish to continue?', ['yes', 'no'], 1);
if ($continue === 'no') {
$this->info('Exiting Installer.');
return 1;
}
}
@ -170,6 +171,7 @@ class Installer extends Command
$continue = $this->choice('Do you want to continue without FFmpeg?', ['yes', 'no'], 1);
if ($continue === 'no') {
$this->info('Exiting Installer. Please install FFmpeg and try again.');
return 1;
}
} else {
@ -212,8 +214,8 @@ class Installer extends Command
foreach ($paths as $path) {
if (is_writable($path) == false) {
$this->error("- Invalid permission found! Aborting installation.");
$this->error(" Please make the following path writeable by the web server:");
$this->error('- Invalid permission found! Aborting installation.');
$this->error(' Please make the following path writeable by the web server:');
$this->error(" $path");
exit;
} else {
@ -236,7 +238,7 @@ class Installer extends Command
{
$this->line('');
$this->info('Database Settings:');
$database = $this->choice('Select database driver', ['mysql', 'pgsql'], $this->option('db-driver') ?: 0);
$database_host = $this->ask('Select database host', $this->option('db-host') ?: '127.0.0.1');
$database_port_default = $database === 'mysql' ? 3306 : 5432;
@ -260,7 +262,7 @@ class Installer extends Command
$dbh = null; // Close connection
} catch (\PDOException $e) {
$this->error('Cannot connect to database, check your details and try again');
$this->error('Error: ' . $e->getMessage());
$this->error('Error: '.$e->getMessage());
exit;
}
$this->info('- Connected to DB Successfully');
@ -293,7 +295,7 @@ class Installer extends Command
}
} catch (\Exception $e) {
$this->error('Cannot connect to Redis, check your details and try again');
$this->error('Error: ' . $e->getMessage());
$this->error('Error: '.$e->getMessage());
exit;
}
}
@ -308,28 +310,31 @@ class Installer extends Command
while (empty($domain)) {
$domain = $this->ask('Site Domain [ex: pixelfed.com]', $this->option('domain') ?: null);
$domain = strtolower(trim($domain));
if (empty($domain)) {
$this->error('You must set the site domain');
continue;
}
if (str_starts_with($domain, 'http://') || str_starts_with($domain, 'https://')) {
$this->error('The site domain cannot start with http:// or https://, you must use the FQDN (eg: example.org)');
$domain = '';
continue;
}
// Better domain validation
if (!preg_match('/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/i', $domain)) {
if (! preg_match('/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/i', $domain)) {
$this->error('Invalid domain format. Please enter a valid domain (eg: example.org)');
$domain = '';
continue;
}
}
$this->updateEnvFile('APP_NAME', $name);
$this->updateEnvFile('APP_URL', 'https://' . $domain);
$this->updateEnvFile('APP_URL', 'https://'.$domain);
$this->updateEnvFile('APP_DOMAIN', $domain);
$this->updateEnvFile('ADMIN_DOMAIN', $domain);
$this->updateEnvFile('SESSION_DOMAIN', $domain);
@ -352,11 +357,11 @@ class Installer extends Command
{
$this->line('');
$this->info('Laravel Settings (Defaults are recommended):');
$session = $this->choice('Select session driver', ["database", "file", "cookie", "redis", "memcached", "array"], 0);
$cache = $this->choice('Select cache driver', ["redis", "apc", "array", "database", "file", "memcached"], 0);
$queue = $this->choice('Select queue driver', ["redis", "database", "sync", "beanstalkd", "sqs", "null"], 0);
$broadcast = $this->choice('Select broadcast driver', ["log", "redis", "pusher", "null"], 0);
$log = $this->choice('Select Log Channel', ["stack", "single", "daily", "stderr", "syslog", "null"], 0);
$session = $this->choice('Select session driver', ['database', 'file', 'cookie', 'redis', 'memcached', 'array'], 0);
$cache = $this->choice('Select cache driver', ['redis', 'apc', 'array', 'database', 'file', 'memcached'], 0);
$queue = $this->choice('Select queue driver', ['redis', 'database', 'sync', 'beanstalkd', 'sqs', 'null'], 0);
$broadcast = $this->choice('Select broadcast driver', ['log', 'redis', 'pusher', 'null'], 0);
$log = $this->choice('Select Log Channel', ['stack', 'single', 'daily', 'stderr', 'syslog', 'null'], 0);
$horizon = $this->ask('Set Horizon Prefix [ex: horizon-]', 'horizon-');
$this->updateEnvFile('SESSION_DRIVER', $session);
@ -371,15 +376,15 @@ class Installer extends Command
{
$this->line('');
$this->info('Instance Settings:');
$max_registration = '';
while (!is_numeric($max_registration) || $max_registration < 1) {
while (! is_numeric($max_registration) || $max_registration < 1) {
$max_registration = $this->ask('Set Maximum users on this instance', '1000');
if (!is_numeric($max_registration) || $max_registration < 1) {
if (! is_numeric($max_registration) || $max_registration < 1) {
$this->error('Please enter a valid number greater than 0');
}
}
$open_registration = $this->choice('Allow new registrations?', ['false', 'true'], 0);
$enforce_email_verification = $this->choice('Enforce email verification?', ['false', 'true'], 0);
$enable_mobile_apis = $this->choice('Enable mobile app/apis support?', ['false', 'true'], 1);
@ -396,36 +401,36 @@ class Installer extends Command
$this->line('');
$this->info('Media Settings:');
$optimize_media = $this->choice('Optimize media uploads? Requires jpegoptim and other dependencies!', ['false', 'true'], 1);
$image_quality = '';
while (!is_numeric($image_quality) || $image_quality < 1 || $image_quality > 100) {
while (! is_numeric($image_quality) || $image_quality < 1 || $image_quality > 100) {
$image_quality = $this->ask('Set image optimization quality between 1-100 (default: 80)', '80');
if (!is_numeric($image_quality) || $image_quality < 1 || $image_quality > 100) {
if (! is_numeric($image_quality) || $image_quality < 1 || $image_quality > 100) {
$this->error('Please enter a number between 1 and 100');
}
}
$this->info('Note: Max photo size cannot exceed `post_max_size` in php.ini.');
$max_photo_size = '';
while (!is_numeric($max_photo_size) || $max_photo_size < 1) {
while (! is_numeric($max_photo_size) || $max_photo_size < 1) {
$max_photo_size = $this->ask('Max photo upload size in kilobytes (default: 15000 = 15MB)', '15000');
if (!is_numeric($max_photo_size) || $max_photo_size < 1) {
if (! is_numeric($max_photo_size) || $max_photo_size < 1) {
$this->error('Please enter a valid number greater than 0');
}
}
$max_caption_length = '';
while (!is_numeric($max_caption_length) || $max_caption_length < 1 || $max_caption_length > 5000) {
while (! is_numeric($max_caption_length) || $max_caption_length < 1 || $max_caption_length > 5000) {
$max_caption_length = $this->ask('Max caption limit (1-5000, default: 500)', '500');
if (!is_numeric($max_caption_length) || $max_caption_length < 1 || $max_caption_length > 5000) {
if (! is_numeric($max_caption_length) || $max_caption_length < 1 || $max_caption_length > 5000) {
$this->error('Please enter a number between 1 and 5000');
}
}
$max_album_length = '';
while (!is_numeric($max_album_length) || $max_album_length < 1 || $max_album_length > 10) {
while (! is_numeric($max_album_length) || $max_album_length < 1 || $max_album_length > 10) {
$max_album_length = $this->ask('Max photos per album (1-10, default: 4)', '4');
if (!is_numeric($max_album_length) || $max_album_length < 1 || $max_album_length > 10) {
if (! is_numeric($max_album_length) || $max_album_length < 1 || $max_album_length > 10) {
$this->error('Please enter a number between 1 and 10');
}
}
@ -445,24 +450,24 @@ class Installer extends Command
if ($confirm === 'Yes') {
sleep(3);
// Clear any cached config
$this->call('config:clear');
// Force reload environment variables
$app = app();
$app->bootstrapWith([
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
]);
// Purge database connections to force reconnect with new credentials
$app->forgetInstance('db');
$app->forgetInstance('db.connection');
\Illuminate\Support\Facades\DB::purge();
// Rebuild config cache
$this->call('config:cache');
$this->line('');
$this->info('Migrating DB:');
$this->call('migrate', ['--force' => true]);
@ -472,12 +477,13 @@ class Installer extends Command
protected function setupPrep()
{
if (!$this->migrationsRan) {
if (! $this->migrationsRan) {
$this->warn('Skipping setup tasks because migrations were not run.');
$this->warn('You can run these commands manually later:');
$this->warn(' php artisan import:cities');
$this->warn(' php artisan instance:actor');
$this->warn(' php artisan passport:keys');
return;
}
@ -501,9 +507,9 @@ class Installer extends Command
protected function validateEnv()
{
$this->checkEnvKeys('APP_KEY', "key:generate failed?");
$this->checkEnvKeys('APP_ENV', "APP_ENV value should be production");
$this->checkEnvKeys('APP_DEBUG', "APP_DEBUG value should be false");
$this->checkEnvKeys('APP_KEY', 'key:generate failed?');
$this->checkEnvKeys('APP_ENV', 'APP_ENV value should be production');
$this->checkEnvKeys('APP_DEBUG', 'APP_DEBUG value should be false');
}
protected function resetArtisanCache()
@ -515,9 +521,9 @@ class Installer extends Command
$this->line('');
}
#####
# Installer Functions
#####
// ####
// Installer Functions
// ####
protected function checkEnvKeys($key, $error)
{
@ -534,7 +540,7 @@ class Installer extends Command
{
$envPath = app()->environmentFilePath();
$payload = file_get_contents($envPath);
// Escape special characters for .env format
$value = str_replace(['\\', '"', "\n", "\r"], ['\\\\', '\\"', '\\n', '\\r'], $value);
@ -542,7 +548,7 @@ class Installer extends Command
$payload = str_replace("{$key}={$existing}", "{$key}=\"{$value}\"", $payload);
$this->storeEnv($payload);
} else {
$payload = $payload . "\n{$key}=\"{$value}\"\n";
$payload = $payload."\n{$key}=\"{$value}\"\n";
$this->storeEnv($payload);
}
}
@ -553,27 +559,28 @@ class Installer extends Command
if ($matches && count($matches)) {
return substr($matches[0], strlen($needle) + 1);
}
return false;
}
protected function storeEnv($payload)
{
$envPath = app()->environmentFilePath();
$tempPath = $envPath . '.tmp';
$tempPath = $envPath.'.tmp';
// Write to temp file first
$file = fopen($tempPath, 'w');
if ($file === false) {
throw new \RuntimeException("Cannot write to {$tempPath}");
}
fwrite($file, $payload);
fclose($file);
// Atomic rename
if (!rename($tempPath, $envPath)) {
if (! rename($tempPath, $envPath)) {
@unlink($tempPath);
throw new \RuntimeException("Cannot update .env file");
throw new \RuntimeException('Cannot update .env file');
}
}
}

@ -2,15 +2,15 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Instance;
use App\Profile;
use App\Services\InstanceService;
use App\Jobs\InstancePipeline\FetchNodeinfoPipeline;
use function Laravel\Prompts\select;
use App\Services\InstanceService;
use Illuminate\Console\Command;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\progress;
use function Laravel\Prompts\search;
use function Laravel\Prompts\select;
use function Laravel\Prompts\table;
class InstanceManager extends Command
@ -47,7 +47,7 @@ class InstanceManager extends Command
],
);
switch($action) {
switch ($action) {
case 'Recalculate Stats':
return $this->recalculateStats();
@ -74,8 +74,8 @@ class InstanceManager extends Command
protected function recalculateStats()
{
$instanceCount = Instance::count();
$confirmed = confirm('Do you want to recalculate stats for all ' . $instanceCount . ' instances?');
if(!$confirmed) {
$confirmed = confirm('Do you want to recalculate stats for all '.$instanceCount.' instances?');
if (! $confirmed) {
$this->error('Aborting...');
exit;
}
@ -102,7 +102,7 @@ class InstanceManager extends Command
);
$instance = Instance::find($id);
if(!$instance) {
if (! $instance) {
$this->error('Oops, an error occured');
exit;
}
@ -112,7 +112,7 @@ class InstanceManager extends Command
$instance->domain,
number_format($instance->status_count),
number_format($instance->user_count),
]
],
];
table(
['Domain', 'Status Count', 'User Count'],
@ -120,7 +120,7 @@ class InstanceManager extends Command
);
$confirmed = confirm('Are you sure you want to unlist this instance?');
if(!$confirmed) {
if (! $confirmed) {
$this->error('Aborting instance unlisting');
exit;
}
@ -128,7 +128,7 @@ class InstanceManager extends Command
$instance->unlisted = true;
$instance->save();
InstanceService::refresh();
$this->info('Successfully unlisted ' . $instance->domain . '!');
$this->info('Successfully unlisted '.$instance->domain.'!');
exit;
}
@ -142,7 +142,7 @@ class InstanceManager extends Command
);
$instance = Instance::find($id);
if(!$instance) {
if (! $instance) {
$this->error('Oops, an error occured');
exit;
}
@ -152,7 +152,7 @@ class InstanceManager extends Command
$instance->domain,
number_format($instance->status_count),
number_format($instance->user_count),
]
],
];
table(
['Domain', 'Status Count', 'User Count'],
@ -160,7 +160,7 @@ class InstanceManager extends Command
);
$confirmed = confirm('Are you sure you want to re-list this instance?');
if(!$confirmed) {
if (! $confirmed) {
$this->error('Aborting instance re-listing');
exit;
}
@ -168,7 +168,7 @@ class InstanceManager extends Command
$instance->unlisted = false;
$instance->save();
InstanceService::refresh();
$this->info('Successfully re-listed ' . $instance->domain . '!');
$this->info('Successfully re-listed '.$instance->domain.'!');
exit;
}
@ -182,7 +182,7 @@ class InstanceManager extends Command
);
$instance = Instance::find($id);
if(!$instance) {
if (! $instance) {
$this->error('Oops, an error occured');
exit;
}
@ -192,7 +192,7 @@ class InstanceManager extends Command
$instance->domain,
number_format($instance->status_count),
number_format($instance->user_count),
]
],
];
table(
['Domain', 'Status Count', 'User Count'],
@ -200,7 +200,7 @@ class InstanceManager extends Command
);
$confirmed = confirm('Are you sure you want to ban this instance?');
if(!$confirmed) {
if (! $confirmed) {
$this->error('Aborting instance ban');
exit;
}
@ -208,7 +208,7 @@ class InstanceManager extends Command
$instance->banned = true;
$instance->save();
InstanceService::refresh();
$this->info('Successfully banned ' . $instance->domain . '!');
$this->info('Successfully banned '.$instance->domain.'!');
exit;
}
@ -222,7 +222,7 @@ class InstanceManager extends Command
);
$instance = Instance::find($id);
if(!$instance) {
if (! $instance) {
$this->error('Oops, an error occured');
exit;
}
@ -232,7 +232,7 @@ class InstanceManager extends Command
$instance->domain,
number_format($instance->status_count),
number_format($instance->user_count),
]
],
];
table(
['Domain', 'Status Count', 'User Count'],
@ -240,7 +240,7 @@ class InstanceManager extends Command
);
$confirmed = confirm('Are you sure you want to unban this instance?');
if(!$confirmed) {
if (! $confirmed) {
$this->error('Aborting instance unban');
exit;
}
@ -248,7 +248,7 @@ class InstanceManager extends Command
$instance->banned = false;
$instance->save();
InstanceService::refresh();
$this->info('Successfully un-banned ' . $instance->domain . '!');
$this->info('Successfully un-banned '.$instance->domain.'!');
exit;
}
@ -256,7 +256,7 @@ class InstanceManager extends Command
{
$data = Instance::whereBanned(true)
->get(['domain', 'user_count', 'status_count'])
->map(function($d) {
->map(function ($d) {
return [
'domain' => $d->domain,
'user_count' => number_format($d->user_count),
@ -274,12 +274,12 @@ class InstanceManager extends Command
{
$data = Instance::whereUnlisted(true)
->get(['domain', 'user_count', 'status_count', 'banned'])
->map(function($d) {
->map(function ($d) {
return [
'domain' => $d->domain,
'user_count' => number_format($d->user_count),
'status_count' => number_format($d->status_count),
'banned' => $d->banned ? '✅' : null
'banned' => $d->banned ? '✅' : null,
];
})
->toArray();

@ -2,9 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Util\Media\Filter;
use App\Media;
use App\Util\Media\Filter;
use Illuminate\Console\Command;
class MediaFix extends Command
{
@ -39,7 +39,7 @@ class MediaFix extends Command
*/
public function handle()
{
if(!version_compare(config('pixelfed.version'),'0.10.8','ge')) {
if (! version_compare(config('pixelfed.version'), '0.10.8', 'ge')) {
$this->error('Please update to version 0.10.8 or newer.');
exit;
}
@ -47,15 +47,15 @@ class MediaFix extends Command
$classes = Filter::classes();
Media::whereNotNull('filter_class')
->chunk(50, function($filters) use($classes) {
foreach($filters as $filter) {
->chunk(50, function ($filters) use ($classes) {
foreach ($filters as $filter) {
$match = $filter->filter_class ? in_array($filter->filter_class, $classes) : true;
if(!$match) {
if (! $match) {
$filter->filter_class = null;
$filter->filter_name = null;
$filter->save();
}
}
});
});
}
}

@ -2,57 +2,57 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\{Media, Status};
use App\Media;
use App\Services\MediaStorageService;
use Illuminate\Console\Command;
class MediaGarbageCollector extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'media:gc';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Delete media uploads not attached to any active statuses';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$limit = 500;
$gc = Media::whereNull('status_id')
->where('created_at', '<', now()->subHours(2)->toDateTimeString())
->take($limit)
->get();
$bar = $this->output->createProgressBar($gc->count());
$bar->start();
foreach($gc as $media) {
MediaStorageService::delete($media, true);
$bar->advance();
}
$bar->finish();
$this->line('');
}
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'media:gc';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Delete media uploads not attached to any active statuses';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$limit = 500;
$gc = Media::whereNull('status_id')
->where('created_at', '<', now()->subHours(2)->toDateTimeString())
->take($limit)
->get();
$bar = $this->output->createProgressBar($gc->count());
$bar->start();
foreach ($gc as $media) {
MediaStorageService::delete($media, true);
$bar->advance();
}
$bar->finish();
$this->line('');
}
}

@ -2,58 +2,59 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Media;
use App\Status;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use App\Services\MediaService;
use App\Services\StatusService;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class MediaS3GarbageCollector extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'media:s3gc {--limit=200} {--huge} {--log-errors}';
/**
* The console command description.
*
* @var string
*/
* The console command description.
*
* @var string
*/
protected $description = 'Delete (local) media uploads that exist on S3';
/**
* Create a new command instance.
*
* @return void
*/
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
* Execute the console command.
*
* @return int
*/
public function handle()
{
$enabled = (bool) config_cache('pixelfed.cloud_storage');
if(!$enabled) {
if (! $enabled) {
$this->error('Cloud storage not enabled. Exiting...');
return;
}
$deleteEnabled = config('media.delete_local_after_cloud');
if(!$deleteEnabled) {
if (! $deleteEnabled) {
$this->error('Delete local storage after cloud upload is not enabled');
return;
}
@ -61,17 +62,18 @@ class MediaS3GarbageCollector extends Command
$hugeMode = $this->option('huge');
$log = $this->option('log-errors');
if($limit > 2000 && !$hugeMode) {
if ($limit > 2000 && ! $hugeMode) {
$this->error('Limit exceeded, please use a limit under 2000 or run again with the --huge flag');
return;
}
$minId = Media::orderByDesc('id')->where('created_at', '<', now()->subHours(12))->first();
if(!$minId) {
return;
if (! $minId) {
return;
} else {
$minId = $minId->id;
$minId = $minId->id;
}
return $hugeMode ?
@ -95,19 +97,19 @@ class MediaS3GarbageCollector extends Command
$cloudDisk = Storage::disk(config('filesystems.cloud'));
$localDisk = Storage::disk('local');
foreach($gc as $media) {
foreach ($gc as $media) {
try {
if(
if (
$cloudDisk->exists($media->media_path)
) {
if( $localDisk->exists($media->media_path)) {
if ($localDisk->exists($media->media_path)) {
$localDisk->delete($media->media_path);
$media->version = 4;
$media->save();
$totalSize = $totalSize + $media->size;
MediaService::del($media->status_id);
StatusService::del($media->status_id, false);
if($localDisk->exists($media->thumbnail_path)) {
if ($localDisk->exists($media->thumbnail_path)) {
$localDisk->delete($media->thumbnail_path);
}
} else {
@ -115,28 +117,32 @@ class MediaS3GarbageCollector extends Command
$media->save();
}
} else {
if($log) {
if ($log) {
Log::channel('media')->info('[GC] Local media not properly persisted to cloud storage', ['media_id' => $media->id]);
}
}
$bar->advance();
} catch (FileNotFoundException $e) {
$bar->advance();
continue;
} catch (NotFoundHttpException $e) {
$bar->advance();
continue;
} catch (\Exception $e) {
$bar->advance();
continue;
}
}
$bar->finish();
$this->line(' ');
$this->info('Finished!');
if($totalSize) {
$this->info('Cleared ' . $totalSize . ' bytes of media from local disk!');
if ($totalSize) {
$this->info('Cleared '.$totalSize.' bytes of media from local disk!');
}
return 0;
}
@ -152,17 +158,17 @@ class MediaS3GarbageCollector extends Command
->whereNotNull(['status_id', 'cdn_url', 'replicated_at'])
->whereNot('version', '4')
->where('id', '<', $minId)
->chunk(50, function($medias) use($cloudDisk, $localDisk, $bar, $log) {
foreach($medias as $media) {
->chunk(50, function ($medias) use ($cloudDisk, $localDisk, $bar, $log) {
foreach ($medias as $media) {
try {
if($cloudDisk->exists($media->media_path)) {
if( $localDisk->exists($media->media_path)) {
if ($cloudDisk->exists($media->media_path)) {
if ($localDisk->exists($media->media_path)) {
$localDisk->delete($media->media_path);
$media->version = 4;
$media->save();
MediaService::del($media->status_id);
StatusService::del($media->status_id, false);
if($localDisk->exists($media->thumbnail_path)) {
if ($localDisk->exists($media->thumbnail_path)) {
$localDisk->delete($media->thumbnail_path);
}
} else {
@ -170,23 +176,26 @@ class MediaS3GarbageCollector extends Command
$media->save();
}
} else {
if($log) {
if ($log) {
Log::channel('media')->info('[GC] Local media not properly persisted to cloud storage', ['media_id' => $media->id]);
}
}
$bar->advance();
} catch (FileNotFoundException $e) {
$bar->advance();
continue;
} catch (NotFoundHttpException $e) {
$bar->advance();
continue;
} catch (\Exception $e) {
$bar->advance();
continue;
}
}
});
});
$bar->finish();
$this->line(' ');

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Jobs\InternalPipeline\NotificationEpochUpdatePipeline;
use Illuminate\Console\Command;
class NotificationEpochUpdate extends Command
{

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\EmailVerification;
use Illuminate\Console\Command;
class PasswordResetGC extends Command
{
@ -39,8 +39,8 @@ class PasswordResetGC extends Command
public function handle()
{
EmailVerification::where('created_at', '<', now()->subMinutes(1441))
->chunk(50, function($emails) {
foreach($emails as $em) {
->chunk(50, function ($emails) {
foreach ($emails as $em) {
$em->delete();
}
});

@ -3,7 +3,6 @@
namespace App\Console\Commands;
use App\Services\NotificationAppGatewayService;
use App\Services\PushNotificationService;
use Illuminate\Console\Command;
use function Laravel\Prompts\select;
@ -51,6 +50,7 @@ class PushGatewayRefresh extends Command
$recheck = NotificationAppGatewayService::forceSupportRecheck();
if ($recheck) {
$this->info('Success! Push Notifications are now active!');
return;
} else {
$this->error('Error, please ensure you have a valid API key.');

@ -2,12 +2,12 @@
namespace App\Console\Commands;
use App\User;
use App\Profile;
use App\User;
use Illuminate\Console\Command;
use function Laravel\Prompts\search;
use function Laravel\Prompts\text;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\search;
class ReclaimUsername extends Command
{
@ -32,20 +32,22 @@ class ReclaimUsername extends Command
{
$username = search(
label: 'What username would you like to reclaim?',
options: fn (string $search) => strlen($search) > 0 ? $this->getUsernameOptions($search) : [],
options: fn (string $search) => strlen($search) > 0 ? $this->getUsernameOptions($search) : [],
required: true
);
$user = User::whereUsername($username)->withTrashed()->first();
$profile = Profile::whereUsername($username)->withTrashed()->first();
if (!$user && !$profile) {
if (! $user && ! $profile) {
$this->error("No user or profile found with username: {$username}");
return Command::FAILURE;
}
if ($user->delete_after === null || $user->status !== 'deleted') {
$this->error("Cannot reclaim an active account: {$username}");
return Command::FAILURE;
}
@ -54,8 +56,9 @@ class ReclaimUsername extends Command
default: false
);
if (!$confirm) {
if (! $confirm) {
$this->info('Operation cancelled.');
return Command::SUCCESS;
}
@ -70,6 +73,7 @@ class ReclaimUsername extends Command
}
$this->info('Username reclaimed successfully!');
return Command::SUCCESS;
}

@ -2,9 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Media;
use DB;
use Illuminate\Console\Command;
class RegenerateThumbnails extends Command
{
@ -39,10 +39,10 @@ class RegenerateThumbnails extends Command
*/
public function handle()
{
DB::transaction(function() {
DB::transaction(function () {
Media::whereIn('mime', ['image/jpeg', 'image/png', 'image/jpg'])
->chunk(50, function($medias) {
foreach($medias as $media) {
->chunk(50, function ($medias) {
foreach ($medias as $media) {
\App\Jobs\ImageOptimizePipeline\ImageThumbnail::dispatch($media);
}
});

@ -5,8 +5,8 @@ namespace App\Console\Commands;
use App\Follower;
use App\Jobs\FollowPipeline\FollowPipeline;
use App\Profile;
use Illuminate\Console\Command;
use Exception;
use Illuminate\Console\Command;
class SeedFollows extends Command
{
@ -48,15 +48,15 @@ class SeedFollows extends Command
$actor = Profile::whereDomain(false)->inRandomOrder()->firstOrFail();
$target = Profile::whereDomain(false)->inRandomOrder()->firstOrFail();
if($actor->id == $target->id) {
if ($actor->id == $target->id) {
continue;
}
$follow = Follower::firstOrCreate([
'profile_id' => $actor->id,
'following_id' => $target->id
'profile_id' => $actor->id,
'following_id' => $target->id,
]);
if($follow->wasRecentlyCreated == true) {
if ($follow->wasRecentlyCreated == true) {
FollowPipeline::dispatch($follow);
}
} catch (Exception $e) {

@ -2,12 +2,12 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Storage;
use App\Instance;
use App\Profile;
use App\User;
use App\Instance;
use App\Util\ActivityPub\Helpers;
use Illuminate\Console\Command;
use Storage;
use Symfony\Component\HttpKernel\Exception\HttpException;
class SendUpdateActor extends Command
@ -35,33 +35,35 @@ class SendUpdateActor extends Command
{
$totalUserCount = Profile::whereNotNull('user_id')->count();
$totalInstanceCount = Instance::count();
$this->info('Found ' . $totalUserCount . ' local accounts and ' . $totalInstanceCount . ' remote instances');
$this->info('Found '.$totalUserCount.' local accounts and '.$totalInstanceCount.' remote instances');
$task = $this->choice(
'What do you want to do?',
[
'View top instances',
'Send updates to an instance'
'Send updates to an instance',
],
0
);
if($task === 'View top instances') {
if ($task === 'View top instances') {
$this->table(
['domain', 'user_count', 'last_synced'],
Instance::orderByDesc('user_count')->take(20)->get(['domain', 'user_count', 'actors_last_synced_at'])->toArray()
);
return Command::SUCCESS;
} else {
$domain = $this->anticipate('Enter the instance domain', function ($input) {
return Instance::where('domain', 'like', '%' . $input . '%')->pluck('domain')->toArray();
return Instance::where('domain', 'like', '%'.$input.'%')->pluck('domain')->toArray();
});
if(!$this->confirm('Are you sure you want to send actor updates to ' . $domain . '?')) {
if (! $this->confirm('Are you sure you want to send actor updates to '.$domain.'?')) {
return;
}
if($cur = Instance::whereDomain($domain)->whereNotNull('actors_last_synced_at')->first()) {
if(!$this->option('force')) {
$this->error('ERROR: Cannot re-sync this instance, it was already synced on ' . $cur->actors_last_synced_at);
if ($cur = Instance::whereDomain($domain)->whereNotNull('actors_last_synced_at')->first()) {
if (! $this->option('force')) {
$this->error('ERROR: Cannot re-sync this instance, it was already synced on '.$cur->actors_last_synced_at);
return;
}
}
@ -69,25 +71,27 @@ class SendUpdateActor extends Command
$this->line(' ');
$this->error('Keep this window open during this process or it will not complete!');
$sharedInbox = Profile::whereDomain($domain)->whereNotNull('sharedInbox')->first();
if(!$sharedInbox) {
$this->error('ERROR: Cannot find the sharedInbox of ' . $domain);
if (! $sharedInbox) {
$this->error('ERROR: Cannot find the sharedInbox of '.$domain);
return;
}
$url = $sharedInbox->sharedInbox;
$this->line(' ');
$this->info('Found sharedInbox: ' . $url);
$this->info('Found sharedInbox: '.$url);
$bar = $this->output->createProgressBar($totalUserCount);
$bar->start();
$startCache = $this->getStorageCache($domain);
User::whereNull('status')->when($startCache, function($query, $startCache) use($bar) {
User::whereNull('status')->when($startCache, function ($query, $startCache) use ($bar) {
$bar->advance($startCache);
return $query->where('id', '>', $startCache);
})->chunk(50, function($users) use($bar, $url, $domain) {
foreach($users as $user) {
})->chunk(50, function ($users) use ($bar, $url, $domain) {
foreach ($users as $user) {
$this->updateStorageCache($domain, $user->id);
$profile = Profile::find($user->profile_id);
if(!$profile) {
if (! $profile) {
continue;
}
$body = $this->updateObject($profile);
@ -105,6 +109,7 @@ class SendUpdateActor extends Command
$instance->actors_last_synced_at = now();
$instance->save();
$this->info('Finished!');
return Command::SUCCESS;
}
@ -121,61 +126,63 @@ class SendUpdateActor extends Command
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
],
],
'id' => $profile->permalink('#updates/' . time()),
'id' => $profile->permalink('#updates/'.time()),
'actor' => $profile->permalink(),
'type' => 'Update',
'object' => $this->actorObject($profile)
'object' => $this->actorObject($profile),
];
}
protected function touchStorageCache($domain)
{
$path = 'actor-update-cache/' . $domain;
if(!Storage::exists($path)) {
Storage::put($path, "");
$path = 'actor-update-cache/'.$domain;
if (! Storage::exists($path)) {
Storage::put($path, '');
}
}
protected function getStorageCache($domain)
{
$path = 'actor-update-cache/' . $domain;
$path = 'actor-update-cache/'.$domain;
return Storage::get($path);
}
protected function updateStorageCache($domain, $value)
{
$path = 'actor-update-cache/' . $domain;
$path = 'actor-update-cache/'.$domain;
Storage::put($path, $value);
}
protected function actorObject($profile)
{
$permalink = $profile->permalink();
return [
'id' => $permalink,
'type' => 'Person',
'following' => $permalink . '/following',
'followers' => $permalink . '/followers',
'inbox' => $permalink . '/inbox',
'outbox' => $permalink . '/outbox',
'preferredUsername' => $profile->username,
'name' => $profile->name,
'summary' => $profile->bio,
'url' => $profile->url(),
'id' => $permalink,
'type' => 'Person',
'following' => $permalink.'/following',
'followers' => $permalink.'/followers',
'inbox' => $permalink.'/inbox',
'outbox' => $permalink.'/outbox',
'preferredUsername' => $profile->username,
'name' => $profile->name,
'summary' => $profile->bio,
'url' => $profile->url(),
'manuallyApprovesFollowers' => (bool) $profile->is_private,
'publicKey' => [
'id' => $permalink . '#main-key',
'owner' => $permalink,
'id' => $permalink.'#main-key',
'owner' => $permalink,
'publicKeyPem' => $profile->public_key,
],
'icon' => [
'type' => 'Image',
'type' => 'Image',
'mediaType' => 'image/jpeg',
'url' => $profile->avatarUrl(),
'url' => $profile->avatarUrl(),
],
'endpoints' => [
'sharedInbox' => config('app.url') . '/f/inbox'
]
'sharedInbox' => config('app.url').'/f/inbox',
],
];
}
}

@ -2,9 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\Internal\SoftwareUpdateService;
use Cache;
use Illuminate\Console\Command;
class SoftwareUpdateRefresh extends Command
{
@ -29,7 +29,7 @@ class SoftwareUpdateRefresh extends Command
{
$key = SoftwareUpdateService::cacheKey();
Cache::forget($key);
Cache::remember($key, 1209600, function() {
Cache::remember($key, 1209600, function () {
return SoftwareUpdateService::fetchLatest();
});
$this->info('Succesfully updated software versions!');

@ -2,10 +2,10 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Jobs\StatusPipeline\StatusDelete;
use App\Status;
use DB;
use App\Jobs\StatusPipeline\StatusDelete;
use Illuminate\Console\Command;
class StatusDedupe extends Command
{
@ -41,8 +41,9 @@ class StatusDedupe extends Command
public function handle()
{
if(config('database.default') == 'pgsql') {
if (config('database.default') == 'pgsql') {
$this->info('This command is not compatible with Postgres, we are working on a fix.');
return;
}
DB::table('statuses')
@ -52,13 +53,13 @@ class StatusDedupe extends Command
->groupBy('uri')
->orderBy('created_at')
->having('occurences', '>', 1)
->chunk(50, function($statuses) {
foreach($statuses as $status) {
->chunk(50, function ($statuses) {
foreach ($statuses as $status) {
$this->info("Found duplicate: $status->uri");
Status::whereUri($status->uri)
->where('id', '!=', $status->id)
->get()
->map(function($status) {
->map(function ($status) {
$this->info("Deleting Duplicate ID: $status->id");
StatusDelete::dispatch($status);
});

@ -2,83 +2,82 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Storage;
use App\Story;
use App\StoryView;
use App\Jobs\StoryPipeline\StoryExpire;
use App\Jobs\StoryPipeline\StoryRotateMedia;
use App\Services\StoryService;
use App\Story;
use Illuminate\Console\Command;
class StoryGC extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'story:gc';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'story:gc';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Clear expired Stories';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* The console command description.
*
* @var string
*/
protected $description = 'Clear expired Stories';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->archiveExpiredStories();
$this->rotateMedia();
}
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
protected function archiveExpiredStories()
{
$stories = Story::whereActive(true)
->where('expires_at', '<', now())
->get();
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$this->archiveExpiredStories();
$this->rotateMedia();
}
foreach ($stories as $story) {
StoryExpire::dispatch($story)->onQueue('story');
}
}
protected function archiveExpiredStories()
{
$stories = Story::whereActive(true)
->where('expires_at', '<', now())
->get();
protected function rotateMedia()
{
$queue = StoryService::rotateQueue();
foreach($stories as $story) {
StoryExpire::dispatch($story)->onQueue('story');
}
}
if (! $queue || count($queue) == 0) {
return;
}
protected function rotateMedia()
{
$queue = StoryService::rotateQueue();
collect($queue)
->each(function ($id) {
$story = StoryService::getById($id);
if (! $story) {
StoryService::removeRotateQueue($id);
if(!$queue || count($queue) == 0) {
return;
}
return;
}
if ($story->created_at->gt(now()->subMinutes(20))) {
return;
}
StoryRotateMedia::dispatch($story)->onQueue('story');
StoryService::removeRotateQueue($id);
collect($queue)
->each(function($id) {
$story = StoryService::getById($id);
if(!$story) {
StoryService::removeRotateQueue($id);
return;
}
if($story->created_at->gt(now()->subMinutes(20))) {
return;
}
StoryRotateMedia::dispatch($story)->onQueue('story');
StoryService::removeRotateQueue($id);
return;
});
}
});
}
}

@ -2,9 +2,7 @@
namespace App\Console\Commands;
use Schema;
use Illuminate\Console\Command;
use App\Jobs\ImageOptimizePipeline\ImageThumbnail;
class UpdateCommand extends Command
{
@ -44,43 +42,14 @@ class UpdateCommand extends Command
public function update()
{
$v = $this->getVersionFile();
if($v && isset($v['commit_hash']) && $v['commit_hash'] == exec('git rev-parse HEAD') && \App\StatusHashtag::whereNull('profile_id')->count() == 0) {
$this->info('No updates found.');
return;
}
$bar = $this->output->createProgressBar(\App\StatusHashtag::whereNull('profile_id')->count());
\App\StatusHashtag::whereNull('profile_id')->with('status')->chunk(50, function($sh) use ($bar) {
foreach($sh as $status_hashtag) {
if(!$status_hashtag->status) {
$status_hashtag->delete();
} else {
$status_hashtag->profile_id = $status_hashtag->status->profile_id;
$status_hashtag->save();
}
$bar->advance();
}
});
$this->updateVersionFile();
$bar->finish();
}
protected function getVersionFile()
{
$path = storage_path('app/version.json');
return is_file($path) ?
json_decode(file_get_contents($path), true) :
false;
}
protected function updateVersionFile() {
$path = storage_path('app/version.json');
$contents = [
'commit_hash' => exec('git rev-parse HEAD'),
'version' => config('pixelfed.version'),
'timestamp' => date('c')
];
$json = json_encode($contents, JSON_PRETTY_PRINT);
file_put_contents($path, $json);
$this->info('Starting update...');
$this->line(' ');
$this->callSilent('config:cache');
$this->callSilent('route:cache');
$this->callSilent('migrate', [
'--force' => true,
]);
$this->callSilent('horizon:terminate');
$this->info('Completed update!');
}
}

@ -2,9 +2,9 @@
namespace App\Console\Commands;
use App\User;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
use App\User;
class UserAdmin extends Command implements PromptsForMissingInput
{
@ -45,19 +45,19 @@ class UserAdmin extends Command implements PromptsForMissingInput
$user = User::whereUsername($id)->first();
if(!$user) {
if (! $user) {
$this->error('Could not find any user with that username or id.');
exit;
}
$this->info('Found username: ' . $user->username);
$this->info('Found username: '.$user->username);
$state = $user->is_admin ? 'Remove admin privileges from this user?' : 'Add admin privileges to this user?';
$confirmed = $this->confirm($state);
if(!$confirmed) {
if (! $confirmed) {
exit;
}
$user->is_admin = !$user->is_admin;
$user->is_admin = ! $user->is_admin;
$user->save();
$this->info('Successfully changed permissions!');
}

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\User;
use Illuminate\Console\Command;
class UserCreate extends Command
{
@ -42,7 +42,7 @@ class UserCreate extends Command
$o = $this->options();
if( $o['name'] &&
if ($o['name'] &&
$o['username'] &&
$o['email'] &&
$o['password']
@ -57,6 +57,7 @@ class UserCreate extends Command
$user->save();
$this->info('Successfully created user!');
return;
}
@ -64,14 +65,14 @@ class UserCreate extends Command
$username = $this->ask('Username');
if(User::whereUsername($username)->exists()) {
if (User::whereUsername($username)->exists()) {
$this->error('Username already in use, please try again...');
exit;
}
$email = $this->ask('Email');
if(User::whereEmail($email)->exists()) {
if (User::whereEmail($email)->exists()) {
$this->error('Email already in use, please try again...');
exit;
}
@ -79,23 +80,23 @@ class UserCreate extends Command
$password = $this->secret('Password');
$confirm = $this->secret('Confirm Password');
if($password !== $confirm) {
if ($password !== $confirm) {
$this->error('Password mismatch, please try again...');
exit;
}
if (strlen($password) < 6) {
$this->error('Must be 6 or more characters, please try again...');
exit;
}
$is_admin = $this->confirm('Make this user an admin?');
$confirm_email = $this->confirm('Manually verify email address?');
if($this->confirm('Are you sure you want to create this user?') &&
if ($this->confirm('Are you sure you want to create this user?') &&
$username &&
$name &&
$email &&
$name &&
$email &&
$password
) {
$user = new User;

@ -2,11 +2,18 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\User;
use App\Jobs\DeletePipeline\DeleteAccountPipeline;
use App\Profile;
use App\Services\AccountService;
use App\User;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
class UserDelete extends Command
use function Laravel\Prompts\select;
use function Laravel\Prompts\table;
use function Laravel\Prompts\text;
class UserDelete extends Command implements PromptsForMissingInput
{
/**
* The name and signature of the console command.
@ -32,6 +39,18 @@ class UserDelete extends Command
parent::__construct();
}
/**
* Prompt for missing input arguments using the returned questions.
*
* @return array
*/
protected function promptForMissingArgumentsUsing()
{
return [
'id' => 'Which user ID or username should be deleted?',
];
}
/**
* Execute the console command.
*
@ -42,39 +61,82 @@ class UserDelete extends Command
$id = $this->argument('id');
$force = $this->option('force');
if(ctype_digit($id) == true) {
$user = Profile::where('username', 'like', '%'.$id.'%')->orWhere('user_id', $id)->orWhere('id', $id)->orderByDesc('followers_count')->get();
if (! $user || ! $user->count()) {
$this->error('Invalid user id or username');
return;
}
$user = select(
'Select the account',
$user->map(function ($u) {
return $u->username;
})
);
$user = Profile::whereUsername($user)->first();
if (! $user) {
$this->error('Invalid id or username');
return;
}
$this->info($user->username);
return;
if (ctype_digit($id) == true) {
$user = User::find($id);
} else {
$user = User::whereUsername($id)->first();
}
if(!$user) {
if (! $user) {
$this->error('Could not find any user with that username or id.');
exit;
}
if($user->status == 'deleted' && $force == false) {
if ($user->status == 'deleted' && $force == false) {
$this->error('Account has already been deleted.');
return;
}
if($user->is_admin == true) {
if ($user->is_admin == true) {
$this->error('Cannot delete an admin account from CLI.');
exit;
}
if(!$this->confirm('Are you sure you want to delete this account?')) {
$account = AccountService::get($user->profile_id);
$data = [
'Username' => $account['username'],
'Statuses' => $account['statuses_count'],
'Followers' => $account['followers_count'],
'Following' => $account['following_count'],
'Joined' => now()->parse($account['created_at'])->format('M Y'),
];
table(
['Username', 'Statuses', 'Followers', 'Following', 'Joined'],
[
$data,
]
);
if (! $this->confirm('Are you sure you want to delete this account?')) {
exit;
}
$confirmation = $this->ask('Enter the username to confirm deletion');
$confirmation = text('Enter the username to confirm deletion');
if($confirmation !== $user->username) {
if ($confirmation != $user->username) {
$this->error('Username does not match, exiting...');
exit;
}
if($user->status !== 'deleted') {
return;
if ($user->status !== 'deleted') {
$profile = $user->profile;
$profile->status = $user->status = 'deleted';
$profile->save();

@ -2,9 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\EmailVerification;
use App\User;
use Illuminate\Console\Command;
class UserRegistrationMagicLink extends Command
{
@ -31,45 +31,50 @@ class UserRegistrationMagicLink extends Command
{
$username = $this->option('username');
$email = $this->option('email');
if(!$username && !$email) {
if (! $username && ! $email) {
$this->error('Please provide the username or email as arguments');
$this->line(' ');
$this->info('Example: ');
$this->info('php artisan user:app-magic-link --username=dansup');
$this->info('php artisan user:app-magic-link --email=dansup@pixelfed.com');
return;
}
$user = User::when($username, function($q, $username) {
$user = User::when($username, function ($q, $username) {
return $q->whereUsername($username);
})
->when($email, function($q, $email) {
return $q->whereEmail($email);
})
->first();
->when($email, function ($q, $email) {
return $q->whereEmail($email);
})
->first();
if(!$user) {
if (! $user) {
$this->error('We cannot find any matching accounts');
return;
}
if($user->email_verified_at) {
if ($user->email_verified_at) {
$this->error('User already verified email address');
return;
}
if(!$user->register_source || $user->register_source !== 'app' || !$user->app_register_token) {
if (! $user->register_source || $user->register_source !== 'app' || ! $user->app_register_token) {
$this->error('User did not register via app');
return;
}
$verify = EmailVerification::whereUserId($user->id)->first();
if(!$verify) {
if (! $verify) {
$this->error('Cannot find user verification codes');
return;
}
$appUrl = 'pixelfed://confirm-account/'. $user->app_register_token . '?rt=' . $verify->random_token;
$appUrl = 'pixelfed://confirm-account/'.$user->app_register_token.'?rt='.$verify->random_token;
$this->line(' ');
$this->info('Magic link found! Copy the following link and send to user');
$this->line(' ');
@ -77,6 +82,7 @@ class UserRegistrationMagicLink extends Command
$this->info($appUrl);
$this->line(' ');
$this->line(' ');
return Command::SUCCESS;
}
}

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\User;
use Illuminate\Console\Command;
class UserShow extends Command
{
@ -39,20 +39,20 @@ class UserShow extends Command
public function handle()
{
$id = $this->argument('id');
if(ctype_digit($id) == true) {
if (ctype_digit($id) == true) {
$user = User::find($id);
} else {
$user = User::whereUsername($id)->first();
}
if(!$user) {
if (! $user) {
$this->error('Could not find any user with that username or id.');
exit;
}
$this->info('User ID: ' . $user->id);
$this->info('Username: ' . $user->username);
$this->info('Email: ' . $user->email);
$this->info('Joined: ' . $user->created_at->diffForHumans());
$this->info('Status Count: ' . $user->statuses()->count());
$this->info('User ID: '.$user->id);
$this->info('Username: '.$user->username);
$this->info('Email: '.$user->email);
$this->info('Joined: '.$user->created_at->diffForHumans());
$this->info('Status Count: '.$user->statuses()->count());
}
}

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\User;
use Illuminate\Console\Command;
class UserSuspend extends Command
{
@ -39,17 +39,17 @@ class UserSuspend extends Command
public function handle()
{
$id = $this->argument('id');
if(ctype_digit($id) == true) {
if (ctype_digit($id) == true) {
$user = User::find($id);
} else {
$user = User::whereUsername($id)->first();
}
if(!$user) {
if (! $user) {
$this->error('Could not find any user with that username or id.');
exit;
}
$this->info('Found user, username: ' . $user->username);
if($this->confirm('Are you sure you want to suspend this user?')) {
$this->info('Found user, username: '.$user->username);
if ($this->confirm('Are you sure you want to suspend this user?')) {
$profile = $user->profile;
$user->status = $profile->status = 'suspended';
$user->save();

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\User;
use Illuminate\Console\Command;
class UserTable extends Command
{

@ -2,9 +2,9 @@
namespace App\Console\Commands;
use App\User;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
use App\User;
class UserToggle2FA extends Command implements PromptsForMissingInput
{
@ -41,13 +41,14 @@ class UserToggle2FA extends Command implements PromptsForMissingInput
{
$user = User::whereUsername($this->argument('username'))->first();
if(!$user) {
if (! $user) {
$this->error('Could not find any user with that username');
exit;
}
if(!$user->{'2fa_enabled'}) {
if (! $user->{'2fa_enabled'}) {
$this->info('User did not have 2FA enabled!');
return;
}

@ -2,8 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\User;
use Illuminate\Console\Command;
class UserUnsuspend extends Command
{
@ -39,17 +39,17 @@ class UserUnsuspend extends Command
public function handle()
{
$id = $this->argument('id');
if(ctype_digit($id) == true) {
if (ctype_digit($id) == true) {
$user = User::find($id);
} else {
$user = User::whereUsername($id)->first();
}
if(!$user) {
if (! $user) {
$this->error('Could not find any user with that username or id.');
exit;
}
$this->info('Found user, username: ' . $user->username);
if($this->confirm('Are you sure you want to unsuspend this user?')) {
$this->info('Found user, username: '.$user->username);
if ($this->confirm('Are you sure you want to unsuspend this user?')) {
$profile = $user->profile;
$user->status = $profile->status = null;
$user->save();

@ -2,9 +2,8 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use App\User;
use Illuminate\Console\Command;
use Illuminate\Contracts\Console\PromptsForMissingInput;
class UserVerifyEmail extends Command implements PromptsForMissingInput
@ -43,18 +42,20 @@ class UserVerifyEmail extends Command implements PromptsForMissingInput
$username = $this->argument('username');
$user = User::whereUsername($username)->first();
if(!$user) {
if (! $user) {
$this->error('Username not found');
return;
}
if($user->email_verified_at) {
$this->error('Email already verified ' . $user->email_verified_at->diffForHumans());
if ($user->email_verified_at) {
$this->error('Email already verified '.$user->email_verified_at->diffForHumans());
return;
}
$user->email_verified_at = now();
$user->save();
$this->info('Successfully verified email address for ' . $user->username);
$this->info('Successfully verified email address for '.$user->username);
}
}

@ -2,10 +2,9 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Jobs\VideoPipeline\VideoThumbnail as Pipeline;
use App\Media;
use App\Jobs\VideoPipeline\VideoThumbnail as Pipeline;
use Illuminate\Console\Command;
class VideoThumbnail extends Command
{
@ -42,10 +41,10 @@ class VideoThumbnail extends Command
{
$limit = 10;
$videos = Media::whereMime('video/mp4')
->whereNull('thumbnail_path')
->take($limit)
->get();
foreach($videos as $video) {
->whereNull('thumbnail_path')
->take($limit)
->get();
foreach ($videos as $video) {
Pipeline::dispatch($video);
}
}

Loading…
Cancel
Save