Merge pull request #3975 from pixelfed/staging

Add Admin Invites
This commit is contained in:
daniel 2022-12-19 23:02:36 -07:00 committed by GitHub
commit 5f8ff9d280
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 1253 additions and 236 deletions

View file

@ -9,6 +9,7 @@
- Manually verify email address (php artisan user:verifyemail) ([682f5f0f](https://github.com/pixelfed/pixelfed/commit/682f5f0f))
- Manually generate in-app registration confirmation links (php artisan user:app-magic-link) ([73eb9e36](https://github.com/pixelfed/pixelfed/commit/73eb9e36))
- Optional home feed caching ([3328b367](https://github.com/pixelfed/pixelfed/commit/3328b367))
- Admin Invites ([b73ca9a1](https://github.com/pixelfed/pixelfed/commit/b73ca9a1))
### Updates
- Update ApiV1Controller, include self likes in favourited_by endpoint ([58b331d2](https://github.com/pixelfed/pixelfed/commit/58b331d2))
@ -59,6 +60,7 @@
- Update MediaS3GarbageCollector command, disable logging by default and optimize huge invocations ([a14af93b](https://github.com/pixelfed/pixelfed/commit/a14af93b))
- Update MediaStorageService, clear MediaService and StatusService caches after localToCloud ([de56b0f0](https://github.com/pixelfed/pixelfed/commit/de56b0f0))
- Add CloudMediaMigrate command to migrate older local media to cloud storage ([382d00d9](https://github.com/pixelfed/pixelfed/commit/382d00d9))
- Update MediaS3GarbageCollector command, handle thumbnail deletion ([95bbcc38](https://github.com/pixelfed/pixelfed/commit/95bbcc38))
- ([](https://github.com/pixelfed/pixelfed/commit/))
## [v0.11.4 (2022-10-04)](https://github.com/pixelfed/pixelfed/compare/v0.11.3...v0.11.4)

View file

@ -0,0 +1,179 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\AdminInvite;
use Illuminate\Support\Str;
class AdminInviteCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'admin:invite';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Create an invite link';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->info(' ____ _ ______ __ ');
$this->info(' / __ \(_) _____ / / __/__ ____/ / ');
$this->info(' / /_/ / / |/_/ _ \/ / /_/ _ \/ __ / ');
$this->info(' / ____/ /> </ __/ / __/ __/ /_/ / ');
$this->info(' /_/ /_/_/|_|\___/_/_/ \___/\__,_/ ');
$this->info(' ');
$this->info(' Pixelfed Admin Inviter');
$this->line(' ');
$this->info(' Manage user registration invite links');
$this->line(' ');
$action = $this->choice(
'Select an action',
[
'Create invite',
'View invites',
'Expire invite',
'Cancel'
],
3
);
switch($action) {
case 'Create invite':
return $this->create();
break;
case 'View invites':
return $this->view();
break;
case 'Expire invite':
return $this->expire();
break;
case 'Cancel':
return;
break;
}
}
protected function create()
{
$this->info('Create Invite');
$this->line('=============');
$this->info('Set an optional invite name (only visible to admins)');
$name = $this->ask('Invite Name (optional)', 'Untitled Invite');
$this->info('Set an optional invite description (only visible to admins)');
$description = $this->ask('Invite Description (optional)');
$this->info('Set an optional message to invitees (visible to all)');
$message = $this->ask('Invite Message (optional)', 'You\'ve been invited to join');
$this->info('Set maximum # of invite uses, use 0 for unlimited');
$max_uses = $this->ask('Max uses', 1);
$shouldExpire = $this->choice(
'Set an invite expiry date?',
[
'No - invite never expires',
'Yes - expire after 24 hours',
'Custom - let me pick an expiry date'
],
0
);
switch($shouldExpire) {
case 'No - invite never expires':
$expires = null;
break;
case 'Yes - expire after 24 hours':
$expires = now()->addHours(24);
break;
case 'Custom - let me pick an expiry date':
$this->info('Set custom expiry date in days');
$customExpiry = $this->ask('Custom Expiry', 14);
$expires = now()->addDays($customExpiry);
break;
}
$this->info('Skip email verification for invitees?');
$skipEmailVerification = $this->choice('Skip email verification', ['No', 'Yes'], 0);
$invite = new AdminInvite;
$invite->name = $name;
$invite->description = $description;
$invite->message = $message;
$invite->max_uses = $max_uses;
$invite->skip_email_verification = $skipEmailVerification === 'Yes';
$invite->expires_at = $expires;
$invite->invite_code = Str::uuid() . Str::random(random_int(1,6));
$invite->save();
$this->info('####################');
$this->info('# Invite Generated!');
$this->line(' ');
$this->info($invite->url());
$this->line(' ');
return Command::SUCCESS;
}
protected function view()
{
$this->info('View Invites');
$this->line('=============');
if(AdminInvite::count() == 0) {
$this->line(' ');
$this->error('No invites found!');
return;
}
$this->table(
['Invite Code', 'Uses Left', 'Expires'],
AdminInvite::all(['invite_code', 'max_uses', 'uses', 'expires_at'])->map(function($invite) {
return [
'invite_code' => $invite->invite_code,
'uses_left' => $invite->max_uses ? ($invite->max_uses - $invite->uses) : '∞',
'expires_at' => $invite->expires_at ? $invite->expires_at->diffForHumans() : 'never'
];
})->toArray()
);
}
protected function expire()
{
$token = $this->anticipate('Enter invite code to expire', function($val) {
if(!$val || empty($val)) {
return [];
}
return AdminInvite::where('invite_code', 'like', '%' . $val . '%')->pluck('invite_code')->toArray();
});
if(!$token || empty($token)) {
$this->error('Invalid invite code');
return;
}
$invite = AdminInvite::whereInviteCode($token)->first();
if(!$invite) {
$this->error('Invalid invite code');
return;
}
$invite->max_uses = 1;
$invite->expires_at = now()->subHours(2);
$invite->save();
$this->info('Expired the following invite: ' . $invite->url());
}
}

View file

@ -0,0 +1,191 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\AdminInvite;
use App\Profile;
use App\User;
use App\Util\Lexer\RestrictedNames;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Auth\Events\Registered;
use App\Services\EmailService;
use App\Http\Controllers\Auth\RegisterController;
class AdminInviteController extends Controller
{
public function __construct()
{
abort_if(!config('instance.admin_invites.enabled'), 404);
}
public function index(Request $request, $code)
{
if($request->user()) {
return redirect('/');
}
return view('invite.admin_invite', compact('code'));
}
public function apiVerifyCheck(Request $request)
{
$this->validate($request, [
'token' => 'required',
]);
$invite = AdminInvite::whereInviteCode($request->input('token'))->first();
abort_if(!$invite, 404);
abort_if($invite->expires_at && $invite->expires_at->lt(now()), 400, 'Invite has expired.');
abort_if($invite->max_uses && $invite->uses >= $invite->max_uses, 400, 'Maximum invites reached.');
$res = [
'message' => $invite->message,
'max_uses' => $invite->max_uses,
'sev' => $invite->skip_email_verification
];
return response()->json($res);
}
public function apiUsernameCheck(Request $request)
{
$this->validate($request, [
'token' => 'required',
'username' => 'required'
]);
$invite = AdminInvite::whereInviteCode($request->input('token'))->first();
abort_if(!$invite, 404);
abort_if($invite->expires_at && $invite->expires_at->lt(now()), 400, 'Invite has expired.');
abort_if($invite->max_uses && $invite->uses >= $invite->max_uses, 400, 'Maximum invites reached.');
$usernameRules = [
'required',
'min:2',
'max:15',
'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.');
}
},
];
$rules = ['username' => $usernameRules];
$validator = Validator::make($request->all(), $rules);
if($validator->fails()) {
return response()->json($validator->errors(), 400);
}
return response()->json([]);
}
public function apiEmailCheck(Request $request)
{
$this->validate($request, [
'token' => 'required',
'email' => 'required'
]);
$invite = AdminInvite::whereInviteCode($request->input('token'))->first();
abort_if(!$invite, 404);
abort_if($invite->expires_at && $invite->expires_at->lt(now()), 400, 'Invite has expired.');
abort_if($invite->max_uses && $invite->uses >= $invite->max_uses, 400, 'Maximum invites reached.');
$emailRules = [
'required',
'string',
'email',
'max:255',
'unique:users',
function ($attribute, $value, $fail) {
$banned = EmailService::isBanned($value);
if($banned) {
return $fail('Email is invalid.');
}
},
];
$rules = ['email' => $emailRules];
$validator = Validator::make($request->all(), $rules);
if($validator->fails()) {
return response()->json($validator->errors(), 400);
}
return response()->json([]);
}
public function apiRegister(Request $request)
{
$this->validate($request, [
'token' => 'required',
'username' => 'required',
'name' => 'nullable',
'email' => 'required|email',
'password' => 'required',
'password_confirm' => 'required'
]);
$invite = AdminInvite::whereInviteCode($request->input('token'))->firstOrFail();
abort_if($invite->expires_at && $invite->expires_at->lt(now()), 400, 'Invite expired');
abort_if($invite->max_uses && $invite->uses >= $invite->max_uses, 400, 'Maximum invites reached.');
$invite->uses = $invite->uses + 1;
event(new Registered($user = User::create([
'name' => $request->input('name') ?? $request->input('username'),
'username' => $request->input('username'),
'email' => $request->input('email'),
'password' => Hash::make($request->input('password')),
])));
$invite->used_by = array_merge($invite->used_by ?? [], [[
'user_id' => $user->id,
'username' => $user->username
]]);
$invite->save();
if($invite->skip_email_verification) {
$user->email_verified_at = now();
$user->save();
}
if(Auth::attempt([
'email' => $request->input('email'),
'password' => $request->input('password')
])) {
$request->session()->regenerate();
return redirect()->intended('/');
} else {
return response()->json([], 400);
}
}
}

View file

@ -0,0 +1,21 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class AdminInvite extends Model
{
use HasFactory;
protected $casts = [
'used_by' => 'array',
'expires_at' => 'datetime',
];
public function url()
{
return url('/auth/invite/a/' . $this->invite_code);
}
}

342
composer.lock generated
View file

@ -114,16 +114,16 @@
},
{
"name": "aws/aws-sdk-php",
"version": "3.253.0",
"version": "3.254.0",
"source": {
"type": "git",
"url": "https://github.com/aws/aws-sdk-php.git",
"reference": "1fc9d166dd8ee7c2a187cf8f3ed9342863208865"
"reference": "9e07cddf9be6ab241c241344ca2e9cf33e32a22e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/1fc9d166dd8ee7c2a187cf8f3ed9342863208865",
"reference": "1fc9d166dd8ee7c2a187cf8f3ed9342863208865",
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/9e07cddf9be6ab241c241344ca2e9cf33e32a22e",
"reference": "9e07cddf9be6ab241c241344ca2e9cf33e32a22e",
"shasum": ""
},
"require": {
@ -202,9 +202,9 @@
"support": {
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
"issues": "https://github.com/aws/aws-sdk-php/issues",
"source": "https://github.com/aws/aws-sdk-php/tree/3.253.0"
"source": "https://github.com/aws/aws-sdk-php/tree/3.254.0"
},
"time": "2022-12-12T19:23:54+00:00"
"time": "2022-12-19T19:23:23+00:00"
},
{
"name": "bacon/bacon-qr-code",
@ -262,16 +262,16 @@
},
{
"name": "beyondcode/laravel-websockets",
"version": "1.13.1",
"version": "1.13.2",
"source": {
"type": "git",
"url": "https://github.com/beyondcode/laravel-websockets.git",
"reference": "f0649b65fb5562d20eff66f61716ef98717e228a"
"reference": "50f8a1e77227a2d2302d45b99185d68a1c1c6866"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/beyondcode/laravel-websockets/zipball/f0649b65fb5562d20eff66f61716ef98717e228a",
"reference": "f0649b65fb5562d20eff66f61716ef98717e228a",
"url": "https://api.github.com/repos/beyondcode/laravel-websockets/zipball/50f8a1e77227a2d2302d45b99185d68a1c1c6866",
"reference": "50f8a1e77227a2d2302d45b99185d68a1c1c6866",
"shasum": ""
},
"require": {
@ -338,9 +338,9 @@
],
"support": {
"issues": "https://github.com/beyondcode/laravel-websockets/issues",
"source": "https://github.com/beyondcode/laravel-websockets/tree/1.13.1"
"source": "https://github.com/beyondcode/laravel-websockets/tree/1.13.2"
},
"time": "2022-03-03T08:41:47+00:00"
"time": "2022-10-19T18:15:42+00:00"
},
{
"name": "brick/math",
@ -1576,16 +1576,16 @@
},
{
"name": "firebase/php-jwt",
"version": "v6.3.1",
"version": "v6.3.2",
"source": {
"type": "git",
"url": "https://github.com/firebase/php-jwt.git",
"reference": "ddfaddcb520488b42bca3a75e17e9dd53c3667da"
"reference": "ea7dda77098b96e666c5ef382452f94841e439cd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/ddfaddcb520488b42bca3a75e17e9dd53c3667da",
"reference": "ddfaddcb520488b42bca3a75e17e9dd53c3667da",
"url": "https://api.github.com/repos/firebase/php-jwt/zipball/ea7dda77098b96e666c5ef382452f94841e439cd",
"reference": "ea7dda77098b96e666c5ef382452f94841e439cd",
"shasum": ""
},
"require": {
@ -1632,9 +1632,9 @@
],
"support": {
"issues": "https://github.com/firebase/php-jwt/issues",
"source": "https://github.com/firebase/php-jwt/tree/v6.3.1"
"source": "https://github.com/firebase/php-jwt/tree/v6.3.2"
},
"time": "2022-11-01T21:20:08+00:00"
"time": "2022-12-19T17:10:46+00:00"
},
{
"name": "fruitcake/laravel-cors",
@ -2400,16 +2400,16 @@
},
{
"name": "laravel/framework",
"version": "v9.43.0",
"version": "v9.44.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "011f2e1d49a11c22519a7899b46ddf3bc5b0f40b"
"reference": "60808a7d9acd53461fd69634c08fc7e0a99fbf98"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/011f2e1d49a11c22519a7899b46ddf3bc5b0f40b",
"reference": "011f2e1d49a11c22519a7899b46ddf3bc5b0f40b",
"url": "https://api.github.com/repos/laravel/framework/zipball/60808a7d9acd53461fd69634c08fc7e0a99fbf98",
"reference": "60808a7d9acd53461fd69634c08fc7e0a99fbf98",
"shasum": ""
},
"require": {
@ -2582,7 +2582,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2022-12-06T14:26:07+00:00"
"time": "2022-12-15T14:56:36+00:00"
},
{
"name": "laravel/helpers",
@ -2642,16 +2642,16 @@
},
{
"name": "laravel/horizon",
"version": "v5.10.5",
"version": "v5.10.6",
"source": {
"type": "git",
"url": "https://github.com/laravel/horizon.git",
"reference": "01b26da26ca8abe3a525a307b1155d52d7293c8d"
"reference": "22b6d7c67bb86722cf380dbaed55ff1a3fc84053"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/horizon/zipball/01b26da26ca8abe3a525a307b1155d52d7293c8d",
"reference": "01b26da26ca8abe3a525a307b1155d52d7293c8d",
"url": "https://api.github.com/repos/laravel/horizon/zipball/22b6d7c67bb86722cf380dbaed55ff1a3fc84053",
"reference": "22b6d7c67bb86722cf380dbaed55ff1a3fc84053",
"shasum": ""
},
"require": {
@ -2713,9 +2713,9 @@
],
"support": {
"issues": "https://github.com/laravel/horizon/issues",
"source": "https://github.com/laravel/horizon/tree/v5.10.5"
"source": "https://github.com/laravel/horizon/tree/v5.10.6"
},
"time": "2022-11-25T15:57:02+00:00"
"time": "2022-12-14T15:24:14+00:00"
},
{
"name": "laravel/passport",
@ -2985,31 +2985,34 @@
},
{
"name": "lcobucci/clock",
"version": "2.2.0",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/lcobucci/clock.git",
"reference": "fb533e093fd61321bfcbac08b131ce805fe183d3"
"reference": "c7aadcd6fd97ed9e199114269c0be3f335e38876"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/lcobucci/clock/zipball/fb533e093fd61321bfcbac08b131ce805fe183d3",
"reference": "fb533e093fd61321bfcbac08b131ce805fe183d3",
"url": "https://api.github.com/repos/lcobucci/clock/zipball/c7aadcd6fd97ed9e199114269c0be3f335e38876",
"reference": "c7aadcd6fd97ed9e199114269c0be3f335e38876",
"shasum": ""
},
"require": {
"php": "^8.0",
"stella-maris/clock": "^0.1.4"
"php": "~8.1.0 || ~8.2.0",
"stella-maris/clock": "^0.1.7"
},
"provide": {
"psr/clock-implementation": "1.0"
},
"require-dev": {
"infection/infection": "^0.26",
"lcobucci/coding-standard": "^8.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^0.12",
"phpstan/phpstan-deprecation-rules": "^0.12",
"phpstan/phpstan-phpunit": "^0.12",
"phpstan/phpstan-strict-rules": "^0.12",
"phpunit/phpunit": "^9.5"
"lcobucci/coding-standard": "^9.0",
"phpstan/extension-installer": "^1.2",
"phpstan/phpstan": "^1.9.4",
"phpstan/phpstan-deprecation-rules": "^1.1.1",
"phpstan/phpstan-phpunit": "^1.3.2",
"phpstan/phpstan-strict-rules": "^1.4.4",
"phpunit/phpunit": "^9.5.27"
},
"type": "library",
"autoload": {
@ -3030,7 +3033,7 @@
"description": "Yet another clock abstraction",
"support": {
"issues": "https://github.com/lcobucci/clock/issues",
"source": "https://github.com/lcobucci/clock/tree/2.2.0"
"source": "https://github.com/lcobucci/clock/tree/2.3.0"
},
"funding": [
{
@ -3042,7 +3045,7 @@
"type": "patreon"
}
],
"time": "2022-04-19T19:34:17+00:00"
"time": "2022-12-19T14:38:11+00:00"
},
{
"name": "lcobucci/jwt",
@ -5081,16 +5084,16 @@
},
{
"name": "phpseclib/phpseclib",
"version": "2.0.39",
"version": "2.0.40",
"source": {
"type": "git",
"url": "https://github.com/phpseclib/phpseclib.git",
"reference": "f3a0e2b715c40cf1fd270d444901b63311725d63"
"reference": "5ef6f8376ddad21f3ce1da429950f7e00ec2292c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/f3a0e2b715c40cf1fd270d444901b63311725d63",
"reference": "f3a0e2b715c40cf1fd270d444901b63311725d63",
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/5ef6f8376ddad21f3ce1da429950f7e00ec2292c",
"reference": "5ef6f8376ddad21f3ce1da429950f7e00ec2292c",
"shasum": ""
},
"require": {
@ -5171,7 +5174,7 @@
],
"support": {
"issues": "https://github.com/phpseclib/phpseclib/issues",
"source": "https://github.com/phpseclib/phpseclib/tree/2.0.39"
"source": "https://github.com/phpseclib/phpseclib/tree/2.0.40"
},
"funding": [
{
@ -5187,7 +5190,7 @@
"type": "tidelift"
}
],
"time": "2022-10-24T10:49:03+00:00"
"time": "2022-12-17T17:22:59+00:00"
},
{
"name": "pixelfed/fractal",
@ -6210,23 +6213,23 @@
},
{
"name": "ramsey/uuid",
"version": "4.6.0",
"version": "4.7.0",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
"reference": "ad63bc700e7d021039e30ce464eba384c4a1d40f"
"reference": "5ed9ad582647bbc3864ef78db34bdc1afdcf9b49"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/ad63bc700e7d021039e30ce464eba384c4a1d40f",
"reference": "ad63bc700e7d021039e30ce464eba384c4a1d40f",
"url": "https://api.github.com/repos/ramsey/uuid/zipball/5ed9ad582647bbc3864ef78db34bdc1afdcf9b49",
"reference": "5ed9ad582647bbc3864ef78db34bdc1afdcf9b49",
"shasum": ""
},
"require": {
"brick/math": "^0.8.8 || ^0.9 || ^0.10",
"ext-json": "*",
"php": "^8.0",
"ramsey/collection": "^1.0"
"ramsey/collection": "^1.2"
},
"replace": {
"rhumsaa/uuid": "self.version"
@ -6286,7 +6289,7 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
"source": "https://github.com/ramsey/uuid/tree/4.6.0"
"source": "https://github.com/ramsey/uuid/tree/4.7.0"
},
"funding": [
{
@ -6298,7 +6301,7 @@
"type": "tidelift"
}
],
"time": "2022-11-05T23:03:38+00:00"
"time": "2022-12-19T22:30:49+00:00"
},
{
"name": "ratchet/rfc6455",
@ -7745,16 +7748,16 @@
},
{
"name": "symfony/cache",
"version": "v6.2.0",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "64cb231dfb25677097d18503d1ad4d016b19f19c"
"reference": "68625530468c5ff4557fc8825dcfa478b94a8309"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/64cb231dfb25677097d18503d1ad4d016b19f19c",
"reference": "64cb231dfb25677097d18503d1ad4d016b19f19c",
"url": "https://api.github.com/repos/symfony/cache/zipball/68625530468c5ff4557fc8825dcfa478b94a8309",
"reference": "68625530468c5ff4557fc8825dcfa478b94a8309",
"shasum": ""
},
"require": {
@ -7821,7 +7824,7 @@
"psr6"
],
"support": {
"source": "https://github.com/symfony/cache/tree/v6.2.0"
"source": "https://github.com/symfony/cache/tree/v6.2.2"
},
"funding": [
{
@ -7837,7 +7840,7 @@
"type": "tidelift"
}
],
"time": "2022-11-24T11:58:37+00:00"
"time": "2022-12-16T12:37:34+00:00"
},
{
"name": "symfony/cache-contracts",
@ -7920,16 +7923,16 @@
},
{
"name": "symfony/console",
"version": "v6.2.1",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "58f6cef5dc5f641b7bbdbf8b32b44cc926c35f3f"
"reference": "5a9bd5c543f00157c55face973c149957467db31"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/58f6cef5dc5f641b7bbdbf8b32b44cc926c35f3f",
"reference": "58f6cef5dc5f641b7bbdbf8b32b44cc926c35f3f",
"url": "https://api.github.com/repos/symfony/console/zipball/5a9bd5c543f00157c55face973c149957467db31",
"reference": "5a9bd5c543f00157c55face973c149957467db31",
"shasum": ""
},
"require": {
@ -7996,7 +7999,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.2.1"
"source": "https://github.com/symfony/console/tree/v6.2.2"
},
"funding": [
{
@ -8012,7 +8015,7 @@
"type": "tidelift"
}
],
"time": "2022-12-01T13:44:20+00:00"
"time": "2022-12-16T15:08:36+00:00"
},
{
"name": "symfony/css-selector",
@ -8148,16 +8151,16 @@
},
{
"name": "symfony/error-handler",
"version": "v6.2.1",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
"reference": "b4e41f62c1124378863ff2705158a60da3e4c6b9"
"reference": "12a25d01cc5273b2445e125d62b61d34db42297e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/b4e41f62c1124378863ff2705158a60da3e4c6b9",
"reference": "b4e41f62c1124378863ff2705158a60da3e4c6b9",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/12a25d01cc5273b2445e125d62b61d34db42297e",
"reference": "12a25d01cc5273b2445e125d62b61d34db42297e",
"shasum": ""
},
"require": {
@ -8199,7 +8202,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/error-handler/tree/v6.2.1"
"source": "https://github.com/symfony/error-handler/tree/v6.2.2"
},
"funding": [
{
@ -8215,20 +8218,20 @@
"type": "tidelift"
}
],
"time": "2022-12-01T21:07:46+00:00"
"time": "2022-12-14T16:11:27+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v6.2.0",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "9efb1618fabee89515fe031314e8ed5625f85a53"
"reference": "3ffeb31139b49bf6ef0bc09d1db95eac053388d1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9efb1618fabee89515fe031314e8ed5625f85a53",
"reference": "9efb1618fabee89515fe031314e8ed5625f85a53",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/3ffeb31139b49bf6ef0bc09d1db95eac053388d1",
"reference": "3ffeb31139b49bf6ef0bc09d1db95eac053388d1",
"shasum": ""
},
"require": {
@ -8282,7 +8285,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v6.2.0"
"source": "https://github.com/symfony/event-dispatcher/tree/v6.2.2"
},
"funding": [
{
@ -8298,7 +8301,7 @@
"type": "tidelift"
}
],
"time": "2022-11-02T09:08:04+00:00"
"time": "2022-12-14T16:11:27+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
@ -8445,16 +8448,16 @@
},
{
"name": "symfony/http-client",
"version": "v6.2.0",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
"reference": "153540b6ed72eecdcb42dc847f8d8cf2e2516e8e"
"reference": "7054ad466f836309aef511789b9c697bc986d8ce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client/zipball/153540b6ed72eecdcb42dc847f8d8cf2e2516e8e",
"reference": "153540b6ed72eecdcb42dc847f8d8cf2e2516e8e",
"url": "https://api.github.com/repos/symfony/http-client/zipball/7054ad466f836309aef511789b9c697bc986d8ce",
"reference": "7054ad466f836309aef511789b9c697bc986d8ce",
"shasum": ""
},
"require": {
@ -8510,7 +8513,7 @@
"description": "Provides powerful methods to fetch HTTP resources synchronously or asynchronously",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-client/tree/v6.2.0"
"source": "https://github.com/symfony/http-client/tree/v6.2.2"
},
"funding": [
{
@ -8526,7 +8529,7 @@
"type": "tidelift"
}
],
"time": "2022-11-14T10:13:36+00:00"
"time": "2022-12-14T16:11:27+00:00"
},
{
"name": "symfony/http-client-contracts",
@ -8611,16 +8614,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v6.2.1",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "d0bbd5a7e81b38f32504399b9199f265505b7bac"
"reference": "ddf4dd35de1623e7c02013523e6c2137b67b636f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/d0bbd5a7e81b38f32504399b9199f265505b7bac",
"reference": "d0bbd5a7e81b38f32504399b9199f265505b7bac",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/ddf4dd35de1623e7c02013523e6c2137b67b636f",
"reference": "ddf4dd35de1623e7c02013523e6c2137b67b636f",
"shasum": ""
},
"require": {
@ -8669,7 +8672,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v6.2.1"
"source": "https://github.com/symfony/http-foundation/tree/v6.2.2"
},
"funding": [
{
@ -8685,20 +8688,20 @@
"type": "tidelift"
}
],
"time": "2022-12-04T18:26:13+00:00"
"time": "2022-12-14T16:11:27+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v6.2.1",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "bcbd2ea12fee651a4c8bff4f6f00cce2ac1f8404"
"reference": "860a0189969b755cd571709bd32313aa8599867a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/bcbd2ea12fee651a4c8bff4f6f00cce2ac1f8404",
"reference": "bcbd2ea12fee651a4c8bff4f6f00cce2ac1f8404",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/860a0189969b755cd571709bd32313aa8599867a",
"reference": "860a0189969b755cd571709bd32313aa8599867a",
"shasum": ""
},
"require": {
@ -8780,7 +8783,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-kernel/tree/v6.2.1"
"source": "https://github.com/symfony/http-kernel/tree/v6.2.2"
},
"funding": [
{
@ -8796,20 +8799,20 @@
"type": "tidelift"
}
],
"time": "2022-12-06T17:28:26+00:00"
"time": "2022-12-16T19:38:34+00:00"
},
{
"name": "symfony/mailer",
"version": "v6.2.1",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
"reference": "a18c3dd41cfcf011e3866802e39b9ae9e541deaf"
"reference": "b355ad81f1d2987c47dcd3b04d5dce669e1e62e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/a18c3dd41cfcf011e3866802e39b9ae9e541deaf",
"reference": "a18c3dd41cfcf011e3866802e39b9ae9e541deaf",
"url": "https://api.github.com/repos/symfony/mailer/zipball/b355ad81f1d2987c47dcd3b04d5dce669e1e62e6",
"reference": "b355ad81f1d2987c47dcd3b04d5dce669e1e62e6",
"shasum": ""
},
"require": {
@ -8859,7 +8862,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/mailer/tree/v6.2.1"
"source": "https://github.com/symfony/mailer/tree/v6.2.2"
},
"funding": [
{
@ -8875,7 +8878,7 @@
"type": "tidelift"
}
],
"time": "2022-12-06T16:54:23+00:00"
"time": "2022-12-14T16:11:27+00:00"
},
{
"name": "symfony/mailgun-mailer",
@ -8944,16 +8947,16 @@
},
{
"name": "symfony/mime",
"version": "v6.2.0",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "1e8005a7cbd79fb824ad81308ef2a76592a08bc0"
"reference": "8c98bf40406e791043890a163f6f6599b9cfa1ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/1e8005a7cbd79fb824ad81308ef2a76592a08bc0",
"reference": "1e8005a7cbd79fb824ad81308ef2a76592a08bc0",
"url": "https://api.github.com/repos/symfony/mime/zipball/8c98bf40406e791043890a163f6f6599b9cfa1ed",
"reference": "8c98bf40406e791043890a163f6f6599b9cfa1ed",
"shasum": ""
},
"require": {
@ -9007,7 +9010,7 @@
"mime-type"
],
"support": {
"source": "https://github.com/symfony/mime/tree/v6.2.0"
"source": "https://github.com/symfony/mime/tree/v6.2.2"
},
"funding": [
{
@ -9023,7 +9026,7 @@
"type": "tidelift"
}
],
"time": "2022-11-28T12:28:19+00:00"
"time": "2022-12-14T16:38:10+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -10001,16 +10004,16 @@
},
{
"name": "symfony/service-contracts",
"version": "v3.1.1",
"version": "v3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239"
"reference": "aac98028c69df04ee77eb69b96b86ee51fbf4b75"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/925e713fe8fcacf6bc05e936edd8dd5441a21239",
"reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/aac98028c69df04ee77eb69b96b86ee51fbf4b75",
"reference": "aac98028c69df04ee77eb69b96b86ee51fbf4b75",
"shasum": ""
},
"require": {
@ -10026,7 +10029,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "3.1-dev"
"dev-main": "3.3-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -10066,7 +10069,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v3.1.1"
"source": "https://github.com/symfony/service-contracts/tree/v3.2.0"
},
"funding": [
{
@ -10082,20 +10085,20 @@
"type": "tidelift"
}
],
"time": "2022-05-30T19:18:58+00:00"
"time": "2022-11-25T10:21:52+00:00"
},
{
"name": "symfony/string",
"version": "v6.2.0",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "145702685e0d12f81d755c71127bfff7582fdd36"
"reference": "863219fd713fa41cbcd285a79723f94672faff4d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/145702685e0d12f81d755c71127bfff7582fdd36",
"reference": "145702685e0d12f81d755c71127bfff7582fdd36",
"url": "https://api.github.com/repos/symfony/string/zipball/863219fd713fa41cbcd285a79723f94672faff4d",
"reference": "863219fd713fa41cbcd285a79723f94672faff4d",
"shasum": ""
},
"require": {
@ -10152,7 +10155,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.2.0"
"source": "https://github.com/symfony/string/tree/v6.2.2"
},
"funding": [
{
@ -10168,20 +10171,20 @@
"type": "tidelift"
}
],
"time": "2022-11-30T17:13:47+00:00"
"time": "2022-12-14T16:11:27+00:00"
},
{
"name": "symfony/translation",
"version": "v6.2.0",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "c08de62caead8357244efcb809d0b1a2584f2198"
"reference": "3294288c335b6267eab14964bf2c46015663d93f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/c08de62caead8357244efcb809d0b1a2584f2198",
"reference": "c08de62caead8357244efcb809d0b1a2584f2198",
"url": "https://api.github.com/repos/symfony/translation/zipball/3294288c335b6267eab14964bf2c46015663d93f",
"reference": "3294288c335b6267eab14964bf2c46015663d93f",
"shasum": ""
},
"require": {
@ -10250,7 +10253,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/translation/tree/v6.2.0"
"source": "https://github.com/symfony/translation/tree/v6.2.2"
},
"funding": [
{
@ -10266,7 +10269,7 @@
"type": "tidelift"
}
],
"time": "2022-11-02T09:08:04+00:00"
"time": "2022-12-13T18:04:17+00:00"
},
{
"name": "symfony/translation-contracts",
@ -10425,16 +10428,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v6.2.1",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "1e7544c8698627b908657e5276854d52ab70087a"
"reference": "6168f544827e897f708a684f75072a8c33a5e309"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/1e7544c8698627b908657e5276854d52ab70087a",
"reference": "1e7544c8698627b908657e5276854d52ab70087a",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/6168f544827e897f708a684f75072a8c33a5e309",
"reference": "6168f544827e897f708a684f75072a8c33a5e309",
"shasum": ""
},
"require": {
@ -10493,7 +10496,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v6.2.1"
"source": "https://github.com/symfony/var-dumper/tree/v6.2.2"
},
"funding": [
{
@ -10509,20 +10512,20 @@
"type": "tidelift"
}
],
"time": "2022-12-03T22:32:58+00:00"
"time": "2022-12-14T16:11:27+00:00"
},
{
"name": "symfony/var-exporter",
"version": "v6.2.1",
"version": "v6.2.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-exporter.git",
"reference": "8a3f442d48567a5447e984ce9e86875ed768304a"
"reference": "ada947160cf9444d17d9ac0b2df46c06941b5526"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/8a3f442d48567a5447e984ce9e86875ed768304a",
"reference": "8a3f442d48567a5447e984ce9e86875ed768304a",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/ada947160cf9444d17d9ac0b2df46c06941b5526",
"reference": "ada947160cf9444d17d9ac0b2df46c06941b5526",
"shasum": ""
},
"require": {
@ -10567,7 +10570,7 @@
"serialize"
],
"support": {
"source": "https://github.com/symfony/var-exporter/tree/v6.2.1"
"source": "https://github.com/symfony/var-exporter/tree/v6.2.2"
},
"funding": [
{
@ -10583,7 +10586,7 @@
"type": "tidelift"
}
],
"time": "2022-12-03T22:32:58+00:00"
"time": "2022-12-12T08:57:11+00:00"
},
{
"name": "tightenco/collect",
@ -11074,20 +11077,20 @@
},
{
"name": "fakerphp/faker",
"version": "v1.20.0",
"version": "v1.21.0",
"source": {
"type": "git",
"url": "https://github.com/FakerPHP/Faker.git",
"reference": "37f751c67a5372d4e26353bd9384bc03744ec77b"
"reference": "92efad6a967f0b79c499705c69b662f738cc9e4d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/FakerPHP/Faker/zipball/37f751c67a5372d4e26353bd9384bc03744ec77b",
"reference": "37f751c67a5372d4e26353bd9384bc03744ec77b",
"url": "https://api.github.com/repos/FakerPHP/Faker/zipball/92efad6a967f0b79c499705c69b662f738cc9e4d",
"reference": "92efad6a967f0b79c499705c69b662f738cc9e4d",
"shasum": ""
},
"require": {
"php": "^7.1 || ^8.0",
"php": "^7.4 || ^8.0",
"psr/container": "^1.0 || ^2.0",
"symfony/deprecation-contracts": "^2.2 || ^3.0"
},
@ -11098,7 +11101,8 @@
"bamarni/composer-bin-plugin": "^1.4.1",
"doctrine/persistence": "^1.3 || ^2.0",
"ext-intl": "*",
"symfony/phpunit-bridge": "^4.4 || ^5.2"
"phpunit/phpunit": "^9.5.26",
"symfony/phpunit-bridge": "^5.4.16"
},
"suggest": {
"doctrine/orm": "Required to use Faker\\ORM\\Doctrine",
@ -11110,7 +11114,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "v1.20-dev"
"dev-main": "v1.21-dev"
}
},
"autoload": {
@ -11135,22 +11139,22 @@
],
"support": {
"issues": "https://github.com/FakerPHP/Faker/issues",
"source": "https://github.com/FakerPHP/Faker/tree/v1.20.0"
"source": "https://github.com/FakerPHP/Faker/tree/v1.21.0"
},
"time": "2022-07-20T13:12:54+00:00"
"time": "2022-12-13T13:54:32+00:00"
},
{
"name": "fidry/cpu-core-counter",
"version": "0.4.0",
"version": "0.4.1",
"source": {
"type": "git",
"url": "https://github.com/theofidry/cpu-core-counter.git",
"reference": "666cb04a02f2801f3b19955fc23c824f9018bf64"
"reference": "79261cc280aded96d098e1b0e0ba0c4881b432c2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/666cb04a02f2801f3b19955fc23c824f9018bf64",
"reference": "666cb04a02f2801f3b19955fc23c824f9018bf64",
"url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/79261cc280aded96d098e1b0e0ba0c4881b432c2",
"reference": "79261cc280aded96d098e1b0e0ba0c4881b432c2",
"shasum": ""
},
"require": {
@ -11190,7 +11194,7 @@
],
"support": {
"issues": "https://github.com/theofidry/cpu-core-counter/issues",
"source": "https://github.com/theofidry/cpu-core-counter/tree/0.4.0"
"source": "https://github.com/theofidry/cpu-core-counter/tree/0.4.1"
},
"funding": [
{
@ -11198,7 +11202,7 @@
"type": "github"
}
],
"time": "2022-12-10T21:26:31+00:00"
"time": "2022-12-16T22:01:02+00:00"
},
{
"name": "filp/whoops",
@ -11383,16 +11387,16 @@
},
{
"name": "laravel/telescope",
"version": "v4.10.0",
"version": "v4.10.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/telescope.git",
"reference": "e4b16dd22db3e8a8b52e3a03343b11ffcee2aaaa"
"reference": "fcf4d360c003a1d27e2c1b298691645f8942943b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/telescope/zipball/e4b16dd22db3e8a8b52e3a03343b11ffcee2aaaa",
"reference": "e4b16dd22db3e8a8b52e3a03343b11ffcee2aaaa",
"url": "https://api.github.com/repos/laravel/telescope/zipball/fcf4d360c003a1d27e2c1b298691645f8942943b",
"reference": "fcf4d360c003a1d27e2c1b298691645f8942943b",
"shasum": ""
},
"require": {
@ -11445,9 +11449,9 @@
],
"support": {
"issues": "https://github.com/laravel/telescope/issues",
"source": "https://github.com/laravel/telescope/tree/v4.10.0"
"source": "https://github.com/laravel/telescope/tree/v4.10.1"
},
"time": "2022-12-05T15:34:49+00:00"
"time": "2022-12-14T15:00:00+00:00"
},
{
"name": "mockery/mockery",
@ -11781,16 +11785,16 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.19",
"version": "9.2.22",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "c77b56b63e3d2031bd8997fcec43c1925ae46559"
"reference": "e4bf60d2220b4baaa0572986b5d69870226b06df"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c77b56b63e3d2031bd8997fcec43c1925ae46559",
"reference": "c77b56b63e3d2031bd8997fcec43c1925ae46559",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e4bf60d2220b4baaa0572986b5d69870226b06df",
"reference": "e4bf60d2220b4baaa0572986b5d69870226b06df",
"shasum": ""
},
"require": {
@ -11846,7 +11850,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.19"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.22"
},
"funding": [
{
@ -11854,7 +11858,7 @@
"type": "github"
}
],
"time": "2022-11-18T07:47:47+00:00"
"time": "2022-12-18T16:40:55+00:00"
},
{
"name": "phpunit/php-file-iterator",

View file

@ -103,4 +103,8 @@ return [
'avatar' => [
'local_to_cloud' => env('PF_LOCAL_AVATAR_TO_CLOUD', false)
],
'admin_invites' => [
'enabled' => env('PF_ADMIN_INVITES_ENABLED', true)
],
];

View file

@ -0,0 +1,41 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('admin_invites', function (Blueprint $table) {
$table->id();
$table->string('name')->nullable();
$table->string('invite_code')->unique()->index();
$table->text('description')->nullable();
$table->text('message')->nullable();
$table->unsignedInteger('max_uses')->nullable();
$table->unsignedInteger('uses')->nullable();
$table->boolean('skip_email_verification')->default(false);
$table->timestamp('expires_at')->nullable();
$table->json('used_by')->nullable();
$table->unsignedInteger('admin_user_id')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('admin_invites');
}
};

View file

@ -0,0 +1,31 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('admin_invites', function (Blueprint $table) {
$table->unsignedInteger('uses')->default(0)->after('max_uses')->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('admin_invites', function (Blueprint $table) {
});
}
};

158
package-lock.json generated
View file

@ -1933,17 +1933,27 @@
"integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ=="
},
"node_modules/@types/express": {
"version": "4.17.14",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz",
"integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==",
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz",
"integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==",
"dependencies": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.18",
"@types/express-serve-static-core": "^4.17.31",
"@types/qs": "*",
"@types/serve-static": "*"
}
},
"node_modules/@types/express-serve-static-core": {
"version": "4.17.28",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
"integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*"
}
},
"node_modules/@types/express/node_modules/@types/express-serve-static-core": {
"version": "4.17.31",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz",
"integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==",
@ -2027,9 +2037,9 @@
"integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA=="
},
"node_modules/@types/node": {
"version": "18.11.13",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
"integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
"version": "18.11.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
"integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
@ -3528,14 +3538,14 @@
}
},
"node_modules/css-loader": {
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.2.tgz",
"integrity": "sha512-oqGbbVcBJkm8QwmnNzrFrWTnudnRZC+1eXikLJl0n4ljcfotgRifpg2a1lKy8jTrc4/d9A/ap1GFq1jDKG7J+Q==",
"version": "6.7.3",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz",
"integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==",
"dev": true,
"peer": true,
"dependencies": {
"icss-utils": "^5.1.0",
"postcss": "^8.4.18",
"postcss": "^8.4.19",
"postcss-modules-extract-imports": "^3.0.0",
"postcss-modules-local-by-default": "^4.0.0",
"postcss-modules-scope": "^3.0.0",
@ -5075,9 +5085,9 @@
]
},
"node_modules/ignore": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
"integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==",
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
"engines": {
"node": ">= 4"
}
@ -5413,9 +5423,9 @@
}
},
"node_modules/jquery": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz",
"integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw=="
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.2.tgz",
"integrity": "sha512-/e7ulNIEEYk1Z/l4X0vpxGt+B/dNsV8ghOPAWZaJs8pkGvsSC0tm33aMGylXcj/U7y4IcvwtMXPMyBFZn/gK9A=="
},
"node_modules/jquery-scroll-lock": {
"version": "3.1.3",
@ -5459,9 +5469,9 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
"integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==",
"bin": {
"json5": "lib/cli.js"
},
@ -6180,9 +6190,9 @@
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"node_modules/node-releases": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg=="
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz",
"integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A=="
},
"node_modules/normalize-path": {
"version": "3.0.0",
@ -7227,19 +7237,20 @@
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="
},
"node_modules/pusher-js": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-7.5.0.tgz",
"integrity": "sha512-R8eL3v2hnOC7NY8ufvrcDPdEjit//2pqVmcC7h1sUyoZQ4M+bwlwkszmMVuVbYNKZUS8WRFmSvdeb9LkfLyvZQ==",
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-7.6.0.tgz",
"integrity": "sha512-5CJ7YN5ZdC24E0ETraCU5VYFv0IY5ziXhrS0gS5+9Qrro1E4M1lcZhtr9H1H+6jNSLj1LKKAgcLeE1EH9GxMlw==",
"dev": true,
"dependencies": {
"@types/express-serve-static-core": "4.17.28",
"@types/node": "^14.14.31",
"tweetnacl": "^1.0.3"
}
},
"node_modules/pusher-js/node_modules/@types/node": {
"version": "14.18.34",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.34.tgz",
"integrity": "sha512-hcU9AIQVHmPnmjRK+XUUYlILlr9pQrsqSrwov/JK1pnf3GTQowVBhx54FbvM0AU/VXGH4i3+vgXS5EguR7fysA==",
"version": "14.18.35",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.35.tgz",
"integrity": "sha512-2ATO8pfhG1kDvw4Lc4C0GXIMSQFFJBCo/R1fSgTwmUlq5oy95LXyjDQinsRVgQY6gp6ghh3H91wk9ES5/5C+Tw==",
"dev": true
},
"node_modules/qs": {
@ -7659,9 +7670,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sass": {
"version": "1.56.2",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.56.2.tgz",
"integrity": "sha512-ciEJhnyCRwzlBCB+h5cCPM6ie/6f8HrhZMQOf5vlU60Y1bI1rx5Zb0vlDZvaycHsg/MqFfF1Eq2eokAa32iw8w==",
"version": "1.57.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz",
"integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
@ -10710,20 +10721,32 @@
"integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ=="
},
"@types/express": {
"version": "4.17.14",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz",
"integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==",
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz",
"integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==",
"requires": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.18",
"@types/express-serve-static-core": "^4.17.31",
"@types/qs": "*",
"@types/serve-static": "*"
},
"dependencies": {
"@types/express-serve-static-core": {
"version": "4.17.31",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz",
"integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==",
"requires": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*"
}
}
}
},
"@types/express-serve-static-core": {
"version": "4.17.31",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz",
"integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==",
"version": "4.17.28",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
"integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
"requires": {
"@types/node": "*",
"@types/qs": "*",
@ -10804,9 +10827,9 @@
"integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA=="
},
"@types/node": {
"version": "18.11.13",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz",
"integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w=="
"version": "18.11.17",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
"integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
},
"@types/parse-json": {
"version": "4.0.0",
@ -12023,14 +12046,14 @@
"requires": {}
},
"css-loader": {
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.2.tgz",
"integrity": "sha512-oqGbbVcBJkm8QwmnNzrFrWTnudnRZC+1eXikLJl0n4ljcfotgRifpg2a1lKy8jTrc4/d9A/ap1GFq1jDKG7J+Q==",
"version": "6.7.3",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz",
"integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==",
"dev": true,
"peer": true,
"requires": {
"icss-utils": "^5.1.0",
"postcss": "^8.4.18",
"postcss": "^8.4.19",
"postcss-modules-extract-imports": "^3.0.0",
"postcss-modules-local-by-default": "^4.0.0",
"postcss-modules-scope": "^3.0.0",
@ -13182,9 +13205,9 @@
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
},
"ignore": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz",
"integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA=="
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ=="
},
"imagemin": {
"version": "7.0.1",
@ -13419,9 +13442,9 @@
}
},
"jquery": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz",
"integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw=="
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.2.tgz",
"integrity": "sha512-/e7ulNIEEYk1Z/l4X0vpxGt+B/dNsV8ghOPAWZaJs8pkGvsSC0tm33aMGylXcj/U7y4IcvwtMXPMyBFZn/gK9A=="
},
"jquery-scroll-lock": {
"version": "3.1.3",
@ -13459,9 +13482,9 @@
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA=="
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz",
"integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ=="
},
"jsonfile": {
"version": "6.1.0",
@ -14006,9 +14029,9 @@
}
},
"node-releases": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz",
"integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg=="
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz",
"integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A=="
},
"normalize-path": {
"version": "3.0.0",
@ -14696,19 +14719,20 @@
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ=="
},
"pusher-js": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-7.5.0.tgz",
"integrity": "sha512-R8eL3v2hnOC7NY8ufvrcDPdEjit//2pqVmcC7h1sUyoZQ4M+bwlwkszmMVuVbYNKZUS8WRFmSvdeb9LkfLyvZQ==",
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/pusher-js/-/pusher-js-7.6.0.tgz",
"integrity": "sha512-5CJ7YN5ZdC24E0ETraCU5VYFv0IY5ziXhrS0gS5+9Qrro1E4M1lcZhtr9H1H+6jNSLj1LKKAgcLeE1EH9GxMlw==",
"dev": true,
"requires": {
"@types/express-serve-static-core": "4.17.28",
"@types/node": "^14.14.31",
"tweetnacl": "^1.0.3"
},
"dependencies": {
"@types/node": {
"version": "14.18.34",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.34.tgz",
"integrity": "sha512-hcU9AIQVHmPnmjRK+XUUYlILlr9pQrsqSrwov/JK1pnf3GTQowVBhx54FbvM0AU/VXGH4i3+vgXS5EguR7fysA==",
"version": "14.18.35",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.35.tgz",
"integrity": "sha512-2ATO8pfhG1kDvw4Lc4C0GXIMSQFFJBCo/R1fSgTwmUlq5oy95LXyjDQinsRVgQY6gp6ghh3H91wk9ES5/5C+Tw==",
"dev": true
}
}
@ -15013,9 +15037,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sass": {
"version": "1.56.2",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.56.2.tgz",
"integrity": "sha512-ciEJhnyCRwzlBCB+h5cCPM6ie/6f8HrhZMQOf5vlU60Y1bI1rx5Zb0vlDZvaycHsg/MqFfF1Eq2eokAa32iw8w==",
"version": "1.57.1",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz",
"integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==",
"dev": true,
"requires": {
"chokidar": ">=3.0.0 <4.0.0",

BIN
public/js/admin_invite.js vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
public/js/spa.js vendored

Binary file not shown.

BIN
public/js/vendor.js vendored

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,488 @@
<template>
<div class="admin-invite-component">
<div class="admin-invite-component-inner">
<div class="card bg-dark">
<div v-if="tabIndex === 0" class="card-body d-flex align-items-center justify-content-center">
<div class="text-center">
<b-spinner variant="muted" />
<p class="text-muted mb-0">Loading...</p>
</div>
</div>
<div v-else-if="tabIndex === 1" class="card-body">
<div class="d-flex justify-content-center my-3">
<img src="/img/pixelfed-icon-color.png" width="60" alt="Pixelfed logo" />
</div>
<div class="d-flex flex-column align-items-center justify-content-center">
<p class="lead mb-1 text-muted">You've been invited to join</p>
<p class="h3 mb-2">{{ instance.uri }}</p>
<p class="mb-0 text-muted">
<span>{{ instance.stats.user_count.toLocaleString('en-CA', { compactDisplay: "short", notation: "compact"}) }} users</span>
<span>·</span>
<span>{{ instance.stats.status_count.toLocaleString('en-CA', { compactDisplay: "short", notation: "compact"}) }} posts</span>
</p>
<div v-if="inviteConfig.message != 'You\'ve been invited to join'">
<div class="admin-message">
<p class="small text-light mb-0">Message from admin(s):</p>
{{ inviteConfig.message }}
</div>
</div>
</div>
<div class="mt-5">
<div class="form-group">
<label for="username">Username</label>
<input
type="text"
class="form-control form-control-lg"
placeholder="What should everyone call you?"
minlength="2"
maxlength="15"
v-model="form.username" />
<p v-if="errors.username" class="form-text text-danger">
<i class="far fa-exclamation-triangle mr-1"></i>
{{ errors.username }}
</p>
</div>
<button
class="btn btn-primary btn-block font-weight-bold"
@click="proceed(tabIndex)"
:disabled="isProceeding || !form.username || form.username.length < 2">
<template v-if="isProceeding">
<b-spinner small />
</template>
<template v-else>
Continue
</template>
</button>
<p class="login-link">
<a href="/login">Already have an account?</a>
</p>
<p class="register-terms">
By registering, you agree to our <a href="/site/terms">Terms of Service</a> and <a href="/site/privacy">Privacy Policy</a>.
</p>
</div>
</div>
<div v-else-if="tabIndex === 2" class="card-body">
<div class="d-flex justify-content-center my-3">
<img src="/img/pixelfed-icon-color.png" width="60" alt="Pixelfed logo" />
</div>
<div class="d-flex flex-column align-items-center justify-content-center">
<p class="lead mb-1 text-muted">You've been invited to join</p>
<p class="h3 mb-2">{{ instance.uri }}</p>
</div>
<div class="mt-5">
<div class="form-group">
<label for="username">Email Address</label>
<input
type="email"
class="form-control form-control-lg"
placeholder="Your email address"
v-model="form.email" />
<p v-if="errors.email" class="form-text text-danger">
<i class="far fa-exclamation-triangle mr-1"></i>
{{ errors.email }}
</p>
</div>
<button
class="btn btn-primary btn-block font-weight-bold"
@click="proceed(tabIndex)"
:disabled="isProceeding || !form.email || !validateEmail()">
<template v-if="isProceeding">
<b-spinner small />
</template>
<template v-else>
Continue
</template>
</button>
</div>
</div>
<div v-else-if="tabIndex === 3" class="card-body">
<div class="d-flex justify-content-center my-3">
<img src="/img/pixelfed-icon-color.png" width="60" alt="Pixelfed logo" />
</div>
<div class="d-flex flex-column align-items-center justify-content-center">
<p class="lead mb-1 text-muted">You've been invited to join</p>
<p class="h3 mb-2">{{ instance.uri }}</p>
</div>
<div class="mt-5">
<div class="form-group">
<label for="username">Password</label>
<input
type="password"
class="form-control form-control-lg"
placeholder="Use a secure password"
minlength="8"
v-model="form.password" />
<p v-if="errors.password" class="form-text text-danger">
<i class="far fa-exclamation-triangle mr-1"></i>
{{ errors.password }}
</p>
</div>
<button
class="btn btn-primary btn-block font-weight-bold"
@click="proceed(tabIndex)"
:disabled="isProceeding || !form.password || form.password.length < 8">
<template v-if="isProceeding">
<b-spinner small />
</template>
<template v-else>
Continue
</template>
</button>
</div>
</div>
<div v-else-if="tabIndex === 4" class="card-body">
<div class="d-flex justify-content-center my-3">
<img src="/img/pixelfed-icon-color.png" width="60" alt="Pixelfed logo" />
</div>
<div class="d-flex flex-column align-items-center justify-content-center">
<p class="lead mb-1 text-muted">You've been invited to join</p>
<p class="h3 mb-2">{{ instance.uri }}</p>
</div>
<div class="mt-5">
<div class="form-group">
<label for="username">Confirm Password</label>
<input
type="password"
class="form-control form-control-lg"
placeholder="Use a secure password"
minlength="8"
v-model="form.password_confirm" />
<p v-if="errors.password_confirm" class="form-text text-danger">
<i class="far fa-exclamation-triangle mr-1"></i>
{{ errors.password_confirm }}
</p>
</div>
<button
class="btn btn-primary btn-block font-weight-bold"
@click="proceed(tabIndex)"
:disabled="isProceeding || !form.password_confirm || form.password !== form.password_confirm">
<template v-if="isProceeding">
<b-spinner small />
</template>
<template v-else>
Continue
</template>
</button>
</div>
</div>
<div v-else-if="tabIndex === 5" class="card-body">
<div class="d-flex justify-content-center my-3">
<img src="/img/pixelfed-icon-color.png" width="60" alt="Pixelfed logo" />
</div>
<div class="d-flex flex-column align-items-center justify-content-center">
<p class="lead mb-1 text-muted">You've been invited to join</p>
<p class="h3 mb-2">{{ instance.uri }}</p>
</div>
<div class="mt-5">
<div class="form-group">
<label for="username">Display Name</label>
<input
type="text"
class="form-control form-control-lg"
placeholder="Add an optional display name"
minlength="8"
v-model="form.display_name" />
<p v-if="errors.display_name" class="form-text text-danger">
<i class="far fa-exclamation-triangle mr-1"></i>
{{ errors.display_name }}
</p>
</div>
<button
class="btn btn-primary btn-block font-weight-bold"
@click="proceed(tabIndex)"
:disabled="isProceeding">
<template v-if="isProceeding">
<b-spinner small />
</template>
<template v-else>
Continue
</template>
</button>
</div>
</div>
<div v-else-if="tabIndex === 6" class="card-body d-flex flex-column">
<div class="d-flex justify-content-center my-3">
<img src="/img/pixelfed-icon-color.png" width="60" alt="Pixelfed logo" />
</div>
<div class="d-flex flex-column align-items-center justify-content-center">
<p class="lead mb-1 text-muted">You've been invited to join</p>
<p class="h3 mb-2">{{ instance.uri }}</p>
</div>
<div class="mt-5 d-flex align-items-center justify-content-center flex-column flex-grow-1">
<b-spinner variant="muted" />
<p class="text-muted">Registering...</p>
</div>
</div>
<div v-else-if="tabIndex === 'invalid-code'" class="card-body d-flex align-items-center justify-content-center">
<div>
<h1 class="text-center">Invalid Invite Code</h1>
<hr>
<p class="text-muted mb-1">The invite code you were provided is not valid, this can happen when:</p>
<ul class="text-muted">
<li>Invite code has typos</li>
<li>Invite code was already used</li>
<li>Invite code has reached max uses</li>
<li>Invite code has expired</li>
<li>You have been rate limited</li>
</ul>
<hr>
<a href="/" class="btn btn-primary btn-block rounded-pill font-weight-bold">Go back home</a>
</div>
</div>
<div v-else class="card-body">
<p>An error occured.</p>
</div>
</div>
</div>
</div>
</template>
<script type="text/javascript">
export default {
props: ['code'],
data() {
return {
instance: {},
inviteConfig: {},
tabIndex: 0,
isProceeding: false,
errors: {
username: undefined,
email: undefined,
password: undefined,
password_confirm: undefined
},
form: {
username: undefined,
email: undefined,
password: undefined,
password_confirm: undefined,
display_name: undefined,
}
}
},
mounted() {
this.fetchInstanceData();
},
methods: {
fetchInstanceData() {
axios.get('/api/v1/instance')
.then(res => {
this.instance = res.data;
})
.then(res => {
this.verifyToken();
})
.catch(err => {
console.log(err);
})
},
verifyToken() {
axios.post('/api/v1.1/auth/invite/admin/verify', {
token: this.code,
})
.then(res => {
this.tabIndex = 1;
this.inviteConfig = res.data;
})
.catch(err => {
this.tabIndex = 'invalid-code';
})
},
checkUsernameAvailability() {
axios.post('/api/v1.1/auth/invite/admin/uc', {
token: this.code,
username: this.form.username
})
.then(res => {
if(res && res.data) {
this.isProceeding = false;
this.tabIndex = 2;
} else {
this.tabIndex = 'invalid-code';
this.isProceeding = false;
}
})
.catch(err => {
if(err.response.data && err.response.data.username) {
this.errors.username = err.response.data.username[0];
this.isProceeding = false;
} else {
this.tabIndex = 'invalid-code';
this.isProceeding = false;
}
})
},
checkEmailAvailability() {
axios.post('/api/v1.1/auth/invite/admin/ec', {
token: this.code,
email: this.form.email
})
.then(res => {
if(res && res.data) {
this.isProceeding = false;
this.tabIndex = 3;
} else {
this.tabIndex = 'invalid-code';
this.isProceeding = false;
}
})
.catch(err => {
if(err.response.data && err.response.data.email) {
this.errors.email = err.response.data.email[0];
this.isProceeding = false;
} else {
this.tabIndex = 'invalid-code';
this.isProceeding = false;
}
})
},
validateEmail() {
if(!this.form.email || !this.form.email.length) {
return false;
}
return /^[a-z0-9.]{1,64}@[a-z0-9.]{1,64}$/i.test(this.form.email);
},
handleRegistration() {
var $form = $('<form>', {
action: '/api/v1.1/auth/invite/admin/re',
method: 'post'
});
let fields = {
'_token': document.head.querySelector('meta[name="csrf-token"]').content,
token: this.code,
username: this.form.username,
name: this.form.display_name,
email: this.form.email,
password: this.form.password,
password_confirm: this.form.password_confirm
};
$.each(fields, function(key, val) {
$('<input>').attr({
type: "hidden",
name: key,
value: val
}).appendTo($form);
});
$form.appendTo('body').submit();
},
proceed(cur) {
this.isProceeding = true;
event.currentTarget.blur();
switch(cur) {
case 1:
this.checkUsernameAvailability();
break;
case 2:
this.checkEmailAvailability();
break;
case 3:
this.isProceeding = false;
this.tabIndex = 4;
break;
case 4:
this.isProceeding = false;
this.tabIndex = 5;
break;
case 5:
this.tabIndex = 6;
this.handleRegistration();
break;
}
}
}
}
</script>
<style lang="scss">
.admin-invite-component {
font-family: var(--font-family-sans-serif);
&-inner {
display: flex;
width: 100wv;
height: 100vh;
justify-content: center;
align-items: center;
.card {
width: 100%;
color: #fff;
padding: 1.25rem 2.5rem;
border-radius: 10px;
min-height: 530px;
@media(min-width: 768px) {
width: 30%;
}
label {
color: var(--muted);
font-weight: bold;
text-transform: uppercase;
}
.login-link {
margin-top: 10px;
font-weight: 600;
}
.register-terms {
font-size: 12px;
color: var(--muted);
}
.form-control {
color: #fff;
}
.admin-message {
margin-top: 20px;
border: 1px solid var(--dropdown-item-hover-color);
color: var(--text-lighter);
padding: 1rem;
border-radius: 5px;
}
}
}
}
</style>

4
resources/assets/js/admin_invite.js vendored Normal file
View file

@ -0,0 +1,4 @@
Vue.component(
'admin-invite',
require('./../components/invite/AdminInvite.vue').default
);

View file

@ -0,0 +1,21 @@
@extends('layouts.blank')
@section('content')
<admin-invite code="{{$code}}" />
@endsection
@push('scripts')
<script type="text/javascript" src="{{ mix('js/admin_invite.js') }}"></script>
<script type="text/javascript">App.boot();</script>
@endpush
@push('styles')
<link href="{{ mix('css/spa.css') }}" rel="stylesheet" data-stylesheet="light">
<style type="text/css">
body {
background: #4776E6;
background: -webkit-linear-gradient(to right, #8E54E9, #4776E6);
background: linear-gradient(to right, #8E54E9, #4776E6);
}
</style>
@endpush

View file

@ -155,6 +155,10 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
Route::post('iar', 'Api\ApiV1Dot1Controller@inAppRegistration');
Route::post('iarc', 'Api\ApiV1Dot1Controller@inAppRegistrationConfirm');
Route::get('iarer', 'Api\ApiV1Dot1Controller@inAppRegistrationEmailRedirect');
Route::post('invite/admin/verify', 'AdminInviteController@apiVerifyCheck')->middleware('throttle:20,120');
Route::post('invite/admin/uc', 'AdminInviteController@apiUsernameCheck')->middleware('throttle:20,120');
Route::post('invite/admin/ec', 'AdminInviteController@apiEmailCheck')->middleware('throttle:10,1440');
});
});

View file

@ -587,6 +587,9 @@ Route::domain(config('pixelfed.domain.app'))->middleware(['validemail', 'twofact
Route::get('privacy', 'MobileController@privacy');
});
Route::get('auth/invite/a/{code}', 'AdminInviteController@index');
Route::post('api/v1.1/auth/invite/admin/re', 'AdminInviteController@apiRegister')->middleware('throttle:5,1440');
Route::get('stories/{username}', 'ProfileController@stories');
Route::get('p/{id}', 'StatusController@shortcodeRedirect');
Route::get('c/{collection}', 'CollectionController@show');