mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-12-22 13:03:16 +00:00
commit
e7a8dec1a9
17 changed files with 11612 additions and 1775 deletions
|
@ -3,9 +3,11 @@
|
||||||
## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.11.4...dev)
|
## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.11.4...dev)
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
- Mobile App Registration ([#3829](https://github.com/pixelfed/pixelfed/pull/3829))
|
||||||
- Portfolios ([#3705](https://github.com/pixelfed/pixelfed/pull/3705))
|
- Portfolios ([#3705](https://github.com/pixelfed/pixelfed/pull/3705))
|
||||||
- Server Directory ([#3762](https://github.com/pixelfed/pixelfed/pull/3762))
|
- Server Directory ([#3762](https://github.com/pixelfed/pixelfed/pull/3762))
|
||||||
- Manually verify email address (php artisan user:verifyemail) ([682f5f0f](https://github.com/pixelfed/pixelfed/commit/682f5f0f))
|
- 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))
|
||||||
|
|
||||||
### Updates
|
### Updates
|
||||||
- Update ApiV1Controller, include self likes in favourited_by endpoint ([58b331d2](https://github.com/pixelfed/pixelfed/commit/58b331d2))
|
- Update ApiV1Controller, include self likes in favourited_by endpoint ([58b331d2](https://github.com/pixelfed/pixelfed/commit/58b331d2))
|
||||||
|
@ -26,8 +28,7 @@
|
||||||
- Update landing view, add `app.name` and `app.short_description` for better customizability ([bda9d16b](https://github.com/pixelfed/pixelfed/commit/bda9d16b))
|
- Update landing view, add `app.name` and `app.short_description` for better customizability ([bda9d16b](https://github.com/pixelfed/pixelfed/commit/bda9d16b))
|
||||||
- Update Profile, fix avatarUrl paths. Fixes #3559 #3634 ([989e4249](https://github.com/pixelfed/pixelfed/commit/989e4249))
|
- Update Profile, fix avatarUrl paths. Fixes #3559 #3634 ([989e4249](https://github.com/pixelfed/pixelfed/commit/989e4249))
|
||||||
- Update InboxPipeline, bump request timeout from 5s to 60s ([bb120019](https://github.com/pixelfed/pixelfed/commit/bb120019))
|
- Update InboxPipeline, bump request timeout from 5s to 60s ([bb120019](https://github.com/pixelfed/pixelfed/commit/bb120019))
|
||||||
- Update web routes, fix missing hom route ([a9f4ddfc](https://github.com/pixelfed/pixelfed/commit/a9f4ddfc))
|
- Update web routes, fix missing home route ([a9f4ddfc](https://github.com/pixelfed/pixelfed/commit/a9f4ddfc))
|
||||||
- ([](https://github.com/pixelfed/pixelfed/commit/))
|
|
||||||
|
|
||||||
## [v0.11.4 (2022-10-04)](https://github.com/pixelfed/pixelfed/compare/v0.11.3...v0.11.4)
|
## [v0.11.4 (2022-10-04)](https://github.com/pixelfed/pixelfed/compare/v0.11.3...v0.11.4)
|
||||||
|
|
||||||
|
|
123
app/Console/Commands/AvatarStorage.php
Normal file
123
app/Console/Commands/AvatarStorage.php
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use App\Avatar;
|
||||||
|
use App\User;
|
||||||
|
use Storage;
|
||||||
|
use App\Util\Lexer\PrettyNumber;
|
||||||
|
|
||||||
|
class AvatarStorage extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'avatar:storage';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Manage avatar storage';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$this->info('Pixelfed Avatar Storage Manager');
|
||||||
|
$this->line(' ');
|
||||||
|
$segments = [
|
||||||
|
[
|
||||||
|
'Local',
|
||||||
|
Avatar::whereNull('is_remote')->count(),
|
||||||
|
PrettyNumber::size(Avatar::whereNull('is_remote')->sum('size'))
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'Remote',
|
||||||
|
Avatar::whereNotNull('is_remote')->count(),
|
||||||
|
PrettyNumber::size(Avatar::whereNotNull('is_remote')->sum('size'))
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'Cached (CDN)',
|
||||||
|
Avatar::whereNotNull('cdn_url')->count(),
|
||||||
|
PrettyNumber::size(Avatar::whereNotNull('cdn_url')->sum('size'))
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'Uncached',
|
||||||
|
Avatar::whereNull('is_remote')->whereNull('cdn_url')->count(),
|
||||||
|
PrettyNumber::size(Avatar::whereNull('is_remote')->whereNull('cdn_url')->sum('size'))
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'------------',
|
||||||
|
'----------',
|
||||||
|
'-----'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'Total',
|
||||||
|
Avatar::count(),
|
||||||
|
PrettyNumber::size(Avatar::sum('size'))
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$this->table(
|
||||||
|
['Segment', 'Count', 'Space Used'],
|
||||||
|
$segments
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->line(' ');
|
||||||
|
|
||||||
|
if(config_cache('pixelfed.cloud_storage')) {
|
||||||
|
$this->info('✅ - Cloud storage configured');
|
||||||
|
$this->line(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config_cache('instance.avatar.local_to_cloud')) {
|
||||||
|
$this->info('✅ - Store avatars on cloud filesystem');
|
||||||
|
$this->line(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(config_cache('pixelfed.cloud_storage') && config_cache('instance.avatar.local_to_cloud')) {
|
||||||
|
$disk = Storage::disk(config_cache('filesystems.cloud'));
|
||||||
|
$exists = $disk->exists('cache/avatars/default.jpg');
|
||||||
|
$state = $exists ? '✅' : '❌';
|
||||||
|
$msg = $state . ' - Cloud default avatar exists';
|
||||||
|
$this->info($msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
$choice = $this->choice(
|
||||||
|
'Select action:',
|
||||||
|
[
|
||||||
|
'Upload default avatar to cloud',
|
||||||
|
'Move local avatars to cloud',
|
||||||
|
'Move cloud avatars to local'
|
||||||
|
],
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->handleChoice($choice);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleChoice($id)
|
||||||
|
{
|
||||||
|
switch ($id) {
|
||||||
|
case 'Upload default avatar to cloud':
|
||||||
|
return $this->uploadDefaultAvatar();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function uploadDefaultAvatar()
|
||||||
|
{
|
||||||
|
$disk = Storage::disk(config_cache('filesystems.cloud'));
|
||||||
|
$disk->put('cache/avatars/default.jpg', Storage::get('public/avatars/default.jpg'));
|
||||||
|
Avatar::whereMediaPath('public/avatars/default.jpg')->update(['cdn_url' => $disk->url('cache/avatars/default.jpg')]);
|
||||||
|
$this->info('Successfully uploaded default avatar to cloud storage!');
|
||||||
|
$this->info($disk->url('cache/avatars/default.jpg'));
|
||||||
|
}
|
||||||
|
}
|
82
app/Console/Commands/UserRegistrationMagicLink.php
Normal file
82
app/Console/Commands/UserRegistrationMagicLink.php
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use App\EmailVerification;
|
||||||
|
use App\User;
|
||||||
|
|
||||||
|
class UserRegistrationMagicLink extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'user:app-magic-link {--username=} {--email=}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Get the app magic link for users who register in-app but have not recieved the confirmation email';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$username = $this->option('username');
|
||||||
|
$email = $this->option('email');
|
||||||
|
if(!$username && !$email) {
|
||||||
|
$this->error('Please provide the username or email as arguments');
|
||||||
|
$this->line(' ');
|
||||||
|
$this->info('Example: ');
|
||||||
|
$this->info('php artisan user:app-magic-link --username=dansup');
|
||||||
|
$this->info('php artisan user:app-magic-link --email=dansup@pixelfed.com');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$user = User::when($username, function($q, $username) {
|
||||||
|
return $q->whereUsername($username);
|
||||||
|
})
|
||||||
|
->when($email, function($q, $email) {
|
||||||
|
return $q->whereEmail($email);
|
||||||
|
})
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if(!$user) {
|
||||||
|
$this->error('We cannot find any matching accounts');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($user->email_verified_at) {
|
||||||
|
$this->error('User already verified email address');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$user->register_source || $user->register_source !== 'app' || !$user->app_register_token) {
|
||||||
|
$this->error('User did not register via app');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$verify = EmailVerification::whereUserId($user->id)->first();
|
||||||
|
|
||||||
|
if(!$verify) {
|
||||||
|
$this->error('Cannot find user verification codes');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$appUrl = 'pixelfed://confirm-account/'. $user->app_register_token . '?rt=' . $verify->random_token;
|
||||||
|
$this->line(' ');
|
||||||
|
$this->info('Magic link found! Copy the following link and send to user');
|
||||||
|
$this->line(' ');
|
||||||
|
$this->line(' ');
|
||||||
|
$this->info($appUrl);
|
||||||
|
$this->line(' ');
|
||||||
|
$this->line(' ');
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,12 +14,18 @@ use App\EmailVerification;
|
||||||
use App\Status;
|
use App\Status;
|
||||||
use App\Report;
|
use App\Report;
|
||||||
use App\Profile;
|
use App\Profile;
|
||||||
|
use App\User;
|
||||||
use App\Services\AccountService;
|
use App\Services\AccountService;
|
||||||
use App\Services\StatusService;
|
use App\Services\StatusService;
|
||||||
use App\Services\ProfileStatusService;
|
use App\Services\ProfileStatusService;
|
||||||
|
use App\Util\Lexer\RestrictedNames;
|
||||||
|
use App\Services\EmailService;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Jenssegers\Agent\Agent;
|
use Jenssegers\Agent\Agent;
|
||||||
use Mail;
|
use Mail;
|
||||||
use App\Mail\PasswordChange;
|
use App\Mail\PasswordChange;
|
||||||
|
use App\Mail\ConfirmAppEmail;
|
||||||
|
|
||||||
class ApiV1Dot1Controller extends Controller
|
class ApiV1Dot1Controller extends Controller
|
||||||
{
|
{
|
||||||
|
@ -402,4 +408,146 @@ class ApiV1Dot1Controller extends Controller
|
||||||
|
|
||||||
return $this->json($res);
|
return $this->json($res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function inAppRegistrationPreFlightCheck(Request $request)
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'open' => config('pixelfed.open_registration'),
|
||||||
|
'iara' => config('pixelfed.allow_app_registration')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function inAppRegistration(Request $request)
|
||||||
|
{
|
||||||
|
abort_if($request->user(), 404);
|
||||||
|
abort_unless(config('pixelfed.open_registration'), 404);
|
||||||
|
abort_unless(config('pixelfed.allow_app_registration'), 404);
|
||||||
|
abort_unless($request->hasHeader('X-PIXELFED-APP'), 403);
|
||||||
|
$this->validate($request, [
|
||||||
|
'email' => [
|
||||||
|
'required',
|
||||||
|
'string',
|
||||||
|
'email',
|
||||||
|
'max:255',
|
||||||
|
'unique:users',
|
||||||
|
function ($attribute, $value, $fail) {
|
||||||
|
$banned = EmailService::isBanned($value);
|
||||||
|
if($banned) {
|
||||||
|
return $fail('Email is invalid.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'username' => [
|
||||||
|
'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.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'password' => 'required|string|min:8',
|
||||||
|
// 'avatar' => 'required|mimetypes:image/jpeg,image/png|max:15000',
|
||||||
|
// 'bio' => 'required|max:140'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$email = $request->input('email');
|
||||||
|
$username = $request->input('username');
|
||||||
|
$password = $request->input('password');
|
||||||
|
|
||||||
|
if(config('database.default') == 'pgsql') {
|
||||||
|
$username = strtolower($username);
|
||||||
|
$email = strtolower($email);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = new User;
|
||||||
|
$user->name = $username;
|
||||||
|
$user->username = $username;
|
||||||
|
$user->email = $email;
|
||||||
|
$user->password = Hash::make($password);
|
||||||
|
$user->register_source = 'app';
|
||||||
|
$user->app_register_ip = $request->ip();
|
||||||
|
$user->app_register_token = Str::random(32);
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
$rtoken = Str::random(mt_rand(64, 70));
|
||||||
|
|
||||||
|
$verify = new EmailVerification();
|
||||||
|
$verify->user_id = $user->id;
|
||||||
|
$verify->email = $user->email;
|
||||||
|
$verify->user_token = $user->app_register_token;
|
||||||
|
$verify->random_token = $rtoken;
|
||||||
|
$verify->save();
|
||||||
|
|
||||||
|
$appUrl = 'pixelfed://confirm-account/'. $user->app_register_token . '?rt=' . $rtoken;
|
||||||
|
|
||||||
|
Mail::to($user->email)->send(new ConfirmAppEmail($verify, $appUrl));
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function inAppRegistrationConfirm(Request $request)
|
||||||
|
{
|
||||||
|
abort_if($request->user(), 404);
|
||||||
|
abort_unless(config('pixelfed.open_registration'), 404);
|
||||||
|
abort_unless(config('pixelfed.allow_app_registration'), 404);
|
||||||
|
abort_unless($request->hasHeader('X-PIXELFED-APP'), 403);
|
||||||
|
$this->validate($request, [
|
||||||
|
'user_token' => 'required',
|
||||||
|
'random_token' => 'required',
|
||||||
|
'email' => 'required'
|
||||||
|
]);
|
||||||
|
|
||||||
|
$verify = EmailVerification::whereEmail($request->input('email'))
|
||||||
|
->whereUserToken($request->input('user_token'))
|
||||||
|
->whereRandomToken($request->input('random_token'))
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if(!$verify) {
|
||||||
|
return response()->json(['error' => 'Invalid tokens'], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::findOrFail($verify->user_id);
|
||||||
|
$user->email_verified_at = now();
|
||||||
|
$user->last_active_at = now();
|
||||||
|
$user->save();
|
||||||
|
|
||||||
|
$verify->delete();
|
||||||
|
|
||||||
|
$token = $user->createToken('Pixelfed');
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'access_token' => $token->accessToken
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,6 +307,7 @@ class PublicApiController extends Controller
|
||||||
$user = $request->user();
|
$user = $request->user();
|
||||||
$filtered = $user ? UserFilterService::filters($user->profile_id) : [];
|
$filtered = $user ? UserFilterService::filters($user->profile_id) : [];
|
||||||
|
|
||||||
|
$hideNsfw = config('instance.hide_nsfw_on_public_feeds');
|
||||||
if(config('exp.cached_public_timeline') == false) {
|
if(config('exp.cached_public_timeline') == false) {
|
||||||
if($min || $max) {
|
if($min || $max) {
|
||||||
$dir = $min ? '>' : '<';
|
$dir = $min ? '>' : '<';
|
||||||
|
@ -322,6 +323,9 @@ class PublicApiController extends Controller
|
||||||
->whereNull(['in_reply_to_id', 'reblog_of_id'])
|
->whereNull(['in_reply_to_id', 'reblog_of_id'])
|
||||||
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||||
->whereLocal(true)
|
->whereLocal(true)
|
||||||
|
->when($hideNsfw, function($q, $hideNsfw) {
|
||||||
|
return $q->where('is_nsfw', false);
|
||||||
|
})
|
||||||
->whereScope('public')
|
->whereScope('public')
|
||||||
->orderBy('id', 'desc')
|
->orderBy('id', 'desc')
|
||||||
->limit($limit)
|
->limit($limit)
|
||||||
|
@ -365,6 +369,9 @@ class PublicApiController extends Controller
|
||||||
->whereNull(['in_reply_to_id', 'reblog_of_id'])
|
->whereNull(['in_reply_to_id', 'reblog_of_id'])
|
||||||
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||||
->whereLocal(true)
|
->whereLocal(true)
|
||||||
|
->when($hideNsfw, function($q, $hideNsfw) {
|
||||||
|
return $q->where('is_nsfw', false);
|
||||||
|
})
|
||||||
->whereScope('public')
|
->whereScope('public')
|
||||||
->orderBy('id', 'desc')
|
->orderBy('id', 'desc')
|
||||||
->limit($limit)
|
->limit($limit)
|
||||||
|
@ -608,6 +615,7 @@ class PublicApiController extends Controller
|
||||||
$amin = SnowflakeService::byDate(now()->subDays(config('federation.network_timeline_days_falloff')));
|
$amin = SnowflakeService::byDate(now()->subDays(config('federation.network_timeline_days_falloff')));
|
||||||
|
|
||||||
$filtered = $user ? UserFilterService::filters($user->profile_id) : [];
|
$filtered = $user ? UserFilterService::filters($user->profile_id) : [];
|
||||||
|
$hideNsfw = config('instance.hide_nsfw_on_public_feeds');
|
||||||
|
|
||||||
if(config('instance.timeline.network.cached') == false) {
|
if(config('instance.timeline.network.cached') == false) {
|
||||||
if($min || $max) {
|
if($min || $max) {
|
||||||
|
@ -620,7 +628,10 @@ class PublicApiController extends Controller
|
||||||
'scope',
|
'scope',
|
||||||
'created_at',
|
'created_at',
|
||||||
)
|
)
|
||||||
->where('id', $dir, $id)
|
->where('id', $dir, $id)
|
||||||
|
->when($hideNsfw, function($q, $hideNsfw) {
|
||||||
|
return $q->where('is_nsfw', false);
|
||||||
|
})
|
||||||
->whereNull(['in_reply_to_id', 'reblog_of_id'])
|
->whereNull(['in_reply_to_id', 'reblog_of_id'])
|
||||||
->whereNotIn('profile_id', $filtered)
|
->whereNotIn('profile_id', $filtered)
|
||||||
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||||
|
@ -648,6 +659,9 @@ class PublicApiController extends Controller
|
||||||
)
|
)
|
||||||
->whereNull(['in_reply_to_id', 'reblog_of_id'])
|
->whereNull(['in_reply_to_id', 'reblog_of_id'])
|
||||||
->whereNotIn('profile_id', $filtered)
|
->whereNotIn('profile_id', $filtered)
|
||||||
|
->when($hideNsfw, function($q, $hideNsfw) {
|
||||||
|
return $q->where('is_nsfw', false);
|
||||||
|
})
|
||||||
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||||
->whereNotNull('uri')
|
->whereNotNull('uri')
|
||||||
->whereScope('public')
|
->whereScope('public')
|
||||||
|
|
|
@ -13,6 +13,7 @@ use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Image as Intervention;
|
use Image as Intervention;
|
||||||
|
use Storage;
|
||||||
|
|
||||||
class AvatarOptimize implements ShouldQueue
|
class AvatarOptimize implements ShouldQueue
|
||||||
{
|
{
|
||||||
|
@ -63,6 +64,13 @@ class AvatarOptimize implements ShouldQueue
|
||||||
$avatar->save();
|
$avatar->save();
|
||||||
Cache::forget('avatar:' . $avatar->profile_id);
|
Cache::forget('avatar:' . $avatar->profile_id);
|
||||||
$this->deleteOldAvatar($avatar->media_path, $this->current);
|
$this->deleteOldAvatar($avatar->media_path, $this->current);
|
||||||
|
|
||||||
|
if(config_cache('pixelfed.cloud_storage') && config_cache('instance.avatar.local_to_cloud')) {
|
||||||
|
$this->uploadToCloud($avatar);
|
||||||
|
} else {
|
||||||
|
$avatar->cdn_url = null;
|
||||||
|
$avatar->save();
|
||||||
|
}
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,4 +87,17 @@ class AvatarOptimize implements ShouldQueue
|
||||||
@unlink($current);
|
@unlink($current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function uploadToCloud($avatar)
|
||||||
|
{
|
||||||
|
$base = 'cache/avatars/' . $avatar->profile_id;
|
||||||
|
$disk = Storage::disk(config('filesystems.cloud'));
|
||||||
|
$disk->deleteDirectory($base);
|
||||||
|
$path = $base . '/' . 'a' . strtolower(Str::random(random_int(3,6))) . $avatar->change_count . '.' . pathinfo($avatar->media_path, PATHINFO_EXTENSION);
|
||||||
|
$url = $disk->put($path, Storage::get($avatar->media_path));
|
||||||
|
$avatar->cdn_url = $disk->url($path);
|
||||||
|
$avatar->save();
|
||||||
|
Storage::delete($avatar->media_path);
|
||||||
|
Cache::forget('avatar:' . $avatar->profile_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,12 +166,13 @@ class StatusEntityLexer implements ShouldQueue
|
||||||
if(config_cache('pixelfed.bouncer.enabled')) {
|
if(config_cache('pixelfed.bouncer.enabled')) {
|
||||||
Bouncer::get($status);
|
Bouncer::get($status);
|
||||||
}
|
}
|
||||||
|
$hideNsfw = config('instance.hide_nsfw_on_public_feeds');
|
||||||
if( $status->uri == null &&
|
if( $status->uri == null &&
|
||||||
$status->scope == 'public' &&
|
$status->scope == 'public' &&
|
||||||
in_array($status->type, $types) &&
|
in_array($status->type, $types) &&
|
||||||
$status->in_reply_to_id === null &&
|
$status->in_reply_to_id === null &&
|
||||||
$status->reblog_of_id === null
|
$status->reblog_of_id === null &&
|
||||||
|
($hideNsfw ? $status->is_nsfw == false : true)
|
||||||
) {
|
) {
|
||||||
PublicTimelineService::add($status->id);
|
PublicTimelineService::add($status->id);
|
||||||
}
|
}
|
||||||
|
|
67
app/Mail/ConfirmAppEmail.php
Normal file
67
app/Mail/ConfirmAppEmail.php
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<?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 ConfirmAppEmail extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public $verify;
|
||||||
|
public $appUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __construct($verify, $url)
|
||||||
|
{
|
||||||
|
$this->verify = $verify;
|
||||||
|
$this->appUrl = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message envelope.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Mail\Mailables\Envelope
|
||||||
|
*/
|
||||||
|
public function envelope()
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
subject: 'Complete Account Registration',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message content definition.
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Mail\Mailables\Content
|
||||||
|
*/
|
||||||
|
public function content()
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
markdown: 'emails.confirm_app_email',
|
||||||
|
with: [
|
||||||
|
'verify' => $this->verify,
|
||||||
|
'appUrl' => $this->appUrl
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachments for the message.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function attachments()
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,9 +75,13 @@ class NetworkTimelineService
|
||||||
public static function warmCache($force = false, $limit = 100)
|
public static function warmCache($force = false, $limit = 100)
|
||||||
{
|
{
|
||||||
if(self::count() == 0 || $force == true) {
|
if(self::count() == 0 || $force == true) {
|
||||||
|
$hideNsfw = config('instance.hide_nsfw_on_public_feeds');
|
||||||
Redis::del(self::CACHE_KEY);
|
Redis::del(self::CACHE_KEY);
|
||||||
$ids = Status::whereNotNull('uri')
|
$ids = Status::whereNotNull('uri')
|
||||||
->whereScope('public')
|
->whereScope('public')
|
||||||
|
->when($hideNsfw, function($q, $hideNsfw) {
|
||||||
|
return $q->where('is_nsfw', false);
|
||||||
|
})
|
||||||
->whereNull('in_reply_to_id')
|
->whereNull('in_reply_to_id')
|
||||||
->whereNull('reblog_of_id')
|
->whereNull('reblog_of_id')
|
||||||
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||||
|
|
|
@ -75,9 +75,13 @@ class PublicTimelineService {
|
||||||
public static function warmCache($force = false, $limit = 100)
|
public static function warmCache($force = false, $limit = 100)
|
||||||
{
|
{
|
||||||
if(self::count() == 0 || $force == true) {
|
if(self::count() == 0 || $force == true) {
|
||||||
|
$hideNsfw = config('instance.hide_nsfw_on_public_feeds');
|
||||||
Redis::del(self::CACHE_KEY);
|
Redis::del(self::CACHE_KEY);
|
||||||
$ids = Status::whereNull('uri')
|
$ids = Status::whereNull('uri')
|
||||||
->whereNull('in_reply_to_id')
|
->whereNull('in_reply_to_id')
|
||||||
|
->when($hideNsfw, function($q, $hideNsfw) {
|
||||||
|
return $q->where('is_nsfw', false);
|
||||||
|
})
|
||||||
->whereNull('reblog_of_id')
|
->whereNull('reblog_of_id')
|
||||||
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
->whereIn('type', ['photo', 'photo:album', 'video', 'video:album', 'photo:video:album'])
|
||||||
->whereScope('public')
|
->whereScope('public')
|
||||||
|
|
|
@ -91,4 +91,10 @@ return [
|
||||||
'profile' => env('INSTANCE_PROFILE_EMBEDS', true),
|
'profile' => env('INSTANCE_PROFILE_EMBEDS', true),
|
||||||
'post' => env('INSTANCE_POST_EMBEDS', true),
|
'post' => env('INSTANCE_POST_EMBEDS', true),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'hide_nsfw_on_public_feeds' => env('PF_HIDE_NSFW_ON_PUBLIC_FEEDS', false),
|
||||||
|
|
||||||
|
'avatar' => [
|
||||||
|
'local_to_cloud' => env('PF_LOCAL_AVATAR_TO_CLOUD', false)
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
|
@ -276,4 +276,6 @@ return [
|
||||||
'media_fast_process' => env('PF_MEDIA_FAST_PROCESS', true),
|
'media_fast_process' => env('PF_MEDIA_FAST_PROCESS', true),
|
||||||
|
|
||||||
'max_altext_length' => env('PF_MEDIA_MAX_ALTTEXT_LENGTH', 1000),
|
'max_altext_length' => env('PF_MEDIA_MAX_ALTTEXT_LENGTH', 1000),
|
||||||
|
|
||||||
|
'allow_app_registration' => env('PF_ALLOW_APP_REGISTRATION', true),
|
||||||
];
|
];
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->string('register_source')->default('web')->nullable()->index();
|
||||||
|
$table->string('app_register_token')->nullable();
|
||||||
|
$table->string('app_register_ip')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('register_source');
|
||||||
|
$table->dropColumn('app_register_token');
|
||||||
|
$table->dropColumn('app_register_ip');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
12837
package-lock.json
generated
12837
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -14,11 +14,14 @@
|
||||||
"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",
|
||||||
|
"laravel-echo": "^1.12.0",
|
||||||
|
"laravel-mix-make-file-hash": "^2.2.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"popper.js": "^1.16.1",
|
"popper.js": "^1.16.1",
|
||||||
|
"pusher-js": "^7.1.1-beta",
|
||||||
"resolve-url-loader": "^5.0.0",
|
"resolve-url-loader": "^5.0.0",
|
||||||
"sass": "^1.52.1",
|
"sass": "^1.52.1",
|
||||||
"sass-loader": "^7.3.1",
|
"sass-loader": "^12.3.0",
|
||||||
"vue": "^2.6.14",
|
"vue": "^2.6.14",
|
||||||
"vue-loader": "^15.9.8",
|
"vue-loader": "^15.9.8",
|
||||||
"vue-masonry-css": "^1.0.3",
|
"vue-masonry-css": "^1.0.3",
|
||||||
|
@ -36,6 +39,7 @@
|
||||||
"bigpicture": "^2.6.2",
|
"bigpicture": "^2.6.2",
|
||||||
"blurhash": "^1.1.3",
|
"blurhash": "^1.1.3",
|
||||||
"bootstrap-vue": "^2.22.0",
|
"bootstrap-vue": "^2.22.0",
|
||||||
|
"caniuse-lite": "^1.0.30001418",
|
||||||
"chart.js": "^2.7.2",
|
"chart.js": "^2.7.2",
|
||||||
"filesize": "^3.6.1",
|
"filesize": "^3.6.1",
|
||||||
"hls.js": "^1.1.5",
|
"hls.js": "^1.1.5",
|
||||||
|
@ -44,7 +48,6 @@
|
||||||
"jquery-scroll-lock": "^3.1.3",
|
"jquery-scroll-lock": "^3.1.3",
|
||||||
"jquery.scrollbar": "^0.2.11",
|
"jquery.scrollbar": "^0.2.11",
|
||||||
"js-cookie": "^2.2.0",
|
"js-cookie": "^2.2.0",
|
||||||
"laravel-echo": "^1.11.7",
|
|
||||||
"laravel-mix": "^6.0.43",
|
"laravel-mix": "^6.0.43",
|
||||||
"plyr": "^3.7.2",
|
"plyr": "^3.7.2",
|
||||||
"promise-polyfill": "8.1.0",
|
"promise-polyfill": "8.1.0",
|
||||||
|
|
18
resources/views/emails/confirm_app_email.blade.php
Normal file
18
resources/views/emails/confirm_app_email.blade.php
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<x-mail::message>
|
||||||
|
# Complete Account Registration
|
||||||
|
|
||||||
|
Hello **{{'@'.$verify->user->username}}**,
|
||||||
|
|
||||||
|
You are moments away from finishing your new account registration!
|
||||||
|
|
||||||
|
@component('mail::button', ['url' => $appUrl])
|
||||||
|
Complete Account Registration
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
<p style="color: #d6d3d1;font-size: 10pt">Make sure you click on the button from your mobile device, opening the link using a desktop browser won't work.</p>
|
||||||
|
<br>
|
||||||
|
<p>If you did not create this account, please disregard this email.</p>
|
||||||
|
|
||||||
|
Thanks,<br>
|
||||||
|
<a href="{{ config('app.url') }}">{{ config('pixelfed.domain.app') }}</a>
|
||||||
|
</x-mail::message>
|
|
@ -149,6 +149,12 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
|
||||||
Route::group(['prefix' => 'directory'], function () use($middleware) {
|
Route::group(['prefix' => 'directory'], function () use($middleware) {
|
||||||
Route::get('listing', 'PixelfedDirectoryController@get');
|
Route::get('listing', 'PixelfedDirectoryController@get');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::group(['prefix' => 'auth'], function () use($middleware) {
|
||||||
|
Route::get('iarpfc', 'Api\ApiV1Dot1Controller@inAppRegistrationPreFlightCheck');
|
||||||
|
Route::post('iar', 'Api\ApiV1Dot1Controller@inAppRegistration');
|
||||||
|
Route::post('iarc', 'Api\ApiV1Dot1Controller@inAppRegistrationConfirm');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::group(['prefix' => 'live'], function() use($middleware) {
|
Route::group(['prefix' => 'live'], function() use($middleware) {
|
||||||
|
|
Loading…
Reference in a new issue