mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-10 00:34:50 +00:00
Merge branch 'staging' of github.com:pixelfed/pixelfed into jippi-fork
This commit is contained in:
commit
5a9cfe1f2a
136 changed files with 5575 additions and 1668 deletions
7
.gitattributes
vendored
7
.gitattributes
vendored
|
@ -3,3 +3,10 @@
|
||||||
*.scss linguist-vendored
|
*.scss linguist-vendored
|
||||||
*.js linguist-vendored
|
*.js linguist-vendored
|
||||||
CHANGELOG.md export-ignore
|
CHANGELOG.md export-ignore
|
||||||
|
|
||||||
|
# Collapse diffs for generated files:
|
||||||
|
public/**/*.js text -diff
|
||||||
|
public/**/*.json text -diff
|
||||||
|
public/**/*.css text -diff
|
||||||
|
public/img/* binary -diff
|
||||||
|
public/fonts/* binary -diff
|
||||||
|
|
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,6 +1,19 @@
|
||||||
# Release Notes
|
# Release Notes
|
||||||
|
|
||||||
## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.11.12...dev)
|
## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.11.12...dev)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
- Curated Onboarding ([8dac2caf](https://github.com/pixelfed/pixelfed/commit/8dac2caf))
|
||||||
|
|
||||||
|
### Updates
|
||||||
|
|
||||||
|
- Update Inbox, cast live filters to lowercase ([d835e0ad](https://github.com/pixelfed/pixelfed/commit/d835e0ad))
|
||||||
|
- Update federation config, increase default timeline days falloff to 90 days from 2 days. Fixes #4905 ([011834f4](https://github.com/pixelfed/pixelfed/commit/011834f4))
|
||||||
|
- Update cache config, use predis as default redis driver client ([ea6b1623](https://github.com/pixelfed/pixelfed/commit/ea6b1623))
|
||||||
|
- Update .gitattributes to collapse diffs on generated files ([ThisIsMissEm](https://github.com/pixelfed/pixelfed/commit/9978b2b9))
|
||||||
|
- Update api v1/v2 instance endpoints, bump mastoapi version from 2.7.2 to 3.5.3 ([545f7d5e](https://github.com/pixelfed/pixelfed/commit/545f7d5e))
|
||||||
|
- Update ApiV1Controller, implement better limit logic to gracefully handle requests with limits that exceed the max ([1f74a95d](https://github.com/pixelfed/pixelfed/commit/1f74a95d))
|
||||||
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
||||||
|
|
||||||
## [v0.11.12 (2024-02-16)](https://github.com/pixelfed/pixelfed/compare/v0.11.11...v0.11.12)
|
## [v0.11.12 (2024-02-16)](https://github.com/pixelfed/pixelfed/compare/v0.11.11...v0.11.12)
|
||||||
|
@ -9,7 +22,7 @@
|
||||||
- Autospam Live Filters - block remote activities based on comma separated keywords ([40b45b2a](https://github.com/pixelfed/pixelfed/commit/40b45b2a))
|
- Autospam Live Filters - block remote activities based on comma separated keywords ([40b45b2a](https://github.com/pixelfed/pixelfed/commit/40b45b2a))
|
||||||
- Added Software Update banner to admin home feeds ([b0fb1988](https://github.com/pixelfed/pixelfed/commit/b0fb1988))
|
- Added Software Update banner to admin home feeds ([b0fb1988](https://github.com/pixelfed/pixelfed/commit/b0fb1988))
|
||||||
|
|
||||||
### Updated
|
### Updates
|
||||||
|
|
||||||
- Update ApiV1Controller, fix network timeline ([0faf59e3](https://github.com/pixelfed/pixelfed/commit/0faf59e3))
|
- Update ApiV1Controller, fix network timeline ([0faf59e3](https://github.com/pixelfed/pixelfed/commit/0faf59e3))
|
||||||
- Update public/network timelines, fix non-redis response and fix reblogs in home feed ([8b4ac5cc](https://github.com/pixelfed/pixelfed/commit/8b4ac5cc))
|
- Update public/network timelines, fix non-redis response and fix reblogs in home feed ([8b4ac5cc](https://github.com/pixelfed/pixelfed/commit/8b4ac5cc))
|
||||||
|
|
|
@ -32,13 +32,9 @@ trait AdminSettingsController
|
||||||
|
|
||||||
$availableAdmins = User::whereIsAdmin(true)->get();
|
$availableAdmins = User::whereIsAdmin(true)->get();
|
||||||
$currentAdmin = config_cache('instance.admin.pid') ? AccountService::get(config_cache('instance.admin.pid'), true) : null;
|
$currentAdmin = config_cache('instance.admin.pid') ? AccountService::get(config_cache('instance.admin.pid'), true) : null;
|
||||||
|
$openReg = (bool) config_cache('pixelfed.open_registration');
|
||||||
// $system = [
|
$curOnboarding = (bool) config_cache('instance.curated_registration.enabled');
|
||||||
// 'permissions' => is_writable(base_path('storage')) && is_writable(base_path('bootstrap')),
|
$regState = $openReg ? 'open' : ($curOnboarding ? 'filtered' : 'closed');
|
||||||
// 'max_upload_size' => ini_get('post_max_size'),
|
|
||||||
// 'image_driver' => config('image.driver'),
|
|
||||||
// 'image_driver_loaded' => extension_loaded(config('image.driver'))
|
|
||||||
// ];
|
|
||||||
|
|
||||||
return view('admin.settings.home', compact(
|
return view('admin.settings.home', compact(
|
||||||
'jpeg',
|
'jpeg',
|
||||||
|
@ -51,8 +47,8 @@ trait AdminSettingsController
|
||||||
'cloud_disk',
|
'cloud_disk',
|
||||||
'cloud_ready',
|
'cloud_ready',
|
||||||
'availableAdmins',
|
'availableAdmins',
|
||||||
'currentAdmin'
|
'currentAdmin',
|
||||||
// 'system'
|
'regState'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,8 +67,31 @@ trait AdminSettingsController
|
||||||
'type_mp4' => 'nullable',
|
'type_mp4' => 'nullable',
|
||||||
'type_webp' => 'nullable',
|
'type_webp' => 'nullable',
|
||||||
'admin_account_id' => 'nullable',
|
'admin_account_id' => 'nullable',
|
||||||
|
'regs' => 'required|in:open,filtered,closed'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$orb = false;
|
||||||
|
$cob = false;
|
||||||
|
switch($request->input('regs')) {
|
||||||
|
case 'open':
|
||||||
|
$orb = true;
|
||||||
|
$cob = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'filtered':
|
||||||
|
$orb = false;
|
||||||
|
$cob = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'closed':
|
||||||
|
$orb = false;
|
||||||
|
$cob = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigCacheService::put('pixelfed.open_registration', (bool) $orb);
|
||||||
|
ConfigCacheService::put('instance.curated_registration.enabled', (bool) $cob);
|
||||||
|
|
||||||
if($request->filled('admin_account_id')) {
|
if($request->filled('admin_account_id')) {
|
||||||
ConfigCacheService::put('instance.admin.pid', $request->admin_account_id);
|
ConfigCacheService::put('instance.admin.pid', $request->admin_account_id);
|
||||||
Cache::forget('api:v1:instance-data:contact');
|
Cache::forget('api:v1:instance-data:contact');
|
||||||
|
@ -143,7 +162,7 @@ trait AdminSettingsController
|
||||||
|
|
||||||
$bools = [
|
$bools = [
|
||||||
'activitypub' => 'federation.activitypub.enabled',
|
'activitypub' => 'federation.activitypub.enabled',
|
||||||
'open_registration' => 'pixelfed.open_registration',
|
// 'open_registration' => 'pixelfed.open_registration',
|
||||||
'mobile_apis' => 'pixelfed.oauth_enabled',
|
'mobile_apis' => 'pixelfed.oauth_enabled',
|
||||||
'stories' => 'instance.stories.enabled',
|
'stories' => 'instance.stories.enabled',
|
||||||
'ig_import' => 'pixelfed.import.instagram.enabled',
|
'ig_import' => 'pixelfed.import.instagram.enabled',
|
||||||
|
|
226
app/Http/Controllers/AdminCuratedRegisterController.php
Normal file
226
app/Http/Controllers/AdminCuratedRegisterController.php
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use App\Models\CuratedRegister;
|
||||||
|
use App\Models\CuratedRegisterActivity;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use App\Mail\CuratedRegisterRequestDetailsFromUser;
|
||||||
|
use App\Mail\CuratedRegisterAcceptUser;
|
||||||
|
use App\Mail\CuratedRegisterRejectUser;
|
||||||
|
use App\User;
|
||||||
|
|
||||||
|
class AdminCuratedRegisterController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->middleware(['auth','admin']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'filter' => 'sometimes|in:open,all,awaiting,approved,rejected'
|
||||||
|
]);
|
||||||
|
$filter = $request->input('filter', 'open');
|
||||||
|
$records = CuratedRegister::when($filter, function($q, $filter) {
|
||||||
|
if($filter === 'open') {
|
||||||
|
return $q->where('is_rejected', false)
|
||||||
|
->whereNotNull('email_verified_at')
|
||||||
|
->whereIsClosed(false);
|
||||||
|
} else if($filter === 'all') {
|
||||||
|
return $q;
|
||||||
|
} elseif ($filter === 'awaiting') {
|
||||||
|
return $q->whereIsClosed(false)
|
||||||
|
->whereNull('is_rejected')
|
||||||
|
->whereNull('is_approved');
|
||||||
|
} elseif ($filter === 'approved') {
|
||||||
|
return $q->whereIsClosed(true)->whereIsApproved(true);
|
||||||
|
} elseif ($filter === 'rejected') {
|
||||||
|
return $q->whereIsClosed(true)->whereIsRejected(true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
->latest()
|
||||||
|
->paginate(10);
|
||||||
|
return view('admin.curated-register.index', compact('records', 'filter'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show(Request $request, $id)
|
||||||
|
{
|
||||||
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
return view('admin.curated-register.show', compact('record'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apiActivityLog(Request $request, $id)
|
||||||
|
{
|
||||||
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
|
||||||
|
$res = collect([
|
||||||
|
[
|
||||||
|
'id' => 1,
|
||||||
|
'action' => 'created',
|
||||||
|
'title' => 'Onboarding application created',
|
||||||
|
'message' => null,
|
||||||
|
'link' => null,
|
||||||
|
'timestamp' => $record->created_at,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
if($record->email_verified_at) {
|
||||||
|
$res->push([
|
||||||
|
'id' => 3,
|
||||||
|
'action' => 'email_verified_at',
|
||||||
|
'title' => 'Applicant successfully verified email address',
|
||||||
|
'message' => null,
|
||||||
|
'link' => null,
|
||||||
|
'timestamp' => $record->email_verified_at,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$activities = CuratedRegisterActivity::whereRegisterId($record->id)->get();
|
||||||
|
|
||||||
|
$idx = 4;
|
||||||
|
$userResponses = collect([]);
|
||||||
|
|
||||||
|
foreach($activities as $activity) {
|
||||||
|
$idx++;
|
||||||
|
if($activity->from_user) {
|
||||||
|
$userResponses->push($activity);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$res->push([
|
||||||
|
'id' => $idx,
|
||||||
|
'aid' => $activity->id,
|
||||||
|
'action' => $activity->type,
|
||||||
|
'title' => $activity->from_admin ? 'Admin requested info' : 'User responded',
|
||||||
|
'message' => $activity->message,
|
||||||
|
'link' => $activity->adminReviewUrl(),
|
||||||
|
'timestamp' => $activity->created_at,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($userResponses as $ur) {
|
||||||
|
$res = $res->map(function($r) use($ur) {
|
||||||
|
if(!isset($r['aid'])) {
|
||||||
|
return $r;
|
||||||
|
}
|
||||||
|
if($ur->reply_to_id === $r['aid']) {
|
||||||
|
$r['user_response'] = $ur;
|
||||||
|
return $r;
|
||||||
|
}
|
||||||
|
return $r;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if($record->is_approved) {
|
||||||
|
$idx++;
|
||||||
|
$res->push([
|
||||||
|
'id' => $idx,
|
||||||
|
'action' => 'approved',
|
||||||
|
'title' => 'Application Approved',
|
||||||
|
'message' => null,
|
||||||
|
'link' => null,
|
||||||
|
'timestamp' => $record->action_taken_at,
|
||||||
|
]);
|
||||||
|
} else if ($record->is_rejected) {
|
||||||
|
$idx++;
|
||||||
|
$res->push([
|
||||||
|
'id' => $idx,
|
||||||
|
'action' => 'rejected',
|
||||||
|
'title' => 'Application Rejected',
|
||||||
|
'message' => null,
|
||||||
|
'link' => null,
|
||||||
|
'timestamp' => $record->action_taken_at,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $res->reverse()->values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apiMessagePreviewStore(Request $request, $id)
|
||||||
|
{
|
||||||
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
return $request->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apiMessageSendStore(Request $request, $id)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'message' => 'required|string|min:5|max:1000'
|
||||||
|
]);
|
||||||
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
||||||
|
$activity = new CuratedRegisterActivity;
|
||||||
|
$activity->register_id = $record->id;
|
||||||
|
$activity->admin_id = $request->user()->id;
|
||||||
|
$activity->secret_code = Str::random(32);
|
||||||
|
$activity->type = 'request_details';
|
||||||
|
$activity->from_admin = true;
|
||||||
|
$activity->message = $request->input('message');
|
||||||
|
$activity->save();
|
||||||
|
$record->is_awaiting_more_info = true;
|
||||||
|
$record->save();
|
||||||
|
Mail::to($record->email)->send(new CuratedRegisterRequestDetailsFromUser($record, $activity));
|
||||||
|
return $request->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function previewDetailsMessageShow(Request $request, $id)
|
||||||
|
{
|
||||||
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
||||||
|
$activity = new CuratedRegisterActivity;
|
||||||
|
$activity->message = $request->input('message');
|
||||||
|
return new \App\Mail\CuratedRegisterRequestDetailsFromUser($record, $activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function previewMessageShow(Request $request, $id)
|
||||||
|
{
|
||||||
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
||||||
|
$record->message = $request->input('message');
|
||||||
|
return new \App\Mail\CuratedRegisterSendMessage($record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apiHandleReject(Request $request, $id)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'action' => 'required|in:reject-email,reject-silent'
|
||||||
|
]);
|
||||||
|
$action = $request->input('action');
|
||||||
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
abort_if($record->email_verified_at === null, 400, 'Cannot reject an unverified email');
|
||||||
|
$record->is_rejected = true;
|
||||||
|
$record->is_closed = true;
|
||||||
|
$record->action_taken_at = now();
|
||||||
|
$record->save();
|
||||||
|
if($action === 'reject-email') {
|
||||||
|
Mail::to($record->email)->send(new CuratedRegisterRejectUser($record));
|
||||||
|
}
|
||||||
|
return [200];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apiHandleApprove(Request $request, $id)
|
||||||
|
{
|
||||||
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
abort_if($record->email_verified_at === null, 400, 'Cannot reject an unverified email');
|
||||||
|
$record->is_approved = true;
|
||||||
|
$record->is_closed = true;
|
||||||
|
$record->action_taken_at = now();
|
||||||
|
$record->save();
|
||||||
|
$user = User::create([
|
||||||
|
'name' => $record->username,
|
||||||
|
'username' => $record->username,
|
||||||
|
'email' => $record->email,
|
||||||
|
'password' => $record->password,
|
||||||
|
'app_register_ip' => $record->ip_address,
|
||||||
|
'email_verified_at' => now(),
|
||||||
|
'register_source' => 'cur_onboarding'
|
||||||
|
]);
|
||||||
|
|
||||||
|
Mail::to($record->email)->send(new CuratedRegisterAcceptUser($record));
|
||||||
|
return [200];
|
||||||
|
}
|
||||||
|
}
|
|
@ -496,9 +496,12 @@ class ApiV1Controller extends Controller
|
||||||
abort_if(!$account, 404);
|
abort_if(!$account, 404);
|
||||||
$pid = $request->user()->profile_id;
|
$pid = $request->user()->profile_id;
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'limit' => 'sometimes|integer|min:1|max:80'
|
'limit' => 'sometimes|integer|min:1'
|
||||||
]);
|
]);
|
||||||
$limit = $request->input('limit', 10);
|
$limit = $request->input('limit', 10);
|
||||||
|
if($limit > 80) {
|
||||||
|
$limit = 80;
|
||||||
|
}
|
||||||
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
||||||
|
|
||||||
if($account && strpos($account['acct'], '@') != -1) {
|
if($account && strpos($account['acct'], '@') != -1) {
|
||||||
|
@ -594,9 +597,12 @@ class ApiV1Controller extends Controller
|
||||||
abort_if(!$account, 404);
|
abort_if(!$account, 404);
|
||||||
$pid = $request->user()->profile_id;
|
$pid = $request->user()->profile_id;
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'limit' => 'sometimes|integer|min:1|max:80'
|
'limit' => 'sometimes|integer|min:1'
|
||||||
]);
|
]);
|
||||||
$limit = $request->input('limit', 10);
|
$limit = $request->input('limit', 10);
|
||||||
|
if($limit > 80) {
|
||||||
|
$limit = 80;
|
||||||
|
}
|
||||||
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
||||||
|
|
||||||
if($account && strpos($account['acct'], '@') != -1) {
|
if($account && strpos($account['acct'], '@') != -1) {
|
||||||
|
@ -698,7 +704,7 @@ class ApiV1Controller extends Controller
|
||||||
'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
||||||
'since_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
'since_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
||||||
'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
||||||
'limit' => 'nullable|integer|min:1|max:100'
|
'limit' => 'nullable|integer|min:1'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
||||||
|
@ -713,7 +719,10 @@ class ApiV1Controller extends Controller
|
||||||
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
abort_if(in_array($domain, InstanceService::getBannedDomains()), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
$limit = $request->limit ?? 20;
|
$limit = $request->input('limit') ?? 20;
|
||||||
|
if($limit > 40) {
|
||||||
|
$limit = 40;
|
||||||
|
}
|
||||||
$max_id = $request->max_id;
|
$max_id = $request->max_id;
|
||||||
$min_id = $request->min_id;
|
$min_id = $request->min_id;
|
||||||
|
|
||||||
|
@ -959,12 +968,16 @@ class ApiV1Controller extends Controller
|
||||||
abort_if(!$request->user(), 403);
|
abort_if(!$request->user(), 403);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'id' => 'required|array|min:1|max:20',
|
'id' => 'required|array|min:1',
|
||||||
'id.*' => 'required|integer|min:1|max:' . PHP_INT_MAX
|
'id.*' => 'required|integer|min:1|max:' . PHP_INT_MAX
|
||||||
]);
|
]);
|
||||||
|
$ids = $request->input('id');
|
||||||
|
if(count($ids) > 20) {
|
||||||
|
$ids = collect($ids)->take(20)->toArray();
|
||||||
|
}
|
||||||
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
$napi = $request->has(self::PF_API_ENTITY_KEY);
|
||||||
$pid = $request->user()->profile_id ?? $request->user()->profile->id;
|
$pid = $request->user()->profile_id ?? $request->user()->profile->id;
|
||||||
$res = collect($request->input('id'))
|
$res = collect($ids)
|
||||||
->filter(function($id) use($pid) {
|
->filter(function($id) use($pid) {
|
||||||
return intval($id) !== intval($pid);
|
return intval($id) !== intval($pid);
|
||||||
})
|
})
|
||||||
|
@ -989,8 +1002,8 @@ class ApiV1Controller extends Controller
|
||||||
abort_unless($request->user()->tokenCan('read'), 403);
|
abort_unless($request->user()->tokenCan('read'), 403);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'q' => 'required|string|min:1|max:255',
|
'q' => 'required|string|min:1|max:30',
|
||||||
'limit' => 'nullable|integer|min:1|max:40',
|
'limit' => 'nullable|integer|min:1',
|
||||||
'resolve' => 'nullable'
|
'resolve' => 'nullable'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -1000,13 +1013,14 @@ class ApiV1Controller extends Controller
|
||||||
AccountService::setLastActive($user->id);
|
AccountService::setLastActive($user->id);
|
||||||
$query = $request->input('q');
|
$query = $request->input('q');
|
||||||
$limit = $request->input('limit') ?? 20;
|
$limit = $request->input('limit') ?? 20;
|
||||||
$resolve = (bool) $request->input('resolve', false);
|
if($limit > 20) {
|
||||||
$q = '%' . $query . '%';
|
$limit = 20;
|
||||||
|
}
|
||||||
|
$resolve = $request->boolean('resolve', false);
|
||||||
|
$q = $query . '%';
|
||||||
|
|
||||||
$profiles = Cache::remember('api:v1:accounts:search:' . sha1($query) . ':limit:' . $limit, 86400, function() use($q, $limit) {
|
$profiles = Profile::where('username', 'like', $q)
|
||||||
return Profile::whereNull('status')
|
->orderByDesc('followers_count')
|
||||||
->where('username', 'like', $q)
|
|
||||||
->orWhere('name', 'like', $q)
|
|
||||||
->limit($limit)
|
->limit($limit)
|
||||||
->pluck('id')
|
->pluck('id')
|
||||||
->map(function($id) {
|
->map(function($id) {
|
||||||
|
@ -1014,8 +1028,8 @@ class ApiV1Controller extends Controller
|
||||||
})
|
})
|
||||||
->filter(function($account) {
|
->filter(function($account) {
|
||||||
return $account && isset($account['id']);
|
return $account && isset($account['id']);
|
||||||
});
|
})
|
||||||
});
|
->values();
|
||||||
|
|
||||||
return $this->json($profiles);
|
return $this->json($profiles);
|
||||||
}
|
}
|
||||||
|
@ -1033,20 +1047,25 @@ class ApiV1Controller extends Controller
|
||||||
abort_unless($request->user()->tokenCan('read'), 403);
|
abort_unless($request->user()->tokenCan('read'), 403);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'limit' => 'nullable|integer|min:1|max:40',
|
'limit' => 'sometimes|integer|min:1',
|
||||||
'page' => 'nullable|integer|min:1|max:10'
|
'page' => 'sometimes|integer|min:1'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
$limit = $request->input('limit') ?? 40;
|
$limit = $request->input('limit') ?? 40;
|
||||||
|
if($limit > 80) {
|
||||||
|
$limit = 80;
|
||||||
|
}
|
||||||
|
|
||||||
$blocked = UserFilter::select('filterable_id','filterable_type','filter_type','user_id')
|
$blocks = UserFilter::select('filterable_id','filterable_type','filter_type','user_id')
|
||||||
->whereUserId($user->profile_id)
|
->whereUserId($user->profile_id)
|
||||||
->whereFilterableType('App\Profile')
|
->whereFilterableType('App\Profile')
|
||||||
->whereFilterType('block')
|
->whereFilterType('block')
|
||||||
->orderByDesc('id')
|
->orderByDesc('id')
|
||||||
->simplePaginate($limit)
|
->simplePaginate($limit)
|
||||||
->pluck('filterable_id')
|
->withQueryString();
|
||||||
|
|
||||||
|
$res = $blocks->pluck('filterable_id')
|
||||||
->map(function($id) {
|
->map(function($id) {
|
||||||
return AccountService::get($id, true);
|
return AccountService::get($id, true);
|
||||||
})
|
})
|
||||||
|
@ -1055,7 +1074,23 @@ class ApiV1Controller extends Controller
|
||||||
})
|
})
|
||||||
->values();
|
->values();
|
||||||
|
|
||||||
return $this->json($blocked);
|
$baseUrl = config('app.url') . '/api/v1/blocks?limit=' . $limit . '&';
|
||||||
|
$next = $blocks->nextPageUrl();
|
||||||
|
$prev = $blocks->previousPageUrl();
|
||||||
|
|
||||||
|
if($next && !$prev) {
|
||||||
|
$link = '<'.$next.'>; rel="next"';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$next && $prev) {
|
||||||
|
$link = '<'.$prev.'>; rel="prev"';
|
||||||
|
}
|
||||||
|
|
||||||
|
if($next && $prev) {
|
||||||
|
$link = '<'.$next.'>; rel="next",<'.$prev.'>; rel="prev"';
|
||||||
|
}
|
||||||
|
$headers = isset($link) ? ['Link' => $link] : [];
|
||||||
|
return $this->json($res, 200, $headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1247,13 +1282,16 @@ class ApiV1Controller extends Controller
|
||||||
abort_unless($request->user()->tokenCan('read'), 403);
|
abort_unless($request->user()->tokenCan('read'), 403);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'limit' => 'sometimes|integer|min:1|max:40'
|
'limit' => 'sometimes|integer|min:1'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
$maxId = $request->input('max_id');
|
$maxId = $request->input('max_id');
|
||||||
$minId = $request->input('min_id');
|
$minId = $request->input('min_id');
|
||||||
$limit = $request->input('limit') ?? 10;
|
$limit = $request->input('limit') ?? 10;
|
||||||
|
if($limit > 40) {
|
||||||
|
$limit = 40;
|
||||||
|
}
|
||||||
|
|
||||||
$res = Like::whereProfileId($user->profile_id)
|
$res = Like::whereProfileId($user->profile_id)
|
||||||
->when($maxId, function($q, $maxId) {
|
->when($maxId, function($q, $maxId) {
|
||||||
|
@ -1612,15 +1650,15 @@ class ApiV1Controller extends Controller
|
||||||
'short_description' => config_cache('app.short_description'),
|
'short_description' => config_cache('app.short_description'),
|
||||||
'description' => config_cache('app.description'),
|
'description' => config_cache('app.description'),
|
||||||
'email' => config('instance.email'),
|
'email' => config('instance.email'),
|
||||||
'version' => '2.7.2 (compatible; Pixelfed ' . config('pixelfed.version') .')',
|
'version' => '3.5.3 (compatible; Pixelfed ' . config('pixelfed.version') .')',
|
||||||
'urls' => [
|
'urls' => [
|
||||||
'streaming_api' => 'wss://' . config('pixelfed.domain.app')
|
'streaming_api' => null,
|
||||||
],
|
],
|
||||||
'stats' => $stats,
|
'stats' => $stats,
|
||||||
'thumbnail' => config_cache('app.banner_image') ?? url(Storage::url('public/headers/default.jpg')),
|
'thumbnail' => config_cache('app.banner_image') ?? url(Storage::url('public/headers/default.jpg')),
|
||||||
'languages' => [config('app.locale')],
|
'languages' => [config('app.locale')],
|
||||||
'registrations' => (bool) config_cache('pixelfed.open_registration'),
|
'registrations' => (bool) config_cache('pixelfed.open_registration'),
|
||||||
'approval_required' => false,
|
'approval_required' => (bool) config_cache('instance.curated_registration.enabled'),
|
||||||
'contact_account' => $contact,
|
'contact_account' => $contact,
|
||||||
'rules' => $rules,
|
'rules' => $rules,
|
||||||
'configuration' => [
|
'configuration' => [
|
||||||
|
@ -2049,18 +2087,23 @@ class ApiV1Controller extends Controller
|
||||||
abort_unless($request->user()->tokenCan('read'), 403);
|
abort_unless($request->user()->tokenCan('read'), 403);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'limit' => 'nullable|integer|min:1|max:40'
|
'limit' => 'sometimes|integer|min:1'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
$limit = $request->input('limit', 40);
|
$limit = $request->input('limit', 40);
|
||||||
|
if($limit > 80) {
|
||||||
|
$limit = 80;
|
||||||
|
}
|
||||||
|
|
||||||
$mutes = UserFilter::whereUserId($user->profile_id)
|
$mutes = UserFilter::whereUserId($user->profile_id)
|
||||||
->whereFilterableType('App\Profile')
|
->whereFilterableType('App\Profile')
|
||||||
->whereFilterType('mute')
|
->whereFilterType('mute')
|
||||||
->orderByDesc('id')
|
->orderByDesc('id')
|
||||||
->simplePaginate($limit)
|
->simplePaginate($limit)
|
||||||
->pluck('filterable_id')
|
->withQueryString();
|
||||||
|
|
||||||
|
$res = $mutes->pluck('filterable_id')
|
||||||
->map(function($id) {
|
->map(function($id) {
|
||||||
return AccountService::get($id, true);
|
return AccountService::get($id, true);
|
||||||
})
|
})
|
||||||
|
@ -2069,7 +2112,23 @@ class ApiV1Controller extends Controller
|
||||||
})
|
})
|
||||||
->values();
|
->values();
|
||||||
|
|
||||||
return $this->json($mutes);
|
$baseUrl = config('app.url') . '/api/v1/mutes?limit=' . $limit . '&';
|
||||||
|
$next = $mutes->nextPageUrl();
|
||||||
|
$prev = $mutes->previousPageUrl();
|
||||||
|
|
||||||
|
if($next && !$prev) {
|
||||||
|
$link = '<'.$next.'>; rel="next"';
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$next && $prev) {
|
||||||
|
$link = '<'.$prev.'>; rel="prev"';
|
||||||
|
}
|
||||||
|
|
||||||
|
if($next && $prev) {
|
||||||
|
$link = '<'.$next.'>; rel="next",<'.$prev.'>; rel="prev"';
|
||||||
|
}
|
||||||
|
$headers = isset($link) ? ['Link' => $link] : [];
|
||||||
|
return $this->json($res, 200, $headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2181,7 +2240,7 @@ class ApiV1Controller extends Controller
|
||||||
abort_unless($request->user()->tokenCan('read'), 403);
|
abort_unless($request->user()->tokenCan('read'), 403);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'limit' => 'nullable|integer|min:1|max:100',
|
'limit' => 'sometimes|integer|min:1',
|
||||||
'min_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX,
|
'min_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX,
|
||||||
'max_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX,
|
'max_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX,
|
||||||
'since_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX,
|
'since_id' => 'nullable|integer|min:1|max:'.PHP_INT_MAX,
|
||||||
|
@ -2191,6 +2250,9 @@ class ApiV1Controller extends Controller
|
||||||
|
|
||||||
$pid = $request->user()->profile_id;
|
$pid = $request->user()->profile_id;
|
||||||
$limit = $request->input('limit', 20);
|
$limit = $request->input('limit', 20);
|
||||||
|
if($limit > 40) {
|
||||||
|
$limit = 40;
|
||||||
|
}
|
||||||
|
|
||||||
$since = $request->input('since_id');
|
$since = $request->input('since_id');
|
||||||
$min = $request->input('min_id');
|
$min = $request->input('min_id');
|
||||||
|
@ -2200,6 +2262,10 @@ class ApiV1Controller extends Controller
|
||||||
$min = 1;
|
$min = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($since) {
|
||||||
|
$min = $since + 1;
|
||||||
|
}
|
||||||
|
|
||||||
$types = $request->input('types');
|
$types = $request->input('types');
|
||||||
|
|
||||||
$maxId = null;
|
$maxId = null;
|
||||||
|
@ -2261,7 +2327,7 @@ class ApiV1Controller extends Controller
|
||||||
'page' => 'sometimes|integer|max:40',
|
'page' => 'sometimes|integer|max:40',
|
||||||
'min_id' => 'sometimes|integer|min:0|max:' . PHP_INT_MAX,
|
'min_id' => 'sometimes|integer|min:0|max:' . PHP_INT_MAX,
|
||||||
'max_id' => 'sometimes|integer|min:0|max:' . PHP_INT_MAX,
|
'max_id' => 'sometimes|integer|min:0|max:' . PHP_INT_MAX,
|
||||||
'limit' => 'sometimes|integer|min:1|max:40',
|
'limit' => 'sometimes|integer|min:1',
|
||||||
'include_reblogs' => 'sometimes',
|
'include_reblogs' => 'sometimes',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -2270,6 +2336,9 @@ class ApiV1Controller extends Controller
|
||||||
$min = $request->input('min_id');
|
$min = $request->input('min_id');
|
||||||
$max = $request->input('max_id');
|
$max = $request->input('max_id');
|
||||||
$limit = $request->input('limit') ?? 20;
|
$limit = $request->input('limit') ?? 20;
|
||||||
|
if($limit > 40) {
|
||||||
|
$limit = 40;
|
||||||
|
}
|
||||||
$pid = $request->user()->profile_id;
|
$pid = $request->user()->profile_id;
|
||||||
$includeReblogs = $request->filled('include_reblogs') ? $request->boolean('include_reblogs') : false;
|
$includeReblogs = $request->filled('include_reblogs') ? $request->boolean('include_reblogs') : false;
|
||||||
$nullFields = $includeReblogs ?
|
$nullFields = $includeReblogs ?
|
||||||
|
@ -2515,7 +2584,7 @@ class ApiV1Controller extends Controller
|
||||||
$this->validate($request,[
|
$this->validate($request,[
|
||||||
'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
||||||
'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
||||||
'limit' => 'nullable|integer|max:100',
|
'limit' => 'sometimes|integer|min:1',
|
||||||
'remote' => 'sometimes',
|
'remote' => 'sometimes',
|
||||||
'local' => 'sometimes'
|
'local' => 'sometimes'
|
||||||
]);
|
]);
|
||||||
|
@ -2525,6 +2594,9 @@ class ApiV1Controller extends Controller
|
||||||
$max = $request->input('max_id');
|
$max = $request->input('max_id');
|
||||||
$minOrMax = $request->anyFilled(['max_id', 'min_id']);
|
$minOrMax = $request->anyFilled(['max_id', 'min_id']);
|
||||||
$limit = $request->input('limit') ?? 20;
|
$limit = $request->input('limit') ?? 20;
|
||||||
|
if($limit > 40) {
|
||||||
|
$limit = 40;
|
||||||
|
}
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
|
|
||||||
$remote = $request->has('remote');
|
$remote = $request->has('remote');
|
||||||
|
@ -3043,10 +3115,13 @@ class ApiV1Controller extends Controller
|
||||||
abort_unless($request->user()->tokenCan('read'), 403);
|
abort_unless($request->user()->tokenCan('read'), 403);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'limit' => 'nullable|integer|min:1|max:80'
|
'limit' => 'sometimes|integer|min:1'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$limit = $request->input('limit', 10);
|
$limit = $request->input('limit', 40);
|
||||||
|
if($limit > 80) {
|
||||||
|
$limit = 80;
|
||||||
|
}
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
$pid = $user->profile_id;
|
$pid = $user->profile_id;
|
||||||
$status = Status::findOrFail($id);
|
$status = Status::findOrFail($id);
|
||||||
|
@ -3485,7 +3560,7 @@ class ApiV1Controller extends Controller
|
||||||
'page' => 'nullable|integer|max:40',
|
'page' => 'nullable|integer|max:40',
|
||||||
'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
||||||
'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
|
||||||
'limit' => 'nullable|integer|max:100',
|
'limit' => 'sometimes|integer|min:1',
|
||||||
'only_media' => 'sometimes|boolean',
|
'only_media' => 'sometimes|boolean',
|
||||||
'_pe' => 'sometimes'
|
'_pe' => 'sometimes'
|
||||||
]);
|
]);
|
||||||
|
@ -3518,6 +3593,9 @@ class ApiV1Controller extends Controller
|
||||||
$min = $request->input('min_id');
|
$min = $request->input('min_id');
|
||||||
$max = $request->input('max_id');
|
$max = $request->input('max_id');
|
||||||
$limit = $request->input('limit', 20);
|
$limit = $request->input('limit', 20);
|
||||||
|
if($limit > 40) {
|
||||||
|
$limit = 40;
|
||||||
|
}
|
||||||
$onlyMedia = $request->input('only_media', true);
|
$onlyMedia = $request->input('only_media', true);
|
||||||
$pe = $request->has(self::PF_API_ENTITY_KEY);
|
$pe = $request->has(self::PF_API_ENTITY_KEY);
|
||||||
$pid = $request->user()->profile_id;
|
$pid = $request->user()->profile_id;
|
||||||
|
@ -3547,7 +3625,7 @@ class ApiV1Controller extends Controller
|
||||||
->whereStatusVisibility('public')
|
->whereStatusVisibility('public')
|
||||||
->where('status_id', $dir, $id)
|
->where('status_id', $dir, $id)
|
||||||
->orderBy('status_id', 'desc')
|
->orderBy('status_id', 'desc')
|
||||||
->limit($limit)
|
->limit(100)
|
||||||
->pluck('status_id')
|
->pluck('status_id')
|
||||||
->map(function ($i) use($pe) {
|
->map(function ($i) use($pe) {
|
||||||
return $pe ? StatusService::get($i) : StatusService::getMastodon($i);
|
return $pe ? StatusService::get($i) : StatusService::getMastodon($i);
|
||||||
|
@ -3565,6 +3643,7 @@ class ApiV1Controller extends Controller
|
||||||
$domain = strtolower(parse_url($i['url'], PHP_URL_HOST));
|
$domain = strtolower(parse_url($i['url'], PHP_URL_HOST));
|
||||||
return !in_array($i['account']['id'], $filters) && !in_array($domain, $domainBlocks);
|
return !in_array($i['account']['id'], $filters) && !in_array($domain, $domainBlocks);
|
||||||
})
|
})
|
||||||
|
->take($limit)
|
||||||
->values()
|
->values()
|
||||||
->toArray();
|
->toArray();
|
||||||
|
|
||||||
|
@ -3584,7 +3663,7 @@ class ApiV1Controller extends Controller
|
||||||
abort_unless($request->user()->tokenCan('read'), 403);
|
abort_unless($request->user()->tokenCan('read'), 403);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'limit' => 'nullable|integer|min:1|max:40',
|
'limit' => 'sometimes|integer|min:1',
|
||||||
'max_id' => 'nullable|integer|min:0',
|
'max_id' => 'nullable|integer|min:0',
|
||||||
'since_id' => 'nullable|integer|min:0',
|
'since_id' => 'nullable|integer|min:0',
|
||||||
'min_id' => 'nullable|integer|min:0'
|
'min_id' => 'nullable|integer|min:0'
|
||||||
|
@ -3593,6 +3672,9 @@ class ApiV1Controller extends Controller
|
||||||
$pe = $request->has('_pe');
|
$pe = $request->has('_pe');
|
||||||
$pid = $request->user()->profile_id;
|
$pid = $request->user()->profile_id;
|
||||||
$limit = $request->input('limit') ?? 20;
|
$limit = $request->input('limit') ?? 20;
|
||||||
|
if($limit > 40) {
|
||||||
|
$limit = 40;
|
||||||
|
}
|
||||||
$max_id = $request->input('max_id');
|
$max_id = $request->input('max_id');
|
||||||
$since_id = $request->input('since_id');
|
$since_id = $request->input('since_id');
|
||||||
$min_id = $request->input('min_id');
|
$min_id = $request->input('min_id');
|
||||||
|
@ -3758,11 +3840,14 @@ class ApiV1Controller extends Controller
|
||||||
abort_if(!$request->user(), 403);
|
abort_if(!$request->user(), 403);
|
||||||
|
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'limit' => 'int|min:1|max:10',
|
'limit' => 'sometimes|integer|min:1',
|
||||||
'sort' => 'in:all,newest,popular'
|
'sort' => 'in:all,newest,popular'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$limit = $request->input('limit', 3);
|
$limit = $request->input('limit', 3);
|
||||||
|
if($limit > 10) {
|
||||||
|
$limit = 10;
|
||||||
|
}
|
||||||
$pid = $request->user()->profile_id;
|
$pid = $request->user()->profile_id;
|
||||||
$status = StatusService::getMastodon($id, false);
|
$status = StatusService::getMastodon($id, false);
|
||||||
|
|
||||||
|
|
|
@ -71,10 +71,11 @@ class ApiV2Controller extends Controller
|
||||||
->toArray() : [];
|
->toArray() : [];
|
||||||
});
|
});
|
||||||
|
|
||||||
$res = [
|
$res = Cache::remember('api:v2:instance-data-response-v2', 1800, function () use($contact, $rules) {
|
||||||
|
return [
|
||||||
'domain' => config('pixelfed.domain.app'),
|
'domain' => config('pixelfed.domain.app'),
|
||||||
'title' => config_cache('app.name'),
|
'title' => config_cache('app.name'),
|
||||||
'version' => config('pixelfed.version'),
|
'version' => '3.5.3 (compatible; Pixelfed ' . config('pixelfed.version') .')',
|
||||||
'source_url' => 'https://github.com/pixelfed/pixelfed',
|
'source_url' => 'https://github.com/pixelfed/pixelfed',
|
||||||
'description' => config_cache('app.short_description'),
|
'description' => config_cache('app.short_description'),
|
||||||
'usage' => [
|
'usage' => [
|
||||||
|
@ -93,7 +94,7 @@ class ApiV2Controller extends Controller
|
||||||
'languages' => [config('app.locale')],
|
'languages' => [config('app.locale')],
|
||||||
'configuration' => [
|
'configuration' => [
|
||||||
'urls' => [
|
'urls' => [
|
||||||
'streaming' => 'wss://' . config('pixelfed.domain.app'),
|
'streaming' => null,
|
||||||
'status' => null
|
'status' => null
|
||||||
],
|
],
|
||||||
'vapid' => [
|
'vapid' => [
|
||||||
|
@ -116,19 +117,20 @@ class ApiV2Controller extends Controller
|
||||||
'video_matrix_limit' => 3686400
|
'video_matrix_limit' => 3686400
|
||||||
],
|
],
|
||||||
'polls' => [
|
'polls' => [
|
||||||
'max_options' => 4,
|
'max_options' => 0,
|
||||||
'max_characters_per_option' => 50,
|
'max_characters_per_option' => 0,
|
||||||
'min_expiration' => 300,
|
'min_expiration' => 0,
|
||||||
'max_expiration' => 2629746,
|
'max_expiration' => 0,
|
||||||
],
|
],
|
||||||
'translation' => [
|
'translation' => [
|
||||||
'enabled' => false,
|
'enabled' => false,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'registrations' => [
|
'registrations' => [
|
||||||
'enabled' => (bool) config_cache('pixelfed.open_registration'),
|
'enabled' => null,
|
||||||
'approval_required' => false,
|
'approval_required' => false,
|
||||||
'message' => null
|
'message' => null,
|
||||||
|
'url' => null,
|
||||||
],
|
],
|
||||||
'contact' => [
|
'contact' => [
|
||||||
'email' => config('instance.email'),
|
'email' => config('instance.email'),
|
||||||
|
@ -136,7 +138,10 @@ class ApiV2Controller extends Controller
|
||||||
],
|
],
|
||||||
'rules' => $rules
|
'rules' => $rules
|
||||||
];
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
$res['registrations']['enabled'] = (bool) config_cache('pixelfed.open_registration');
|
||||||
|
$res['registrations']['approval_required'] = (bool) config_cache('instance.curated_registration.enabled');
|
||||||
return response()->json($res, 200, [], JSON_UNESCAPED_SLASHES);
|
return response()->json($res, 200, [], JSON_UNESCAPED_SLASHES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,7 @@ class RegisterController extends Controller
|
||||||
*/
|
*/
|
||||||
public function showRegistrationForm()
|
public function showRegistrationForm()
|
||||||
{
|
{
|
||||||
if(config_cache('pixelfed.open_registration')) {
|
if((bool) config_cache('pixelfed.open_registration')) {
|
||||||
if(config('pixelfed.bouncer.cloud_ips.ban_signups')) {
|
if(config('pixelfed.bouncer.cloud_ips.ban_signups')) {
|
||||||
abort_if(BouncerService::checkIp(request()->ip()), 404);
|
abort_if(BouncerService::checkIp(request()->ip()), 404);
|
||||||
}
|
}
|
||||||
|
@ -190,10 +190,14 @@ class RegisterController extends Controller
|
||||||
} else {
|
} else {
|
||||||
return view('auth.register');
|
return view('auth.register');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if((bool) config_cache('instance.curated_registration.enabled') && config('instance.curated_registration.state.fallback_on_closed_reg')) {
|
||||||
|
return redirect('/auth/sign_up');
|
||||||
} else {
|
} else {
|
||||||
abort(404);
|
abort(404);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a registration request for the application.
|
* Handle a registration request for the application.
|
||||||
|
|
398
app/Http/Controllers/CuratedRegisterController.php
Normal file
398
app/Http/Controllers/CuratedRegisterController.php
Normal file
|
@ -0,0 +1,398 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use App\User;
|
||||||
|
use App\Models\CuratedRegister;
|
||||||
|
use App\Models\CuratedRegisterActivity;
|
||||||
|
use App\Services\EmailService;
|
||||||
|
use App\Services\BouncerService;
|
||||||
|
use App\Util\Lexer\RestrictedNames;
|
||||||
|
use App\Mail\CuratedRegisterConfirmEmail;
|
||||||
|
use App\Mail\CuratedRegisterNotifyAdmin;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use App\Jobs\CuratedOnboarding\CuratedOnboardingNotifyAdminNewApplicationPipeline;
|
||||||
|
|
||||||
|
class CuratedRegisterController extends Controller
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
abort_unless((bool) config_cache('instance.curated_registration.enabled'), 404);
|
||||||
|
|
||||||
|
if((bool) config_cache('pixelfed.open_registration')) {
|
||||||
|
abort_if(config('instance.curated_registration.state.only_enabled_on_closed_reg'), 404);
|
||||||
|
} else {
|
||||||
|
abort_unless(config('instance.curated_registration.state.fallback_on_closed_reg'), 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index(Request $request)
|
||||||
|
{
|
||||||
|
abort_if($request->user(), 404);
|
||||||
|
return view('auth.curated-register.index', ['step' => 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function concierge(Request $request)
|
||||||
|
{
|
||||||
|
abort_if($request->user(), 404);
|
||||||
|
$emailConfirmed = $request->session()->has('cur-reg-con.email-confirmed') &&
|
||||||
|
$request->has('next') &&
|
||||||
|
$request->session()->has('cur-reg-con.cr-id');
|
||||||
|
return view('auth.curated-register.concierge', compact('emailConfirmed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function conciergeResponseSent(Request $request)
|
||||||
|
{
|
||||||
|
return view('auth.curated-register.user_response_sent');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function conciergeFormShow(Request $request)
|
||||||
|
{
|
||||||
|
abort_if($request->user(), 404);
|
||||||
|
abort_unless(
|
||||||
|
$request->session()->has('cur-reg-con.email-confirmed') &&
|
||||||
|
$request->session()->has('cur-reg-con.cr-id') &&
|
||||||
|
$request->session()->has('cur-reg-con.ac-id'), 404);
|
||||||
|
$crid = $request->session()->get('cur-reg-con.cr-id');
|
||||||
|
$arid = $request->session()->get('cur-reg-con.ac-id');
|
||||||
|
$showCaptcha = config('instance.curated_registration.captcha_enabled');
|
||||||
|
if($attempts = $request->session()->get('cur-reg-con-attempt')) {
|
||||||
|
$showCaptcha = $attempts && $attempts >= 2;
|
||||||
|
} else {
|
||||||
|
$showCaptcha = false;
|
||||||
|
}
|
||||||
|
$activity = CuratedRegisterActivity::whereRegisterId($crid)->whereFromAdmin(true)->findOrFail($arid);
|
||||||
|
return view('auth.curated-register.concierge_form', compact('activity', 'showCaptcha'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function conciergeFormStore(Request $request)
|
||||||
|
{
|
||||||
|
abort_if($request->user(), 404);
|
||||||
|
$request->session()->increment('cur-reg-con-attempt');
|
||||||
|
abort_unless(
|
||||||
|
$request->session()->has('cur-reg-con.email-confirmed') &&
|
||||||
|
$request->session()->has('cur-reg-con.cr-id') &&
|
||||||
|
$request->session()->has('cur-reg-con.ac-id'), 404);
|
||||||
|
$attempts = $request->session()->get('cur-reg-con-attempt');
|
||||||
|
$messages = [];
|
||||||
|
$rules = [
|
||||||
|
'response' => 'required|string|min:5|max:1000',
|
||||||
|
'crid' => 'required|integer|min:1',
|
||||||
|
'acid' => 'required|integer|min:1'
|
||||||
|
];
|
||||||
|
if(config('instance.curated_registration.captcha_enabled') && $attempts >= 3) {
|
||||||
|
$rules['h-captcha-response'] = 'required|captcha';
|
||||||
|
$messages['h-captcha-response.required'] = 'The captcha must be filled';
|
||||||
|
}
|
||||||
|
$this->validate($request, $rules, $messages);
|
||||||
|
$crid = $request->session()->get('cur-reg-con.cr-id');
|
||||||
|
$acid = $request->session()->get('cur-reg-con.ac-id');
|
||||||
|
abort_if((string) $crid !== $request->input('crid'), 404);
|
||||||
|
abort_if((string) $acid !== $request->input('acid'), 404);
|
||||||
|
|
||||||
|
if(CuratedRegisterActivity::whereRegisterId($crid)->whereReplyToId($acid)->exists()) {
|
||||||
|
return redirect()->back()->withErrors(['code' => 'You already replied to this request.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$act = CuratedRegisterActivity::create([
|
||||||
|
'register_id' => $crid,
|
||||||
|
'reply_to_id' => $acid,
|
||||||
|
'type' => 'user_response',
|
||||||
|
'message' => $request->input('response'),
|
||||||
|
'from_user' => true,
|
||||||
|
'action_required' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$request->session()->pull('cur-reg-con');
|
||||||
|
$request->session()->pull('cur-reg-con-attempt');
|
||||||
|
|
||||||
|
return view('auth.curated-register.user_response_sent');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function conciergeStore(Request $request)
|
||||||
|
{
|
||||||
|
abort_if($request->user(), 404);
|
||||||
|
$rules = [
|
||||||
|
'sid' => 'required_if:action,email|integer|min:1|max:20000000',
|
||||||
|
'id' => 'required_if:action,email|integer|min:1|max:20000000',
|
||||||
|
'code' => 'required_if:action,email',
|
||||||
|
'action' => 'required|string|in:email,message',
|
||||||
|
'email' => 'required_if:action,email|email',
|
||||||
|
'response' => 'required_if:action,message|string|min:20|max:1000',
|
||||||
|
];
|
||||||
|
$messages = [];
|
||||||
|
if(config('instance.curated_registration.captcha_enabled')) {
|
||||||
|
$rules['h-captcha-response'] = 'required|captcha';
|
||||||
|
$messages['h-captcha-response.required'] = 'The captcha must be filled';
|
||||||
|
}
|
||||||
|
$this->validate($request, $rules, $messages);
|
||||||
|
|
||||||
|
$action = $request->input('action');
|
||||||
|
$sid = $request->input('sid');
|
||||||
|
$id = $request->input('id');
|
||||||
|
$code = $request->input('code');
|
||||||
|
$email = $request->input('email');
|
||||||
|
|
||||||
|
$cr = CuratedRegister::whereIsClosed(false)->findOrFail($sid);
|
||||||
|
$ac = CuratedRegisterActivity::whereRegisterId($cr->id)->whereFromAdmin(true)->findOrFail($id);
|
||||||
|
|
||||||
|
if(!hash_equals($ac->secret_code, $code)) {
|
||||||
|
return redirect()->back()->withErrors(['code' => 'Invalid code']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!hash_equals($cr->email, $email)) {
|
||||||
|
return redirect()->back()->withErrors(['email' => 'Invalid email']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$request->session()->put('cur-reg-con.email-confirmed', true);
|
||||||
|
$request->session()->put('cur-reg-con.cr-id', $cr->id);
|
||||||
|
$request->session()->put('cur-reg-con.ac-id', $ac->id);
|
||||||
|
$emailConfirmed = true;
|
||||||
|
return redirect('/auth/sign_up/concierge/form');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function confirmEmail(Request $request)
|
||||||
|
{
|
||||||
|
if($request->user()) {
|
||||||
|
return redirect(route('help.email-confirmation-issues'));
|
||||||
|
}
|
||||||
|
return view('auth.curated-register.confirm_email');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function emailConfirmed(Request $request)
|
||||||
|
{
|
||||||
|
if($request->user()) {
|
||||||
|
return redirect(route('help.email-confirmation-issues'));
|
||||||
|
}
|
||||||
|
return view('auth.curated-register.email_confirmed');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resendConfirmation(Request $request)
|
||||||
|
{
|
||||||
|
return view('auth.curated-register.resend-confirmation');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function resendConfirmationProcess(Request $request)
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'email' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
app()->environment() === 'production' ? 'email:rfc,dns,spoof' : 'email',
|
||||||
|
'exists:curated_registers',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$messages = [];
|
||||||
|
|
||||||
|
if(config('instance.curated_registration.captcha_enabled')) {
|
||||||
|
$rules['h-captcha-response'] = 'required|captcha';
|
||||||
|
$messages['h-captcha-response.required'] = 'The captcha must be filled';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->validate($request, $rules, $messages);
|
||||||
|
|
||||||
|
$cur = CuratedRegister::whereEmail($request->input('email'))->whereIsClosed(false)->first();
|
||||||
|
if(!$cur) {
|
||||||
|
return redirect()->back()->withErrors(['email' => 'The selected email is invalid.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$totalCount = CuratedRegisterActivity::whereRegisterId($cur->id)
|
||||||
|
->whereType('user_resend_email_confirmation')
|
||||||
|
->count();
|
||||||
|
|
||||||
|
if($totalCount && $totalCount >= config('instance.curated_registration.resend_confirmation_limit')) {
|
||||||
|
return redirect()->back()->withErrors(['email' => 'You have re-attempted too many times. To proceed with your application, please <a href="/site/contact" class="text-white" style="text-decoration: underline;">contact the admin team</a>.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = CuratedRegisterActivity::whereRegisterId($cur->id)
|
||||||
|
->whereType('user_resend_email_confirmation')
|
||||||
|
->where('created_at', '>', now()->subHours(12))
|
||||||
|
->count();
|
||||||
|
|
||||||
|
if($count) {
|
||||||
|
return redirect()->back()->withErrors(['email' => 'You can only re-send the confirmation email once per 12 hours. Try again later.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
CuratedRegisterActivity::create([
|
||||||
|
'register_id' => $cur->id,
|
||||||
|
'type' => 'user_resend_email_confirmation',
|
||||||
|
'admin_only_view' => true,
|
||||||
|
'from_admin' => false,
|
||||||
|
'from_user' => false,
|
||||||
|
'action_required' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Mail::to($cur->email)->send(new CuratedRegisterConfirmEmail($cur));
|
||||||
|
return view('auth.curated-register.resent-confirmation');
|
||||||
|
return $request->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function confirmEmailHandle(Request $request)
|
||||||
|
{
|
||||||
|
$rules = [
|
||||||
|
'sid' => 'required',
|
||||||
|
'code' => 'required'
|
||||||
|
];
|
||||||
|
$messages = [];
|
||||||
|
if(config('instance.curated_registration.captcha_enabled')) {
|
||||||
|
$rules['h-captcha-response'] = 'required|captcha';
|
||||||
|
$messages['h-captcha-response.required'] = 'The captcha must be filled';
|
||||||
|
}
|
||||||
|
$this->validate($request, $rules, $messages);
|
||||||
|
|
||||||
|
$cr = CuratedRegister::whereNull('email_verified_at')
|
||||||
|
->where('created_at', '>', now()->subHours(24))
|
||||||
|
->find($request->input('sid'));
|
||||||
|
if(!$cr) {
|
||||||
|
return redirect(route('help.email-confirmation-issues'));
|
||||||
|
}
|
||||||
|
if(!hash_equals($cr->verify_code, $request->input('code'))) {
|
||||||
|
return redirect(route('help.email-confirmation-issues'));
|
||||||
|
}
|
||||||
|
$cr->email_verified_at = now();
|
||||||
|
$cr->save();
|
||||||
|
|
||||||
|
if(config('instance.curated_registration.notify.admin.on_verify_email.enabled')) {
|
||||||
|
CuratedOnboardingNotifyAdminNewApplicationPipeline::dispatch($cr);
|
||||||
|
}
|
||||||
|
return view('auth.curated-register.email_confirmed');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function proceed(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'step' => 'required|integer|in:1,2,3,4'
|
||||||
|
]);
|
||||||
|
$step = $request->input('step');
|
||||||
|
|
||||||
|
switch($step) {
|
||||||
|
case 1:
|
||||||
|
$step = 2;
|
||||||
|
$request->session()->put('cur-step', 1);
|
||||||
|
return view('auth.curated-register.index', compact('step'));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
$this->stepTwo($request);
|
||||||
|
$step = 3;
|
||||||
|
$request->session()->put('cur-step', 2);
|
||||||
|
return view('auth.curated-register.index', compact('step'));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
$this->stepThree($request);
|
||||||
|
$step = 3;
|
||||||
|
$request->session()->put('cur-step', 3);
|
||||||
|
$verifiedEmail = true;
|
||||||
|
$request->session()->pull('cur-reg');
|
||||||
|
return view('auth.curated-register.index', compact('step', 'verifiedEmail'));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function stepTwo($request)
|
||||||
|
{
|
||||||
|
if($request->filled('reason')) {
|
||||||
|
$request->session()->put('cur-reg.form-reason', $request->input('reason'));
|
||||||
|
}
|
||||||
|
if($request->filled('username')) {
|
||||||
|
$request->session()->put('cur-reg.form-username', $request->input('username'));
|
||||||
|
}
|
||||||
|
if($request->filled('email')) {
|
||||||
|
$request->session()->put('cur-reg.form-email', $request->input('email'));
|
||||||
|
}
|
||||||
|
$this->validate($request, [
|
||||||
|
'username' => [
|
||||||
|
'required',
|
||||||
|
'min:2',
|
||||||
|
'max:15',
|
||||||
|
'unique:curated_registers',
|
||||||
|
'unique:users',
|
||||||
|
function ($attribute, $value, $fail) {
|
||||||
|
$dash = substr_count($value, '-');
|
||||||
|
$underscore = substr_count($value, '_');
|
||||||
|
$period = substr_count($value, '.');
|
||||||
|
|
||||||
|
if(ends_with($value, ['.php', '.js', '.css'])) {
|
||||||
|
return $fail('Username is invalid.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(($dash + $underscore + $period) > 1) {
|
||||||
|
return $fail('Username is invalid. Can only contain one dash (-), period (.) or underscore (_).');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctype_alnum($value[0])) {
|
||||||
|
return $fail('Username is invalid. Must start with a letter or number.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctype_alnum($value[strlen($value) - 1])) {
|
||||||
|
return $fail('Username is invalid. Must end with a letter or number.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$val = str_replace(['_', '.', '-'], '', $value);
|
||||||
|
if(!ctype_alnum($val)) {
|
||||||
|
return $fail('Username is invalid. Username must be alpha-numeric and may contain dashes (-), periods (.) and underscores (_).');
|
||||||
|
}
|
||||||
|
|
||||||
|
$restricted = RestrictedNames::get();
|
||||||
|
if (in_array(strtolower($value), array_map('strtolower', $restricted))) {
|
||||||
|
return $fail('Username cannot be used.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'email' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
app()->environment() === 'production' ? 'email:rfc,dns,spoof' : 'email',
|
||||||
|
'max:255',
|
||||||
|
'unique:users',
|
||||||
|
'unique:curated_registers',
|
||||||
|
function ($attribute, $value, $fail) {
|
||||||
|
$banned = EmailService::isBanned($value);
|
||||||
|
if($banned) {
|
||||||
|
return $fail('Email is invalid.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'password' => 'required|min:8',
|
||||||
|
'password_confirmation' => 'required|same:password',
|
||||||
|
'reason' => 'required|min:20|max:1000',
|
||||||
|
'agree' => 'required|accepted'
|
||||||
|
]);
|
||||||
|
$request->session()->put('cur-reg.form-email', $request->input('email'));
|
||||||
|
$request->session()->put('cur-reg.form-password', $request->input('password'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function stepThree($request)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'email' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
app()->environment() === 'production' ? 'email:rfc,dns,spoof' : 'email',
|
||||||
|
'max:255',
|
||||||
|
'unique:users',
|
||||||
|
'unique:curated_registers',
|
||||||
|
function ($attribute, $value, $fail) {
|
||||||
|
$banned = EmailService::isBanned($value);
|
||||||
|
if($banned) {
|
||||||
|
return $fail('Email is invalid.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
$cr = new CuratedRegister;
|
||||||
|
$cr->email = $request->email;
|
||||||
|
$cr->username = $request->session()->get('cur-reg.form-username');
|
||||||
|
$cr->password = bcrypt($request->session()->get('cur-reg.form-password'));
|
||||||
|
$cr->ip_address = $request->ip();
|
||||||
|
$cr->reason_to_join = $request->session()->get('cur-reg.form-reason');
|
||||||
|
$cr->verify_code = Str::random(40);
|
||||||
|
$cr->save();
|
||||||
|
|
||||||
|
Mail::to($cr->email)->send(new CuratedRegisterConfirmEmail($cr));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\CuratedOnboarding;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use App\Models\CuratedRegister;
|
||||||
|
use App\User;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use App\Mail\CuratedRegisterNotifyAdmin;
|
||||||
|
|
||||||
|
class CuratedOnboardingNotifyAdminNewApplicationPipeline implements ShouldQueue
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $cr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*/
|
||||||
|
public function __construct(CuratedRegister $cr)
|
||||||
|
{
|
||||||
|
$this->cr = $cr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*/
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
if(!config('instance.curated_registration.notify.admin.on_verify_email.enabled')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
config('instance.curated_registration.notify.admin.on_verify_email.bundle') ?
|
||||||
|
$this->handleBundled() :
|
||||||
|
$this->handleUnbundled();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleBundled()
|
||||||
|
{
|
||||||
|
$cr = $this->cr;
|
||||||
|
Storage::append('conanap.json', json_encode([
|
||||||
|
'id' => $cr->id,
|
||||||
|
'email' => $cr->email,
|
||||||
|
'created_at' => $cr->created_at,
|
||||||
|
'updated_at' => $cr->updated_at,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleUnbundled()
|
||||||
|
{
|
||||||
|
$cr = $this->cr;
|
||||||
|
if($aid = config_cache('instance.admin.pid')) {
|
||||||
|
$admin = User::whereProfileId($aid)->first();
|
||||||
|
if($admin && $admin->email) {
|
||||||
|
Mail::to($admin->email)->send(new CuratedRegisterNotifyAdmin($cr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
app/Mail/CuratedRegisterAcceptUser.php
Normal file
55
app/Mail/CuratedRegisterAcceptUser.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class CuratedRegisterAcceptUser extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $verify;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*/
|
||||||
|
public function __construct($verify)
|
||||||
|
{
|
||||||
|
$this->verify = $verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message envelope.
|
||||||
|
*/
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
subject: 'Your ' . config('pixelfed.domain.app') . ' Registration Update',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message content definition.
|
||||||
|
*/
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
markdown: 'emails.curated-register.request-accepted',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachments for the message.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||||
|
*/
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
55
app/Mail/CuratedRegisterConfirmEmail.php
Normal file
55
app/Mail/CuratedRegisterConfirmEmail.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use App\Models\CuratedRegister;
|
||||||
|
|
||||||
|
class CuratedRegisterConfirmEmail extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
public $verify;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*/
|
||||||
|
public function __construct(CuratedRegister $verify)
|
||||||
|
{
|
||||||
|
$this->verify = $verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message envelope.
|
||||||
|
*/
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
subject: 'Welcome to Pixelfed! Please Confirm Your Email',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message content definition.
|
||||||
|
*/
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
markdown: 'emails.curated-register.confirm_email',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachments for the message.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||||
|
*/
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
55
app/Mail/CuratedRegisterNotifyAdmin.php
Normal file
55
app/Mail/CuratedRegisterNotifyAdmin.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use App\Models\CuratedRegister;
|
||||||
|
|
||||||
|
class CuratedRegisterNotifyAdmin extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
public $verify;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*/
|
||||||
|
public function __construct(CuratedRegister $verify)
|
||||||
|
{
|
||||||
|
$this->verify = $verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message envelope.
|
||||||
|
*/
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
subject: '[Requires Action]: New Curated Onboarding Application',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message content definition.
|
||||||
|
*/
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
markdown: 'emails.curated-register.admin_notify',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachments for the message.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||||
|
*/
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
55
app/Mail/CuratedRegisterNotifyAdminUserResponse.php
Normal file
55
app/Mail/CuratedRegisterNotifyAdminUserResponse.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class CuratedRegisterNotifyAdminUserResponse extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $activity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*/
|
||||||
|
public function __construct($activity)
|
||||||
|
{
|
||||||
|
$this->activity = $activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message envelope.
|
||||||
|
*/
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
subject: 'Curated Register Notify Admin User Response',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message content definition.
|
||||||
|
*/
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
markdown: 'emails.curated-register.admin_notify_user_response',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachments for the message.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||||
|
*/
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
55
app/Mail/CuratedRegisterRejectUser.php
Normal file
55
app/Mail/CuratedRegisterRejectUser.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class CuratedRegisterRejectUser extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $verify;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*/
|
||||||
|
public function __construct($verify)
|
||||||
|
{
|
||||||
|
$this->verify = $verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message envelope.
|
||||||
|
*/
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
subject: 'Your ' . config('pixelfed.domain.app') . ' Registration Update',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message content definition.
|
||||||
|
*/
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
markdown: 'emails.curated-register.request-rejected',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachments for the message.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||||
|
*/
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
58
app/Mail/CuratedRegisterRequestDetailsFromUser.php
Normal file
58
app/Mail/CuratedRegisterRequestDetailsFromUser.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
use App\Models\CuratedRegister;
|
||||||
|
use App\Models\CuratedRegisterActivity;
|
||||||
|
|
||||||
|
class CuratedRegisterRequestDetailsFromUser extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
public $verify;
|
||||||
|
public $activity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*/
|
||||||
|
public function __construct(CuratedRegister $verify, CuratedRegisterActivity $activity)
|
||||||
|
{
|
||||||
|
$this->verify = $verify;
|
||||||
|
$this->activity = $activity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message envelope.
|
||||||
|
*/
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
subject: '[Action Needed]: Additional information requested',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message content definition.
|
||||||
|
*/
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
markdown: 'emails.curated-register.request-details-from-user',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachments for the message.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||||
|
*/
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
55
app/Mail/CuratedRegisterSendMessage.php
Normal file
55
app/Mail/CuratedRegisterSendMessage.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class CuratedRegisterSendMessage extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $verify;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*/
|
||||||
|
public function __construct($verify)
|
||||||
|
{
|
||||||
|
$this->verify = $verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message envelope.
|
||||||
|
*/
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
subject: 'Your ' . config('pixelfed.domain.app') . ' Registration Update',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message content definition.
|
||||||
|
*/
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
markdown: 'emails.curated-register.message-from-admin',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachments for the message.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||||
|
*/
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
49
app/Models/CuratedRegister.php
Normal file
49
app/Models/CuratedRegister.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class CuratedRegister extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'autofollow_account_ids' => 'array',
|
||||||
|
'admin_notes' => 'array',
|
||||||
|
'email_verified_at' => 'datetime',
|
||||||
|
'admin_notified_at' => 'datetime',
|
||||||
|
'action_taken_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function adminStatusLabel()
|
||||||
|
{
|
||||||
|
if(!$this->email_verified_at) {
|
||||||
|
return '<span class="border border-danger px-3 py-1 rounded text-white font-weight-bold">Unverified email</span>';
|
||||||
|
}
|
||||||
|
if($this->is_accepted) { return 'Approved'; }
|
||||||
|
if($this->is_rejected) { return 'Rejected'; }
|
||||||
|
if($this->is_awaiting_more_info ) {
|
||||||
|
return '<span class="border border-info px-3 py-1 rounded text-white font-weight-bold">Awaiting Details</span>';
|
||||||
|
}
|
||||||
|
if($this->is_closed ) { return 'Closed'; }
|
||||||
|
|
||||||
|
return '<span class="border border-success px-3 py-1 rounded text-white font-weight-bold">Open</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function emailConfirmUrl()
|
||||||
|
{
|
||||||
|
return url('/auth/sign_up/confirm?sid=' . $this->id . '&code=' . $this->verify_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function emailReplyUrl()
|
||||||
|
{
|
||||||
|
return url('/auth/sign_up/concierge?sid=' . $this->id . '&code=' . $this->verify_code . '&sc=' . str_random(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function adminReviewUrl()
|
||||||
|
{
|
||||||
|
return url('/i/admin/curated-onboarding/show/' . $this->id);
|
||||||
|
}
|
||||||
|
}
|
38
app/Models/CuratedRegisterActivity.php
Normal file
38
app/Models/CuratedRegisterActivity.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class CuratedRegisterActivity extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $guarded = [];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'metadata' => 'array',
|
||||||
|
'admin_notified_at' => 'datetime',
|
||||||
|
'action_taken_at' => 'datetime',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function application()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(CuratedRegister::class, 'register_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function emailReplyUrl()
|
||||||
|
{
|
||||||
|
return url('/auth/sign_up/concierge?sid='.$this->register_id . '&id=' . $this->id . '&code=' . $this->secret_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function adminReviewUrl()
|
||||||
|
{
|
||||||
|
$url = '/i/admin/curated-onboarding/show/' . $this->register_id . '/?ah=' . $this->id;
|
||||||
|
if($this->reply_to_id) {
|
||||||
|
$url .= '&rtid=' . $this->reply_to_id;
|
||||||
|
}
|
||||||
|
return url($url);
|
||||||
|
}
|
||||||
|
}
|
|
@ -72,6 +72,8 @@ class ConfigCacheService
|
||||||
'instance.banner.blurhash',
|
'instance.banner.blurhash',
|
||||||
|
|
||||||
'autospam.nlp.enabled',
|
'autospam.nlp.enabled',
|
||||||
|
|
||||||
|
'instance.curated_registration.enabled',
|
||||||
// 'system.user_mode'
|
// 'system.user_mode'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -48,13 +48,16 @@ class LandingService
|
||||||
->toArray() : [];
|
->toArray() : [];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$openReg = (bool) config_cache('pixelfed.open_registration');
|
||||||
|
|
||||||
$res = [
|
$res = [
|
||||||
'name' => config_cache('app.name'),
|
'name' => config_cache('app.name'),
|
||||||
'url' => config_cache('app.url'),
|
'url' => config_cache('app.url'),
|
||||||
'domain' => config('pixelfed.domain.app'),
|
'domain' => config('pixelfed.domain.app'),
|
||||||
'show_directory' => config_cache('instance.landing.show_directory'),
|
'show_directory' => config_cache('instance.landing.show_directory'),
|
||||||
'show_explore_feed' => config_cache('instance.landing.show_explore'),
|
'show_explore_feed' => config_cache('instance.landing.show_explore'),
|
||||||
'open_registration' => config_cache('pixelfed.open_registration') == 1,
|
'open_registration' => (bool) $openReg,
|
||||||
|
'curated_onboarding' => (bool) config_cache('instance.curated_registration.enabled'),
|
||||||
'version' => config('pixelfed.version'),
|
'version' => config('pixelfed.version'),
|
||||||
'about' => [
|
'about' => [
|
||||||
'banner_image' => config_cache('app.banner_image') ?? url('/storage/headers/default.jpg'),
|
'banner_image' => config_cache('app.banner_image') ?? url('/storage/headers/default.jpg'),
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.1|^8.2",
|
"php": "^8.1|^8.2|^8.3",
|
||||||
"ext-bcmath": "*",
|
"ext-bcmath": "*",
|
||||||
"ext-ctype": "*",
|
"ext-ctype": "*",
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
|
|
1078
composer.lock
generated
1078
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -74,7 +74,7 @@ return [
|
||||||
'redis' => [
|
'redis' => [
|
||||||
'driver' => 'redis',
|
'driver' => 'redis',
|
||||||
'lock_connection' => 'default',
|
'lock_connection' => 'default',
|
||||||
'client' => env('REDIS_CLIENT', 'phpredis'),
|
'client' => env('REDIS_CLIENT', 'predis'),
|
||||||
|
|
||||||
'default' => [
|
'default' => [
|
||||||
'scheme' => env('REDIS_SCHEME', 'tcp'),
|
'scheme' => env('REDIS_SCHEME', 'tcp'),
|
||||||
|
|
|
@ -49,7 +49,7 @@ return [
|
||||||
],
|
],
|
||||||
|
|
||||||
'network_timeline' => env('PF_NETWORK_TIMELINE', true),
|
'network_timeline' => env('PF_NETWORK_TIMELINE', true),
|
||||||
'network_timeline_days_falloff' => env('PF_NETWORK_TIMELINE_DAYS_FALLOFF', 2),
|
'network_timeline_days_falloff' => env('PF_NETWORK_TIMELINE_DAYS_FALLOFF', 90),
|
||||||
|
|
||||||
'custom_emoji' => [
|
'custom_emoji' => [
|
||||||
'enabled' => env('CUSTOM_EMOJI', false),
|
'enabled' => env('CUSTOM_EMOJI', false),
|
||||||
|
|
|
@ -145,4 +145,35 @@ return [
|
||||||
'software-update' => [
|
'software-update' => [
|
||||||
'disable_failed_warning' => env('INSTANCE_SOFTWARE_UPDATE_DISABLE_FAILED_WARNING', false)
|
'disable_failed_warning' => env('INSTANCE_SOFTWARE_UPDATE_DISABLE_FAILED_WARNING', false)
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'notifications' => [
|
||||||
|
'gc' => [
|
||||||
|
'enabled' => env('INSTANCE_NOTIFY_AUTO_GC', false),
|
||||||
|
'delete_after_days' => env('INSTANCE_NOTIFY_AUTO_GC_DEL_AFTER_DAYS', 365)
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
'curated_registration' => [
|
||||||
|
'enabled' => env('INSTANCE_CUR_REG', false),
|
||||||
|
|
||||||
|
'resend_confirmation_limit' => env('INSTANCE_CUR_REG_RESEND_LIMIT', 5),
|
||||||
|
|
||||||
|
'captcha_enabled' => env('INSTANCE_CUR_REG_CAPTCHA', env('CAPTCHA_ENABLED', false)),
|
||||||
|
|
||||||
|
'state' => [
|
||||||
|
'fallback_on_closed_reg' => true,
|
||||||
|
'only_enabled_on_closed_reg' => env('INSTANCE_CUR_REG_STATE_ONLY_ON_CLOSED', true),
|
||||||
|
],
|
||||||
|
|
||||||
|
'notify' => [
|
||||||
|
'admin' => [
|
||||||
|
'on_verify_email' => [
|
||||||
|
'enabled' => env('INSTANCE_CUR_REG_NOTIFY_ADMIN_ON_VERIFY', false),
|
||||||
|
'bundle' => env('INSTANCE_CUR_REG_NOTIFY_ADMIN_ON_VERIFY_BUNDLE', false),
|
||||||
|
'max_per_day' => env('INSTANCE_CUR_REG_NOTIFY_ADMIN_ON_VERIFY_MPD', 10),
|
||||||
|
],
|
||||||
|
'on_user_response' => env('INSTANCE_CUR_REG_NOTIFY_ADMIN_ON_USER_RESPONSE', false),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?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::create('curated_registers', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('email')->unique()->nullable()->index();
|
||||||
|
$table->string('username')->unique()->nullable()->index();
|
||||||
|
$table->string('password')->nullable();
|
||||||
|
$table->string('ip_address')->nullable();
|
||||||
|
$table->string('verify_code')->nullable();
|
||||||
|
$table->text('reason_to_join')->nullable();
|
||||||
|
$table->unsignedBigInteger('invited_by')->nullable()->index();
|
||||||
|
$table->boolean('is_approved')->default(0)->index();
|
||||||
|
$table->boolean('is_rejected')->default(0)->index();
|
||||||
|
$table->boolean('is_awaiting_more_info')->default(0)->index();
|
||||||
|
$table->boolean('is_closed')->default(0)->index();
|
||||||
|
$table->json('autofollow_account_ids')->nullable();
|
||||||
|
$table->json('admin_notes')->nullable();
|
||||||
|
$table->unsignedInteger('approved_by_admin_id')->nullable();
|
||||||
|
$table->timestamp('email_verified_at')->nullable();
|
||||||
|
$table->timestamp('admin_notified_at')->nullable();
|
||||||
|
$table->timestamp('action_taken_at')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('curated_registers');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?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::create('curated_register_activities', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->unsignedInteger('register_id')->nullable()->index();
|
||||||
|
$table->unsignedInteger('admin_id')->nullable();
|
||||||
|
$table->unsignedInteger('reply_to_id')->nullable()->index();
|
||||||
|
$table->string('secret_code')->nullable();
|
||||||
|
$table->string('type')->nullable()->index();
|
||||||
|
$table->string('title')->nullable();
|
||||||
|
$table->string('link')->nullable();
|
||||||
|
$table->text('message')->nullable();
|
||||||
|
$table->json('metadata')->nullable();
|
||||||
|
$table->boolean('from_admin')->default(false)->index();
|
||||||
|
$table->boolean('from_user')->default(false)->index();
|
||||||
|
$table->boolean('admin_only_view')->default(true);
|
||||||
|
$table->boolean('action_required')->default(false);
|
||||||
|
$table->timestamp('admin_notified_at')->nullable();
|
||||||
|
$table->timestamp('action_taken_at')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('curated_register_activities');
|
||||||
|
}
|
||||||
|
};
|
1543
package-lock.json
generated
1543
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "^8.7.1",
|
"acorn": "^8.7.1",
|
||||||
"axios": "^0.21.1",
|
"axios": ">=1.6.0",
|
||||||
"bootstrap": "^4.5.2",
|
"bootstrap": "^4.5.2",
|
||||||
"cross-env": "^5.2.1",
|
"cross-env": "^5.2.1",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
|
|
BIN
public/js/account-import.js
vendored
BIN
public/js/account-import.js
vendored
Binary file not shown.
BIN
public/js/activity.js
vendored
BIN
public/js/activity.js
vendored
Binary file not shown.
BIN
public/js/admin.js
vendored
BIN
public/js/admin.js
vendored
Binary file not shown.
BIN
public/js/admin_invite.js
vendored
BIN
public/js/admin_invite.js
vendored
Binary file not shown.
BIN
public/js/app.js
vendored
BIN
public/js/app.js
vendored
Binary file not shown.
BIN
public/js/changelog.bundle.742a06ba0a547120.js
vendored
BIN
public/js/changelog.bundle.742a06ba0a547120.js
vendored
Binary file not shown.
BIN
public/js/changelog.bundle.bf44edbbfa14bd53.js
vendored
Normal file
BIN
public/js/changelog.bundle.bf44edbbfa14bd53.js
vendored
Normal file
Binary file not shown.
BIN
public/js/collectioncompose.js
vendored
BIN
public/js/collectioncompose.js
vendored
Binary file not shown.
BIN
public/js/collections.js
vendored
BIN
public/js/collections.js
vendored
Binary file not shown.
BIN
public/js/components.js
vendored
BIN
public/js/components.js
vendored
Binary file not shown.
BIN
public/js/compose-classic.js
vendored
BIN
public/js/compose-classic.js
vendored
Binary file not shown.
BIN
public/js/compose.chunk.1ac292c93b524406.js
vendored
BIN
public/js/compose.chunk.1ac292c93b524406.js
vendored
Binary file not shown.
BIN
public/js/compose.chunk.ffae318db42f1072.js
vendored
Normal file
BIN
public/js/compose.chunk.ffae318db42f1072.js
vendored
Normal file
Binary file not shown.
BIN
public/js/compose.js
vendored
BIN
public/js/compose.js
vendored
Binary file not shown.
BIN
public/js/daci.chunk.34dc7bad3a0792cc.js
vendored
Normal file
BIN
public/js/daci.chunk.34dc7bad3a0792cc.js
vendored
Normal file
Binary file not shown.
BIN
public/js/daci.chunk.8d4acc1db3f27a51.js
vendored
BIN
public/js/daci.chunk.8d4acc1db3f27a51.js
vendored
Binary file not shown.
BIN
public/js/developers.js
vendored
BIN
public/js/developers.js
vendored
Binary file not shown.
BIN
public/js/direct.js
vendored
BIN
public/js/direct.js
vendored
Binary file not shown.
BIN
public/js/discover.chunk.b1846efb6bd1e43c.js
vendored
BIN
public/js/discover.chunk.b1846efb6bd1e43c.js
vendored
Binary file not shown.
BIN
public/js/discover.chunk.c2229e1d15bd3ada.js
vendored
Normal file
BIN
public/js/discover.chunk.c2229e1d15bd3ada.js
vendored
Normal file
Binary file not shown.
BIN
public/js/discover.js
vendored
BIN
public/js/discover.js
vendored
Binary file not shown.
Binary file not shown.
BIN
public/js/discover~findfriends.chunk.b1858bea66d9723b.js
vendored
Normal file
BIN
public/js/discover~findfriends.chunk.b1858bea66d9723b.js
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/js/discover~hashtag.bundle.a0f00fc7df1f313c.js
vendored
Normal file
BIN
public/js/discover~hashtag.bundle.a0f00fc7df1f313c.js
vendored
Normal file
Binary file not shown.
BIN
public/js/discover~memories.chunk.37e0c325f900e163.js
vendored
Normal file
BIN
public/js/discover~memories.chunk.37e0c325f900e163.js
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/js/discover~myhashtags.chunk.8886fc0d4736d819.js
vendored
Normal file
BIN
public/js/discover~myhashtags.chunk.8886fc0d4736d819.js
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/js/discover~serverfeed.chunk.262bf7e3bce843c3.js
vendored
Normal file
BIN
public/js/discover~serverfeed.chunk.262bf7e3bce843c3.js
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/js/discover~settings.chunk.65d6f3cbe5323ed4.js
vendored
Normal file
BIN
public/js/discover~settings.chunk.65d6f3cbe5323ed4.js
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/js/dms.chunk.2b55effc0e8ba89f.js
vendored
Normal file
BIN
public/js/dms.chunk.2b55effc0e8ba89f.js
vendored
Normal file
Binary file not shown.
BIN
public/js/dms.chunk.53a951c5de2d95ac.js
vendored
BIN
public/js/dms.chunk.53a951c5de2d95ac.js
vendored
Binary file not shown.
BIN
public/js/dms~message.chunk.76edeafda3d92320.js
vendored
BIN
public/js/dms~message.chunk.76edeafda3d92320.js
vendored
Binary file not shown.
BIN
public/js/dms~message.chunk.976f7edaa6f71137.js
vendored
Normal file
BIN
public/js/dms~message.chunk.976f7edaa6f71137.js
vendored
Normal file
Binary file not shown.
BIN
public/js/error404.bundle.3bbc118159460db6.js
vendored
BIN
public/js/error404.bundle.3bbc118159460db6.js
vendored
Binary file not shown.
BIN
public/js/error404.bundle.b397483e3991ab20.js
vendored
Normal file
BIN
public/js/error404.bundle.b397483e3991ab20.js
vendored
Normal file
Binary file not shown.
BIN
public/js/hashtag.js
vendored
BIN
public/js/hashtag.js
vendored
Binary file not shown.
BIN
public/js/home.chunk.264eeb47bfac56c1.js
vendored
Normal file
BIN
public/js/home.chunk.264eeb47bfac56c1.js
vendored
Normal file
Binary file not shown.
BIN
public/js/home.chunk.88eeebf6c53d4dca.js
vendored
BIN
public/js/home.chunk.88eeebf6c53d4dca.js
vendored
Binary file not shown.
BIN
public/js/i18n.bundle.47cbf9f04d955267.js
vendored
BIN
public/js/i18n.bundle.47cbf9f04d955267.js
vendored
Binary file not shown.
BIN
public/js/i18n.bundle.93a02e275ac1a708.js
vendored
Normal file
BIN
public/js/i18n.bundle.93a02e275ac1a708.js
vendored
Normal file
Binary file not shown.
BIN
public/js/landing.js
vendored
BIN
public/js/landing.js
vendored
Binary file not shown.
BIN
public/js/manifest.js
vendored
BIN
public/js/manifest.js
vendored
Binary file not shown.
BIN
public/js/notifications.chunk.0c5151643e4534aa.js
vendored
Normal file
BIN
public/js/notifications.chunk.0c5151643e4534aa.js
vendored
Normal file
Binary file not shown.
BIN
public/js/notifications.chunk.3b92cf46da469de1.js
vendored
BIN
public/js/notifications.chunk.3b92cf46da469de1.js
vendored
Binary file not shown.
BIN
public/js/portfolio.js
vendored
BIN
public/js/portfolio.js
vendored
Binary file not shown.
BIN
public/js/post.chunk.5ff16664f9adb901.js
vendored
Normal file
BIN
public/js/post.chunk.5ff16664f9adb901.js
vendored
Normal file
Binary file not shown.
BIN
public/js/post.chunk.eb9804ff282909ae.js
vendored
BIN
public/js/post.chunk.eb9804ff282909ae.js
vendored
Binary file not shown.
BIN
public/js/profile-directory.js
vendored
BIN
public/js/profile-directory.js
vendored
Binary file not shown.
BIN
public/js/profile.chunk.7a6c846c4cb3cfd4.js
vendored
Normal file
BIN
public/js/profile.chunk.7a6c846c4cb3cfd4.js
vendored
Normal file
Binary file not shown.
BIN
public/js/profile.chunk.d52916cb68c9a146.js
vendored
BIN
public/js/profile.chunk.d52916cb68c9a146.js
vendored
Binary file not shown.
BIN
public/js/profile.js
vendored
BIN
public/js/profile.js
vendored
Binary file not shown.
BIN
public/js/profile~followers.bundle.5d796e79f32d066c.js
vendored
Normal file
BIN
public/js/profile~followers.bundle.5d796e79f32d066c.js
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/js/profile~following.bundle.7ca7cfa5aaae75e2.js
vendored
Normal file
BIN
public/js/profile~following.bundle.7ca7cfa5aaae75e2.js
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/js/remote_auth.js
vendored
BIN
public/js/remote_auth.js
vendored
Binary file not shown.
BIN
public/js/search.js
vendored
BIN
public/js/search.js
vendored
Binary file not shown.
BIN
public/js/spa.js
vendored
BIN
public/js/spa.js
vendored
Binary file not shown.
BIN
public/js/status.js
vendored
BIN
public/js/status.js
vendored
Binary file not shown.
BIN
public/js/stories.js
vendored
BIN
public/js/stories.js
vendored
Binary file not shown.
BIN
public/js/story-compose.js
vendored
BIN
public/js/story-compose.js
vendored
Binary file not shown.
BIN
public/js/timeline.js
vendored
BIN
public/js/timeline.js
vendored
Binary file not shown.
BIN
public/js/vendor.js
vendored
BIN
public/js/vendor.js
vendored
Binary file not shown.
|
@ -71,8 +71,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Vue.js v2.7.14
|
* Vue.js v2.7.16
|
||||||
* (c) 2014-2022 Evan You
|
* (c) 2014-2023 Evan You
|
||||||
* Released under the MIT License.
|
* Released under the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue