mirror of https://github.com/pixelfed/pixelfed.git
Merge remote-tracking branch 'pixelfed/staging' into develop
# Conflicts: # app/Console/Kernel.php
This commit is contained in:
commit
55b1d52bf2
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -98,6 +98,18 @@
|
|||
- Update LoginController, fix captcha validation error message ([0325e171](https://github.com/pixelfed/pixelfed/commit/0325e171))
|
||||
- Update ApiV1Controller, properly cast boolean sensitive parameter. Fixes #4888 ([0aff126a](https://github.com/pixelfed/pixelfed/commit/0aff126a))
|
||||
- Update AccountImport.vue, fix new IG export format ([59aa6a4b](https://github.com/pixelfed/pixelfed/commit/59aa6a4b))
|
||||
- Update TransformImports command, fix import service condition ([32c59f04](https://github.com/pixelfed/pixelfed/commit/32c59f04))
|
||||
- Update AP helpers, more efficently update post count ([7caed381](https://github.com/pixelfed/pixelfed/commit/7caed381))
|
||||
- Update AP helpers, refactor post count decrement logic ([b81ae577](https://github.com/pixelfed/pixelfed/commit/b81ae577))
|
||||
- Update AP helpers, fix sensitive bug ([00ed330c](https://github.com/pixelfed/pixelfed/commit/00ed330c))
|
||||
- Update NotificationEpochUpdatePipeline, use more efficient query ([4d401389](https://github.com/pixelfed/pixelfed/commit/4d401389))
|
||||
- Update notification pipelines, fix non-local saving ([fa97a1f3](https://github.com/pixelfed/pixelfed/commit/fa97a1f3))
|
||||
- Update NodeinfoService, disable redirects ([240e6bbe](https://github.com/pixelfed/pixelfed/commit/240e6bbe))
|
||||
- Update Instance model, add entity casts ([289cad47](https://github.com/pixelfed/pixelfed/commit/289cad47))
|
||||
- Update FetchNodeinfoPipeline, use more efficient dispatch ([ac01f51a](https://github.com/pixelfed/pixelfed/commit/ac01f51a))
|
||||
- Update horizon.php config ([1e3acade](https://github.com/pixelfed/pixelfed/commit/1e3acade))
|
||||
- Update PublicApiController, consume InstanceService blocked domains for account and statuses endpoints ([01b33fb3](https://github.com/pixelfed/pixelfed/commit/01b33fb3))
|
||||
- Update ApiV1Controller, enforce blocked instance domain logic ([5b284cac](https://github.com/pixelfed/pixelfed/commit/5b284cac))
|
||||
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
||||
|
||||
## [v0.11.9 (2023-08-21)](https://github.com/pixelfed/pixelfed/compare/v0.11.8...v0.11.9)
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Services\AccountService;
|
||||
use App\Services\Account\AccountStatService;
|
||||
use App\Status;
|
||||
use App\Profile;
|
||||
|
||||
class AccountPostCountStatUpdate extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:account-post-count-stat-update';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Update post counts from recent activities';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$ids = AccountStatService::getAllPostCountIncr();
|
||||
if(!$ids || !count($ids)) {
|
||||
return;
|
||||
}
|
||||
foreach($ids as $id) {
|
||||
$acct = AccountService::get($id, true);
|
||||
if(!$acct) {
|
||||
AccountStatService::removeFromPostCount($id);
|
||||
continue;
|
||||
}
|
||||
$statusCount = Status::whereProfileId($id)->count();
|
||||
if($statusCount != $acct['statuses_count']) {
|
||||
$profile = Profile::find($id);
|
||||
if(!$profile) {
|
||||
AccountStatService::removeFromPostCount($id);
|
||||
continue;
|
||||
}
|
||||
$profile->status_count = $statusCount;
|
||||
$profile->save();
|
||||
AccountService::del($id);
|
||||
}
|
||||
AccountStatService::removeFromPostCount($id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,298 @@
|
|||
<?php
|
||||
|
||||
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 function Laravel\Prompts\confirm;
|
||||
use function Laravel\Prompts\progress;
|
||||
use function Laravel\Prompts\search;
|
||||
use function Laravel\Prompts\table;
|
||||
|
||||
class InstanceManager extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:instance-manager';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Manage Instances';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$action = select(
|
||||
'What action do you want to perform?',
|
||||
[
|
||||
'Recalculate Stats',
|
||||
'Ban Instance',
|
||||
'Unlist Instance',
|
||||
'Unlisted Instances',
|
||||
'Banned Instances',
|
||||
'Unban Instance',
|
||||
'Relist Instance',
|
||||
],
|
||||
);
|
||||
|
||||
switch($action) {
|
||||
case 'Recalculate Stats':
|
||||
return $this->recalculateStats();
|
||||
break;
|
||||
|
||||
case 'Unlisted Instances':
|
||||
return $this->viewUnlistedInstances();
|
||||
break;
|
||||
|
||||
case 'Banned Instances':
|
||||
return $this->viewBannedInstances();
|
||||
break;
|
||||
|
||||
case 'Unlist Instance':
|
||||
return $this->unlistInstance();
|
||||
break;
|
||||
|
||||
case 'Ban Instance':
|
||||
return $this->banInstance();
|
||||
break;
|
||||
|
||||
case 'Unban Instance':
|
||||
return $this->unbanInstance();
|
||||
break;
|
||||
|
||||
case 'Relist Instance':
|
||||
return $this->relistInstance();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function recalculateStats()
|
||||
{
|
||||
$instanceCount = Instance::count();
|
||||
$confirmed = confirm('Do you want to recalculate stats for all ' . $instanceCount . ' instances?');
|
||||
if(!$confirmed) {
|
||||
$this->error('Aborting...');
|
||||
exit;
|
||||
}
|
||||
|
||||
$users = progress(
|
||||
label: 'Updating instance stats...',
|
||||
steps: Instance::all(),
|
||||
callback: fn ($instance) => $this->updateInstanceStats($instance),
|
||||
);
|
||||
}
|
||||
|
||||
protected function updateInstanceStats($instance)
|
||||
{
|
||||
FetchNodeinfoPipeline::dispatch($instance)->onQueue('intbg');
|
||||
}
|
||||
|
||||
protected function unlistInstance()
|
||||
{
|
||||
$id = search(
|
||||
'Search by domain',
|
||||
fn (string $value) => strlen($value) > 0
|
||||
? Instance::whereUnlisted(false)->where('domain', 'like', "%{$value}%")->pluck('domain', 'id')->all()
|
||||
: []
|
||||
);
|
||||
|
||||
$instance = Instance::find($id);
|
||||
if(!$instance) {
|
||||
$this->error('Oops, an error occured');
|
||||
exit;
|
||||
}
|
||||
|
||||
$tbl = [
|
||||
[
|
||||
$instance->domain,
|
||||
number_format($instance->status_count),
|
||||
number_format($instance->user_count),
|
||||
]
|
||||
];
|
||||
table(
|
||||
['Domain', 'Status Count', 'User Count'],
|
||||
$tbl
|
||||
);
|
||||
|
||||
$confirmed = confirm('Are you sure you want to unlist this instance?');
|
||||
if(!$confirmed) {
|
||||
$this->error('Aborting instance unlisting');
|
||||
exit;
|
||||
}
|
||||
|
||||
$instance->unlisted = true;
|
||||
$instance->save();
|
||||
InstanceService::refresh();
|
||||
$this->info('Successfully unlisted ' . $instance->domain . '!');
|
||||
exit;
|
||||
}
|
||||
|
||||
protected function relistInstance()
|
||||
{
|
||||
$id = search(
|
||||
'Search by domain',
|
||||
fn (string $value) => strlen($value) > 0
|
||||
? Instance::whereUnlisted(true)->where('domain', 'like', "%{$value}%")->pluck('domain', 'id')->all()
|
||||
: []
|
||||
);
|
||||
|
||||
$instance = Instance::find($id);
|
||||
if(!$instance) {
|
||||
$this->error('Oops, an error occured');
|
||||
exit;
|
||||
}
|
||||
|
||||
$tbl = [
|
||||
[
|
||||
$instance->domain,
|
||||
number_format($instance->status_count),
|
||||
number_format($instance->user_count),
|
||||
]
|
||||
];
|
||||
table(
|
||||
['Domain', 'Status Count', 'User Count'],
|
||||
$tbl
|
||||
);
|
||||
|
||||
$confirmed = confirm('Are you sure you want to re-list this instance?');
|
||||
if(!$confirmed) {
|
||||
$this->error('Aborting instance re-listing');
|
||||
exit;
|
||||
}
|
||||
|
||||
$instance->unlisted = false;
|
||||
$instance->save();
|
||||
InstanceService::refresh();
|
||||
$this->info('Successfully re-listed ' . $instance->domain . '!');
|
||||
exit;
|
||||
}
|
||||
|
||||
protected function banInstance()
|
||||
{
|
||||
$id = search(
|
||||
'Search by domain',
|
||||
fn (string $value) => strlen($value) > 0
|
||||
? Instance::whereBanned(false)->where('domain', 'like', "%{$value}%")->pluck('domain', 'id')->all()
|
||||
: []
|
||||
);
|
||||
|
||||
$instance = Instance::find($id);
|
||||
if(!$instance) {
|
||||
$this->error('Oops, an error occured');
|
||||
exit;
|
||||
}
|
||||
|
||||
$tbl = [
|
||||
[
|
||||
$instance->domain,
|
||||
number_format($instance->status_count),
|
||||
number_format($instance->user_count),
|
||||
]
|
||||
];
|
||||
table(
|
||||
['Domain', 'Status Count', 'User Count'],
|
||||
$tbl
|
||||
);
|
||||
|
||||
$confirmed = confirm('Are you sure you want to ban this instance?');
|
||||
if(!$confirmed) {
|
||||
$this->error('Aborting instance ban');
|
||||
exit;
|
||||
}
|
||||
|
||||
$instance->banned = true;
|
||||
$instance->save();
|
||||
InstanceService::refresh();
|
||||
$this->info('Successfully banned ' . $instance->domain . '!');
|
||||
exit;
|
||||
}
|
||||
|
||||
protected function unbanInstance()
|
||||
{
|
||||
$id = search(
|
||||
'Search by domain',
|
||||
fn (string $value) => strlen($value) > 0
|
||||
? Instance::whereBanned(true)->where('domain', 'like', "%{$value}%")->pluck('domain', 'id')->all()
|
||||
: []
|
||||
);
|
||||
|
||||
$instance = Instance::find($id);
|
||||
if(!$instance) {
|
||||
$this->error('Oops, an error occured');
|
||||
exit;
|
||||
}
|
||||
|
||||
$tbl = [
|
||||
[
|
||||
$instance->domain,
|
||||
number_format($instance->status_count),
|
||||
number_format($instance->user_count),
|
||||
]
|
||||
];
|
||||
table(
|
||||
['Domain', 'Status Count', 'User Count'],
|
||||
$tbl
|
||||
);
|
||||
|
||||
$confirmed = confirm('Are you sure you want to unban this instance?');
|
||||
if(!$confirmed) {
|
||||
$this->error('Aborting instance unban');
|
||||
exit;
|
||||
}
|
||||
|
||||
$instance->banned = false;
|
||||
$instance->save();
|
||||
InstanceService::refresh();
|
||||
$this->info('Successfully un-banned ' . $instance->domain . '!');
|
||||
exit;
|
||||
}
|
||||
|
||||
protected function viewBannedInstances()
|
||||
{
|
||||
$data = Instance::whereBanned(true)
|
||||
->get(['domain', 'user_count', 'status_count'])
|
||||
->map(function($d) {
|
||||
return [
|
||||
'domain' => $d->domain,
|
||||
'user_count' => number_format($d->user_count),
|
||||
'status_count' => number_format($d->status_count),
|
||||
];
|
||||
})
|
||||
->toArray();
|
||||
table(
|
||||
['Domain', 'User Count', 'Status Count'],
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
protected function viewUnlistedInstances()
|
||||
{
|
||||
$data = Instance::whereUnlisted(true)
|
||||
->get(['domain', 'user_count', 'status_count', 'banned'])
|
||||
->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
|
||||
];
|
||||
})
|
||||
->toArray();
|
||||
table(
|
||||
['Domain', 'User Count', 'Status Count', 'Banned'],
|
||||
$data
|
||||
);
|
||||
}
|
||||
}
|
|
@ -70,6 +70,11 @@ class TransformImports extends Command
|
|||
}
|
||||
|
||||
$idk = ImportService::getId($ip->user_id, $ip->creation_year, $ip->creation_month, $ip->creation_day);
|
||||
if(!$idk) {
|
||||
$ip->skip_missing_media = true;
|
||||
$ip->save();
|
||||
continue;
|
||||
}
|
||||
|
||||
if(Storage::exists('imports/' . $id . '/' . $ip->filename) === false) {
|
||||
ImportService::clearAttempts($profile->id);
|
||||
|
|
|
@ -38,7 +38,7 @@ class Kernel extends ConsoleKernel
|
|||
}
|
||||
|
||||
if(config('import.instagram.enabled')) {
|
||||
$schedule->command('app:transform-imports')->everyFourMinutes()->onOneServer();
|
||||
$schedule->command('app:transform-imports')->everyTenMinutes()->onOneServer();
|
||||
$schedule->command('app:import-upload-garbage-collection')->hourlyAt(51)->onOneServer();
|
||||
$schedule->command('app:import-remove-deleted-accounts')->hourlyAt(37)->onOneServer();
|
||||
$schedule->command('app:import-upload-clean-storage')->twiceDailyAt(1, 13, 32)->onOneServer();
|
||||
|
@ -49,6 +49,7 @@ class Kernel extends ConsoleKernel
|
|||
}
|
||||
$schedule->command('app:notification-epoch-update')->weeklyOn(1, '2:21')->onOneServer();
|
||||
$schedule->command('app:hashtag-cached-count-update')->hourlyAt(25)->onOneServer();
|
||||
$schedule->command('app:account-post-count-stat-update')->everySixHours(25)->onOneServer();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -219,6 +219,10 @@ class ApiV1Controller extends Controller
|
|||
if(!$res) {
|
||||
return response()->json(['error' => 'Record not found'], 404);
|
||||
}
|
||||
if($res && strpos($res['acct'], '@') != -1) {
|
||||
$domain = parse_url($res['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
return $this->json($res);
|
||||
}
|
||||
|
||||
|
@ -483,6 +487,11 @@ class ApiV1Controller extends Controller
|
|||
$limit = $request->input('limit', 10);
|
||||
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
||||
|
||||
if($account && strpos($account['acct'], '@') != -1) {
|
||||
$domain = parse_url($account['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
|
||||
if(intval($pid) !== intval($account['id'])) {
|
||||
if($account['locked']) {
|
||||
if(!FollowerService::follows($pid, $account['id'])) {
|
||||
|
@ -575,6 +584,11 @@ class ApiV1Controller extends Controller
|
|||
$limit = $request->input('limit', 10);
|
||||
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
||||
|
||||
if($account && strpos($account['acct'], '@') != -1) {
|
||||
$domain = parse_url($account['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
|
||||
if(intval($pid) !== intval($account['id'])) {
|
||||
if($account['locked']) {
|
||||
if(!FollowerService::follows($pid, $account['id'])) {
|
||||
|
@ -676,6 +690,11 @@ class ApiV1Controller extends Controller
|
|||
return $this->json(['error' => 'Account not found'], 404);
|
||||
}
|
||||
|
||||
if($profile && strpos($profile['acct'], '@') != -1) {
|
||||
$domain = parse_url($profile['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
|
||||
$limit = $request->limit ?? 20;
|
||||
$max_id = $request->max_id;
|
||||
$min_id = $request->min_id;
|
||||
|
@ -766,6 +785,11 @@ class ApiV1Controller extends Controller
|
|||
->whereNull('status')
|
||||
->findOrFail($id);
|
||||
|
||||
if($target && $target->domain) {
|
||||
$domain = $target->domain;
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
|
||||
$private = (bool) $target->is_private;
|
||||
$remote = (bool) $target->domain;
|
||||
$blocked = UserFilter::whereUserId($target->id)
|
||||
|
@ -1252,14 +1276,19 @@ class ApiV1Controller extends Controller
|
|||
$user = $request->user();
|
||||
abort_if($user->has_roles && !UserRoleService::can('can-like', $user->id), 403, 'Invalid permissions for this action');
|
||||
|
||||
AccountService::setLastActive($user->id);
|
||||
|
||||
$status = StatusService::getMastodon($id, false);
|
||||
|
||||
abort_unless($status, 400);
|
||||
abort_unless($status, 404);
|
||||
|
||||
if($status && isset($status['account'], $status['account']['acct']) && strpos($status['account']['acct'], '@') != -1) {
|
||||
$domain = parse_url($status['account']['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
|
||||
$spid = $status['account']['id'];
|
||||
|
||||
AccountService::setLastActive($user->id);
|
||||
|
||||
if(intval($spid) !== intval($user->profile_id)) {
|
||||
if($status['visibility'] == 'private') {
|
||||
abort_if(!FollowerService::follows($user->profile_id, $spid), 403);
|
||||
|
@ -1404,6 +1433,11 @@ class ApiV1Controller extends Controller
|
|||
return response()->json(['error' => 'Record not found'], 404);
|
||||
}
|
||||
|
||||
if($target && strpos($target['acct'], '@') != -1) {
|
||||
$domain = parse_url($target['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
|
||||
$followRequest = FollowRequest::whereFollowingId($pid)->whereFollowerId($id)->first();
|
||||
|
||||
if(!$followRequest) {
|
||||
|
@ -2011,6 +2045,11 @@ class ApiV1Controller extends Controller
|
|||
|
||||
$account = Profile::findOrFail($id);
|
||||
|
||||
if($account && $account->domain) {
|
||||
$domain = $account->domain;
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
|
||||
$count = UserFilterService::muteCount($pid);
|
||||
$maxLimit = intval(config('instance.user_filters.max_user_mutes'));
|
||||
if($count == 0) {
|
||||
|
@ -2653,6 +2692,11 @@ class ApiV1Controller extends Controller
|
|||
abort(404);
|
||||
}
|
||||
|
||||
if($res && isset($res['account'], $res['account']['acct'], $res['account']['url']) && strpos($res['account']['acct'], '@') != -1) {
|
||||
$domain = parse_url($res['account']['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
|
||||
$scope = $res['visibility'];
|
||||
if(!in_array($scope, ['public', 'unlisted'])) {
|
||||
if($scope === 'private') {
|
||||
|
@ -2697,6 +2741,11 @@ class ApiV1Controller extends Controller
|
|||
return response('', 404);
|
||||
}
|
||||
|
||||
if($status && isset($status['account'], $status['account']['acct']) && strpos($status['account']['acct'], '@') != -1) {
|
||||
$domain = parse_url($status['account']['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
|
||||
if(intval($status['account']['id']) !== intval($user->profile_id)) {
|
||||
if($status['visibility'] == 'private') {
|
||||
if(!FollowerService::follows($user->profile_id, $status['account']['id'])) {
|
||||
|
@ -2780,6 +2829,10 @@ class ApiV1Controller extends Controller
|
|||
$status = Status::findOrFail($id);
|
||||
$account = AccountService::get($status->profile_id, true);
|
||||
abort_if(!$account, 404);
|
||||
if($account && strpos($account['acct'], '@') != -1) {
|
||||
$domain = parse_url($account['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
$author = intval($status->profile_id) === intval($pid) || $user->is_admin;
|
||||
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
||||
|
||||
|
@ -2871,6 +2924,10 @@ class ApiV1Controller extends Controller
|
|||
$pid = $user->profile_id;
|
||||
$status = Status::findOrFail($id);
|
||||
$account = AccountService::get($status->profile_id, true);
|
||||
if($account && strpos($account['acct'], '@') != -1) {
|
||||
$domain = parse_url($account['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
abort_if(!$account, 404);
|
||||
$author = intval($status->profile_id) === intval($pid) || $user->is_admin;
|
||||
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
||||
|
@ -3200,7 +3257,11 @@ class ApiV1Controller extends Controller
|
|||
abort_if($user->has_roles && !UserRoleService::can('can-share', $user->id), 403, 'Invalid permissions for this action');
|
||||
AccountService::setLastActive($user->id);
|
||||
$status = Status::whereScope('public')->findOrFail($id);
|
||||
|
||||
if($status && ($status->uri || $status->url || $status->object_url)) {
|
||||
$url = $status->uri ?? $status->url ?? $status->object_url;
|
||||
$domain = parse_url($url, PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
if(intval($status->profile_id) !== intval($user->profile_id)) {
|
||||
if($status->scope == 'private') {
|
||||
abort_if(!FollowerService::follows($user->profile_id, $status->profile_id), 403);
|
||||
|
|
|
@ -42,6 +42,7 @@ use App\Services\{
|
|||
use App\Jobs\StatusPipeline\NewStatusPipeline;
|
||||
use League\Fractal\Serializer\ArraySerializer;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use App\Services\InstanceService;
|
||||
|
||||
class PublicApiController extends Controller
|
||||
{
|
||||
|
@ -661,6 +662,10 @@ class PublicApiController extends Controller
|
|||
public function account(Request $request, $id)
|
||||
{
|
||||
$res = AccountService::get($id);
|
||||
if($res && isset($res['local'], $res['url']) && !$res['local']) {
|
||||
$domain = parse_url($res['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
return response()->json($res);
|
||||
}
|
||||
|
||||
|
@ -680,6 +685,11 @@ class PublicApiController extends Controller
|
|||
$profile = AccountService::get($id);
|
||||
abort_if(!$profile, 404);
|
||||
|
||||
if($profile && isset($profile['local'], $profile['url']) && !$profile['local']) {
|
||||
$domain = parse_url($profile['url'], PHP_URL_HOST);
|
||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||
}
|
||||
|
||||
$limit = $request->limit ?? 9;
|
||||
$max_id = $request->max_id;
|
||||
$min_id = $request->min_id;
|
||||
|
|
120
app/Instance.php
120
app/Instance.php
|
@ -6,63 +6,77 @@ use Illuminate\Database\Eloquent\Model;
|
|||
|
||||
class Instance extends Model
|
||||
{
|
||||
protected $fillable = ['domain', 'banned', 'auto_cw', 'unlisted', 'notes'];
|
||||
protected $casts = [
|
||||
'last_crawled_at' => 'datetime',
|
||||
'actors_last_synced_at' => 'datetime',
|
||||
'notes' => 'array',
|
||||
'nodeinfo_last_fetched' => 'datetime',
|
||||
'delivery_next_after' => 'datetime',
|
||||
];
|
||||
|
||||
public function profiles()
|
||||
{
|
||||
return $this->hasMany(Profile::class, 'domain', 'domain');
|
||||
}
|
||||
protected $fillable = [
|
||||
'domain',
|
||||
'banned',
|
||||
'auto_cw',
|
||||
'unlisted',
|
||||
'notes'
|
||||
];
|
||||
|
||||
public function statuses()
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
Status::class,
|
||||
Profile::class,
|
||||
'domain',
|
||||
'profile_id',
|
||||
'domain',
|
||||
'id'
|
||||
);
|
||||
}
|
||||
public function profiles()
|
||||
{
|
||||
return $this->hasMany(Profile::class, 'domain', 'domain');
|
||||
}
|
||||
|
||||
public function reported()
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
Report::class,
|
||||
Profile::class,
|
||||
'domain',
|
||||
'reported_profile_id',
|
||||
'domain',
|
||||
'id'
|
||||
);
|
||||
}
|
||||
public function statuses()
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
Status::class,
|
||||
Profile::class,
|
||||
'domain',
|
||||
'profile_id',
|
||||
'domain',
|
||||
'id'
|
||||
);
|
||||
}
|
||||
|
||||
public function reports()
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
Report::class,
|
||||
Profile::class,
|
||||
'domain',
|
||||
'profile_id',
|
||||
'domain',
|
||||
'id'
|
||||
);
|
||||
}
|
||||
public function reported()
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
Report::class,
|
||||
Profile::class,
|
||||
'domain',
|
||||
'reported_profile_id',
|
||||
'domain',
|
||||
'id'
|
||||
);
|
||||
}
|
||||
|
||||
public function media()
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
Media::class,
|
||||
Profile::class,
|
||||
'domain',
|
||||
'profile_id',
|
||||
'domain',
|
||||
'id'
|
||||
);
|
||||
}
|
||||
public function reports()
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
Report::class,
|
||||
Profile::class,
|
||||
'domain',
|
||||
'profile_id',
|
||||
'domain',
|
||||
'id'
|
||||
);
|
||||
}
|
||||
|
||||
public function getUrl()
|
||||
{
|
||||
return url("/i/admin/instances/show/{$this->id}");
|
||||
}
|
||||
public function media()
|
||||
{
|
||||
return $this->hasManyThrough(
|
||||
Media::class,
|
||||
Profile::class,
|
||||
'domain',
|
||||
'profile_id',
|
||||
'domain',
|
||||
'id'
|
||||
);
|
||||
}
|
||||
|
||||
public function getUrl()
|
||||
{
|
||||
return url("/i/admin/instances/show/{$this->id}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,19 +91,21 @@ class CommentPipeline implements ShouldQueue
|
|||
return;
|
||||
}
|
||||
|
||||
DB::transaction(function() use($target, $actor, $comment) {
|
||||
$notification = new Notification();
|
||||
$notification->profile_id = $target->id;
|
||||
$notification->actor_id = $actor->id;
|
||||
$notification->action = 'comment';
|
||||
$notification->item_id = $comment->id;
|
||||
$notification->item_type = "App\Status";
|
||||
$notification->save();
|
||||
if($target->user_id && $target->domain === null) {
|
||||
DB::transaction(function() use($target, $actor, $comment) {
|
||||
$notification = new Notification();
|
||||
$notification->profile_id = $target->id;
|
||||
$notification->actor_id = $actor->id;
|
||||
$notification->action = 'comment';
|
||||
$notification->item_id = $comment->id;
|
||||
$notification->item_type = "App\Status";
|
||||
$notification->save();
|
||||
|
||||
NotificationService::setNotification($notification);
|
||||
NotificationService::set($notification->profile_id, $notification->id);
|
||||
StatusService::del($comment->id);
|
||||
});
|
||||
NotificationService::setNotification($notification);
|
||||
NotificationService::set($notification->profile_id, $notification->id);
|
||||
StatusService::del($comment->id);
|
||||
});
|
||||
}
|
||||
|
||||
if($exists = Cache::get('status:replies:all:' . $status->id)) {
|
||||
if($exists && $exists->count() == 3) {
|
||||
|
|
|
@ -22,9 +22,9 @@ use App\Notification;
|
|||
use App\Services\AccountService;
|
||||
use App\Services\NetworkTimelineService;
|
||||
use App\Services\StatusService;
|
||||
use App\Jobs\ProfilePipeline\DecrementPostCount;
|
||||
use App\Jobs\MediaPipeline\MediaDeletePipeline;
|
||||
use Cache;
|
||||
use App\Services\Account\AccountStatService;
|
||||
|
||||
class DeleteRemoteStatusPipeline implements ShouldQueue
|
||||
{
|
||||
|
@ -56,10 +56,7 @@ class DeleteRemoteStatusPipeline implements ShouldQueue
|
|||
{
|
||||
$status = $this->status;
|
||||
|
||||
if(AccountService::get($status->profile_id, true)) {
|
||||
DecrementPostCount::dispatch($status->profile_id)->onQueue('low');
|
||||
}
|
||||
|
||||
AccountStatService::decrementPostCount($status->profile_id);
|
||||
NetworkTimelineService::del($status->id);
|
||||
StatusService::del($status->id, true);
|
||||
Bookmark::whereStatusId($status->id)->delete();
|
||||
|
|
|
@ -72,16 +72,18 @@ class FollowPipeline implements ShouldQueue
|
|||
$target->save();
|
||||
AccountService::del($target->id);
|
||||
|
||||
try {
|
||||
$notification = new Notification();
|
||||
$notification->profile_id = $target->id;
|
||||
$notification->actor_id = $actor->id;
|
||||
$notification->action = 'follow';
|
||||
$notification->item_id = $target->id;
|
||||
$notification->item_type = "App\Profile";
|
||||
$notification->save();
|
||||
} catch (Exception $e) {
|
||||
Log::error($e);
|
||||
if($target->user_id && $target->domain === null) {
|
||||
try {
|
||||
$notification = new Notification();
|
||||
$notification->profile_id = $target->id;
|
||||
$notification->actor_id = $actor->id;
|
||||
$notification->action = 'follow';
|
||||
$notification->item_id = $target->id;
|
||||
$notification->item_type = "App\Profile";
|
||||
$notification->save();
|
||||
} catch (Exception $e) {
|
||||
Log::error($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Jobs\InstancePipeline;
|
|||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||
use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
|
@ -12,45 +13,71 @@ use Illuminate\Support\Facades\Http;
|
|||
use App\Instance;
|
||||
use App\Profile;
|
||||
use App\Services\NodeinfoService;
|
||||
use Illuminate\Contracts\Cache\Repository;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class FetchNodeinfoPipeline implements ShouldQueue
|
||||
class FetchNodeinfoPipeline implements ShouldQueue, ShouldBeUniqueUntilProcessing
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
protected $instance;
|
||||
protected $instance;
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Instance $instance)
|
||||
{
|
||||
$this->instance = $instance;
|
||||
}
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Instance $instance)
|
||||
{
|
||||
$this->instance = $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$instance = $this->instance;
|
||||
/**
|
||||
* The number of seconds after which the job's unique lock will be released.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $uniqueFor = 14400;
|
||||
|
||||
$ni = NodeinfoService::get($instance->domain);
|
||||
if($ni) {
|
||||
if(isset($ni['software']) && is_array($ni['software']) && isset($ni['software']['name'])) {
|
||||
$software = $ni['software']['name'];
|
||||
$instance->software = strtolower(strip_tags($software));
|
||||
$instance->last_crawled_at = now();
|
||||
$instance->user_count = Profile::whereDomain($instance->domain)->count();
|
||||
$instance->save();
|
||||
}
|
||||
} else {
|
||||
$instance->user_count = Profile::whereDomain($instance->domain)->count();
|
||||
$instance->last_crawled_at = now();
|
||||
$instance->save();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the unique ID for the job.
|
||||
*/
|
||||
public function uniqueId(): string
|
||||
{
|
||||
return $this->instance->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the job.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$instance = $this->instance;
|
||||
|
||||
if( $instance->nodeinfo_last_fetched &&
|
||||
$instance->nodeinfo_last_fetched->gt(now()->subHours(12)) ||
|
||||
$instance->delivery_timeout &&
|
||||
$instance->delivery_next_after->gt(now())
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ni = NodeinfoService::get($instance->domain);
|
||||
$instance->last_crawled_at = now();
|
||||
if($ni) {
|
||||
if(isset($ni['software']) && is_array($ni['software']) && isset($ni['software']['name'])) {
|
||||
$software = $ni['software']['name'];
|
||||
$instance->software = strtolower(strip_tags($software));
|
||||
$instance->user_count = Profile::whereDomain($instance->domain)->count();
|
||||
$instance->nodeinfo_last_fetched = now();
|
||||
$instance->save();
|
||||
}
|
||||
} else {
|
||||
$instance->delivery_timeout = 1;
|
||||
$instance->delivery_next_after = now()->addHours(14);
|
||||
$instance->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,12 @@ class NotificationEpochUpdatePipeline implements ShouldQueue, ShouldBeUniqueUnti
|
|||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
$rec = Notification::where('created_at', '>', now()->subMonths(6))->first();
|
||||
$pid = Cache::get(NotificationService::EPOCH_CACHE_KEY . '6');
|
||||
if($pid && $pid > 1) {
|
||||
$rec = Notification::where('id', '>', $pid)->whereDate('created_at', now()->subMonths(6)->format('Y-m-d'))->first();
|
||||
} else {
|
||||
$rec = Notification::whereDate('created_at', now()->subMonths(6)->format('Y-m-d'))->first();
|
||||
}
|
||||
$id = 1;
|
||||
if($rec) {
|
||||
$id = $rec->id;
|
||||
|
|
|
@ -79,16 +79,18 @@ class LikePipeline implements ShouldQueue
|
|||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
$notification = new Notification();
|
||||
$notification->profile_id = $status->profile_id;
|
||||
$notification->actor_id = $actor->id;
|
||||
$notification->action = 'like';
|
||||
$notification->item_id = $status->id;
|
||||
$notification->item_type = "App\Status";
|
||||
$notification->save();
|
||||
if($status->uri === null && $status->object_url === null && $status->url === null) {
|
||||
try {
|
||||
$notification = new Notification();
|
||||
$notification->profile_id = $status->profile_id;
|
||||
$notification->actor_id = $actor->id;
|
||||
$notification->action = 'like';
|
||||
$notification->item_id = $status->id;
|
||||
$notification->item_type = "App\Status";
|
||||
$notification->save();
|
||||
|
||||
} catch (Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,18 +35,7 @@ class DecrementPostCount implements ShouldQueue
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
$id = $this->id;
|
||||
|
||||
$profile = Profile::find($id);
|
||||
|
||||
if(!$profile) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$profile->status_count = $profile->status_count ? $profile->status_count - 1 : 0;
|
||||
$profile->save();
|
||||
AccountService::del($id);
|
||||
|
||||
return 1;
|
||||
// deprecated
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,42 +14,12 @@ use App\Profile;
|
|||
use App\Status;
|
||||
use App\Services\AccountService;
|
||||
|
||||
class IncrementPostCount implements ShouldQueue, ShouldBeUniqueUntilProcessing
|
||||
class IncrementPostCount implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public $id;
|
||||
|
||||
public $timeout = 900;
|
||||
public $tries = 3;
|
||||
public $maxExceptions = 1;
|
||||
public $failOnTimeout = true;
|
||||
|
||||
/**
|
||||
* The number of seconds after which the job's unique lock will be released.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $uniqueFor = 3600;
|
||||
|
||||
/**
|
||||
* Get the unique ID for the job.
|
||||
*/
|
||||
public function uniqueId(): string
|
||||
{
|
||||
return 'propipe:ipc:' . $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the middleware the job should pass through.
|
||||
*
|
||||
* @return array<int, object>
|
||||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [(new WithoutOverlapping("propipe:ipc:{$this->id}"))->shared()->dontRelease()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new job instance.
|
||||
*
|
||||
|
@ -67,20 +37,7 @@ class IncrementPostCount implements ShouldQueue, ShouldBeUniqueUntilProcessing
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
$id = $this->id;
|
||||
|
||||
$profile = Profile::find($id);
|
||||
|
||||
if(!$profile) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$profile->status_count = $profile->status_count + 1;
|
||||
$profile->last_status_at = now();
|
||||
$profile->save();
|
||||
AccountService::del($id);
|
||||
AccountService::get($id);
|
||||
|
||||
return 1;
|
||||
// deprecated
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ use App\Services\AccountService;
|
|||
use App\Services\CollectionService;
|
||||
use App\Services\StatusService;
|
||||
use App\Jobs\MediaPipeline\MediaDeletePipeline;
|
||||
use App\Jobs\ProfilePipeline\DecrementPostCount;
|
||||
use App\Services\NotificationService;
|
||||
use App\Services\Account\AccountStatService;
|
||||
|
||||
class RemoteStatusDelete implements ShouldQueue, ShouldBeUniqueUntilProcessing
|
||||
{
|
||||
|
@ -109,9 +109,7 @@ class RemoteStatusDelete implements ShouldQueue, ShouldBeUniqueUntilProcessing
|
|||
}
|
||||
|
||||
StatusService::del($status->id, true);
|
||||
|
||||
DecrementPostCount::dispatch($status->profile_id)->onQueue('inbox');
|
||||
|
||||
AccountStatService::decrementPostCount($status->profile_id);
|
||||
return $this->unlinkRemoveMedia($status);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,18 +87,20 @@ class StatusReplyPipeline implements ShouldQueue
|
|||
Cache::forget('status:replies:all:' . $reply->id);
|
||||
Cache::forget('status:replies:all:' . $status->id);
|
||||
|
||||
DB::transaction(function() use($target, $actor, $status) {
|
||||
$notification = new Notification();
|
||||
$notification->profile_id = $target->id;
|
||||
$notification->actor_id = $actor->id;
|
||||
$notification->action = 'comment';
|
||||
$notification->item_id = $status->id;
|
||||
$notification->item_type = "App\Status";
|
||||
$notification->save();
|
||||
if($target->user_id && $target->domain === null) {
|
||||
DB::transaction(function() use($target, $actor, $status) {
|
||||
$notification = new Notification();
|
||||
$notification->profile_id = $target->id;
|
||||
$notification->actor_id = $actor->id;
|
||||
$notification->action = 'comment';
|
||||
$notification->item_id = $status->id;
|
||||
$notification->item_type = "App\Status";
|
||||
$notification->save();
|
||||
|
||||
NotificationService::setNotification($notification);
|
||||
NotificationService::set($notification->profile_id, $notification->id);
|
||||
});
|
||||
NotificationService::setNotification($notification);
|
||||
NotificationService::set($notification->profile_id, $notification->id);
|
||||
});
|
||||
}
|
||||
|
||||
if($exists = Cache::get('status:replies:all:' . $reply->id)) {
|
||||
if($exists && $exists->count() == 3) {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Account;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class AccountStatService
|
||||
{
|
||||
const REFRESH_CACHE_KEY = 'pf:services:accountstats:refresh:daily';
|
||||
|
||||
public static function incrementPostCount($pid)
|
||||
{
|
||||
return Redis::zadd(self::REFRESH_CACHE_KEY, $pid, $pid);
|
||||
}
|
||||
|
||||
public static function decrementPostCount($pid)
|
||||
{
|
||||
return Redis::zadd(self::REFRESH_CACHE_KEY, $pid, $pid);
|
||||
}
|
||||
|
||||
public static function removeFromPostCount($pid)
|
||||
{
|
||||
return Redis::zrem(self::REFRESH_CACHE_KEY, $pid);
|
||||
}
|
||||
|
||||
public static function getAllPostCountIncr($limit = -1)
|
||||
{
|
||||
return Redis::zrange(self::REFRESH_CACHE_KEY, 0, $limit);
|
||||
}
|
||||
}
|
|
@ -22,7 +22,10 @@ class NodeinfoService
|
|||
$wk = $url . '/.well-known/nodeinfo';
|
||||
|
||||
try {
|
||||
$res = Http::withHeaders($headers)
|
||||
$res = Http::withOptions([
|
||||
'allow_redirects' => false,
|
||||
])
|
||||
->withHeaders($headers)
|
||||
->timeout(5)
|
||||
->get($wk);
|
||||
} catch (RequestException $e) {
|
||||
|
@ -61,7 +64,10 @@ class NodeinfoService
|
|||
}
|
||||
|
||||
try {
|
||||
$res = Http::withHeaders($headers)
|
||||
$res = Http::withOptions([
|
||||
'allow_redirects' => false,
|
||||
])
|
||||
->withHeaders($headers)
|
||||
->timeout(5)
|
||||
->get($href);
|
||||
} catch (RequestException $e) {
|
||||
|
|
|
@ -39,10 +39,9 @@ use App\Jobs\HomeFeedPipeline\FeedInsertRemotePipeline;
|
|||
use App\Util\Media\License;
|
||||
use App\Models\Poll;
|
||||
use Illuminate\Contracts\Cache\LockTimeoutException;
|
||||
use App\Jobs\ProfilePipeline\IncrementPostCount;
|
||||
use App\Jobs\ProfilePipeline\DecrementPostCount;
|
||||
use App\Services\DomainService;
|
||||
use App\Services\UserFilterService;
|
||||
use App\Services\Account\AccountStatService;
|
||||
|
||||
class Helpers {
|
||||
|
||||
|
@ -536,7 +535,7 @@ class Helpers {
|
|||
}
|
||||
}
|
||||
|
||||
IncrementPostCount::dispatch($pid)->onQueue('low');
|
||||
AccountStatService::incrementPostCount($pid);
|
||||
|
||||
if( $status->in_reply_to_id === null &&
|
||||
in_array($status->type, ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||
|
@ -549,10 +548,11 @@ class Helpers {
|
|||
|
||||
public static function getSensitive($activity, $url)
|
||||
{
|
||||
$id = isset($activity['id']) ? self::pluckval($activity['id']) : self::pluckval($url);
|
||||
$url = isset($activity['url']) ? self::pluckval($activity['url']) : $id;
|
||||
$urlDomain = parse_url($url, PHP_URL_HOST);
|
||||
if(!$url || !strlen($url)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$urlDomain = parse_url($url, PHP_URL_HOST);
|
||||
$cw = isset($activity['sensitive']) ? (bool) $activity['sensitive'] : false;
|
||||
|
||||
if(in_array($urlDomain, InstanceService::getNsfwDomains())) {
|
||||
|
|
|
@ -48,8 +48,6 @@ use App\Services\UserFilterService;
|
|||
use App\Services\NetworkTimelineService;
|
||||
use App\Models\Conversation;
|
||||
use App\Models\RemoteReport;
|
||||
use App\Jobs\ProfilePipeline\IncrementPostCount;
|
||||
use App\Jobs\ProfilePipeline\DecrementPostCount;
|
||||
use App\Jobs\HomeFeedPipeline\FeedRemoveRemotePipeline;
|
||||
|
||||
class Inbox
|
||||
|
|
|
@ -2,201 +2,202 @@
|
|||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the subdomain where Horizon will be accessible from. If this
|
||||
| setting is null, Horizon will reside under the same domain as the
|
||||
| application. Otherwise, this value will serve as the subdomain.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the subdomain where Horizon will be accessible from. If this
|
||||
| setting is null, Horizon will reside under the same domain as the
|
||||
| application. Otherwise, this value will serve as the subdomain.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => null,
|
||||
'domain' => null,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the URI path where Horizon will be accessible from. Feel free
|
||||
| to change this path to anything you like. Note that the URI will not
|
||||
| affect the paths of its internal API that aren't exposed to users.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the URI path where Horizon will be accessible from. Feel free
|
||||
| to change this path to anything you like. Note that the URI will not
|
||||
| affect the paths of its internal API that aren't exposed to users.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => 'horizon',
|
||||
'path' => 'horizon',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Redis Connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the name of the Redis connection where Horizon will store the
|
||||
| meta information required for it to function. It includes the list
|
||||
| of supervisors, failed jobs, job metrics, and other information.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Redis Connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the name of the Redis connection where Horizon will store the
|
||||
| meta information required for it to function. It includes the list
|
||||
| of supervisors, failed jobs, job metrics, and other information.
|
||||
|
|
||||
*/
|
||||
|
||||
'use' => 'default',
|
||||
'use' => 'default',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Redis Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This prefix will be used when storing all Horizon data in Redis. You
|
||||
| may modify the prefix when you are running multiple installations
|
||||
| of Horizon on the same server so that they don't have problems.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Redis Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This prefix will be used when storing all Horizon data in Redis. You
|
||||
| may modify the prefix when you are running multiple installations
|
||||
| of Horizon on the same server so that they don't have problems.
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => env('HORIZON_PREFIX', 'horizon-'),
|
||||
'prefix' => env('HORIZON_PREFIX', 'horizon-'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Route Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These middleware will get attached onto each Horizon route, giving you
|
||||
| the chance to add your own middleware to this list or change any of
|
||||
| the existing middleware. Or, you can simply stick with this list.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Horizon Route Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These middleware will get attached onto each Horizon route, giving you
|
||||
| the chance to add your own middleware to this list or change any of
|
||||
| the existing middleware. Or, you can simply stick with this list.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => ['web'],
|
||||
'middleware' => ['web'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Wait Time Thresholds
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to configure when the LongWaitDetected event
|
||||
| will be fired. Every connection / queue combination may have its
|
||||
| own, unique threshold (in seconds) before this event is fired.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Wait Time Thresholds
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to configure when the LongWaitDetected event
|
||||
| will be fired. Every connection / queue combination may have its
|
||||
| own, unique threshold (in seconds) before this event is fired.
|
||||
|
|
||||
*/
|
||||
|
||||
'waits' => [
|
||||
'redis:feed' => 30,
|
||||
'redis:follow' => 30,
|
||||
'redis:shared' => 30,
|
||||
'redis:default' => 30,
|
||||
'redis:inbox' => 30,
|
||||
'redis:low' => 30,
|
||||
'redis:high' => 30,
|
||||
'redis:delete' => 30,
|
||||
'redis:story' => 30,
|
||||
'redis:mmo' => 30,
|
||||
],
|
||||
'waits' => [
|
||||
'redis:feed' => 30,
|
||||
'redis:follow' => 30,
|
||||
'redis:shared' => 30,
|
||||
'redis:default' => 30,
|
||||
'redis:inbox' => 30,
|
||||
'redis:low' => 30,
|
||||
'redis:high' => 30,
|
||||
'redis:delete' => 30,
|
||||
'redis:story' => 30,
|
||||
'redis:mmo' => 30,
|
||||
'redis:intbg' => 30,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Job Trimming Times
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you can configure for how long (in minutes) you desire Horizon to
|
||||
| persist the recent and failed jobs. Typically, recent jobs are kept
|
||||
| for one hour while all failed jobs are stored for an entire week.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Job Trimming Times
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you can configure for how long (in minutes) you desire Horizon to
|
||||
| persist the recent and failed jobs. Typically, recent jobs are kept
|
||||
| for one hour while all failed jobs are stored for an entire week.
|
||||
|
|
||||
*/
|
||||
|
||||
'trim' => [
|
||||
'recent' => 60,
|
||||
'pending' => 60,
|
||||
'completed' => 60,
|
||||
'recent_failed' => 10080,
|
||||
'failed' => 10080,
|
||||
'monitored' => 10080,
|
||||
],
|
||||
'trim' => [
|
||||
'recent' => 60,
|
||||
'pending' => 60,
|
||||
'completed' => 60,
|
||||
'recent_failed' => 10080,
|
||||
'failed' => 10080,
|
||||
'monitored' => 10080,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Metrics
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you can configure how many snapshots should be kept to display in
|
||||
| the metrics graph. This will get used in combination with Horizon's
|
||||
| `horizon:snapshot` schedule to define how long to retain metrics.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Metrics
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you can configure how many snapshots should be kept to display in
|
||||
| the metrics graph. This will get used in combination with Horizon's
|
||||
| `horizon:snapshot` schedule to define how long to retain metrics.
|
||||
|
|
||||
*/
|
||||
|
||||
'metrics' => [
|
||||
'trim_snapshots' => [
|
||||
'job' => 24,
|
||||
'queue' => 24,
|
||||
],
|
||||
],
|
||||
'metrics' => [
|
||||
'trim_snapshots' => [
|
||||
'job' => 24,
|
||||
'queue' => 24,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Fast Termination
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When this option is enabled, Horizon's "terminate" command will not
|
||||
| wait on all of the workers to terminate unless the --wait option
|
||||
| is provided. Fast termination can shorten deployment delay by
|
||||
| allowing a new instance of Horizon to start while the last
|
||||
| instance will continue to terminate each of its workers.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Fast Termination
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When this option is enabled, Horizon's "terminate" command will not
|
||||
| wait on all of the workers to terminate unless the --wait option
|
||||
| is provided. Fast termination can shorten deployment delay by
|
||||
| allowing a new instance of Horizon to start while the last
|
||||
| instance will continue to terminate each of its workers.
|
||||
|
|
||||
*/
|
||||
|
||||
'fast_termination' => false,
|
||||
'fast_termination' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Memory Limit (MB)
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value describes the maximum amount of memory the Horizon worker
|
||||
| may consume before it is terminated and restarted. You should set
|
||||
| this value according to the resources available to your server.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Memory Limit (MB)
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value describes the maximum amount of memory the Horizon worker
|
||||
| may consume before it is terminated and restarted. You should set
|
||||
| this value according to the resources available to your server.
|
||||
|
|
||||
*/
|
||||
|
||||
'memory_limit' => env('HORIZON_MEMORY_LIMIT', 64),
|
||||
'memory_limit' => env('HORIZON_MEMORY_LIMIT', 64),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Worker Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define the queue worker settings used by your application
|
||||
| in all environments. These supervisors and settings handle all your
|
||||
| queued jobs and will be provisioned by Horizon during deployment.
|
||||
|
|
||||
*/
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Worker Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define the queue worker settings used by your application
|
||||
| in all environments. These supervisors and settings handle all your
|
||||
| queued jobs and will be provisioned by Horizon during deployment.
|
||||
|
|
||||
*/
|
||||
|
||||
'environments' => [
|
||||
'production' => [
|
||||
'supervisor-1' => [
|
||||
'connection' => 'redis',
|
||||
'queue' => ['high', 'default', 'follow', 'shared', 'inbox', 'feed', 'low', 'story', 'delete', 'mmo'],
|
||||
'balance' => env('HORIZON_BALANCE_STRATEGY', 'auto'),
|
||||
'minProcesses' => env('HORIZON_MIN_PROCESSES', 1),
|
||||
'maxProcesses' => env('HORIZON_MAX_PROCESSES', 20),
|
||||
'memory' => env('HORIZON_SUPERVISOR_MEMORY', 64),
|
||||
'tries' => env('HORIZON_SUPERVISOR_TRIES', 3),
|
||||
'nice' => env('HORIZON_SUPERVISOR_NICE', 0),
|
||||
'timeout' => env('HORIZON_SUPERVISOR_TIMEOUT', 300),
|
||||
],
|
||||
],
|
||||
'environments' => [
|
||||
'production' => [
|
||||
'supervisor-1' => [
|
||||
'connection' => 'redis',
|
||||
'queue' => ['high', 'default', 'follow', 'shared', 'inbox', 'feed', 'low', 'story', 'delete', 'mmo', 'intbg'],
|
||||
'balance' => env('HORIZON_BALANCE_STRATEGY', 'auto'),
|
||||
'minProcesses' => env('HORIZON_MIN_PROCESSES', 1),
|
||||
'maxProcesses' => env('HORIZON_MAX_PROCESSES', 20),
|
||||
'memory' => env('HORIZON_SUPERVISOR_MEMORY', 64),
|
||||
'tries' => env('HORIZON_SUPERVISOR_TRIES', 3),
|
||||
'nice' => env('HORIZON_SUPERVISOR_NICE', 0),
|
||||
'timeout' => env('HORIZON_SUPERVISOR_TIMEOUT', 300),
|
||||
],
|
||||
],
|
||||
|
||||
'local' => [
|
||||
'supervisor-1' => [
|
||||
'connection' => 'redis',
|
||||
'queue' => ['high', 'default', 'follow', 'shared', 'inbox', 'feed', 'low', 'story', 'delete', 'mmo'],
|
||||
'balance' => 'auto',
|
||||
'minProcesses' => 1,
|
||||
'maxProcesses' => 20,
|
||||
'memory' => 128,
|
||||
'tries' => 3,
|
||||
'nice' => 0,
|
||||
'timeout' => 300
|
||||
],
|
||||
],
|
||||
],
|
||||
'local' => [
|
||||
'supervisor-1' => [
|
||||
'connection' => 'redis',
|
||||
'queue' => ['high', 'default', 'follow', 'shared', 'inbox', 'feed', 'low', 'story', 'delete', 'mmo', 'intbg'],
|
||||
'balance' => 'auto',
|
||||
'minProcesses' => 1,
|
||||
'maxProcesses' => 20,
|
||||
'memory' => 128,
|
||||
'tries' => 3,
|
||||
'nice' => 0,
|
||||
'timeout' => 300
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'darkmode' => env('HORIZON_DARKMODE', false),
|
||||
'darkmode' => env('HORIZON_DARKMODE', false),
|
||||
];
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('instances', function (Blueprint $table) {
|
||||
$table->boolean('active_deliver')->nullable()->index()->after('domain');
|
||||
$table->boolean('valid_nodeinfo')->nullable();
|
||||
$table->timestamp('nodeinfo_last_fetched')->nullable();
|
||||
$table->boolean('delivery_timeout')->default(false);
|
||||
$table->timestamp('delivery_next_after')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('instances', function (Blueprint $table) {
|
||||
$table->dropColumn('active_deliver');
|
||||
$table->dropColumn('valid_nodeinfo');
|
||||
$table->dropColumn('nodeinfo_last_fetched');
|
||||
$table->dropColumn('delivery_timeout');
|
||||
$table->dropColumn('delivery_next_after');
|
||||
});
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue