diff --git a/.env.docker b/.env.docker index a15e15431..8367c0032 100644 --- a/.env.docker +++ b/.env.docker @@ -67,7 +67,7 @@ ADMIN_DOMAIN="${APP_DOMAIN}" # @default "false" # @see https://docs.pixelfed.org/technical-documentation/config/#config_cache # @dottie/validate required,boolean -ENABLE_CONFIG_CACHE="false" +ENABLE_CONFIG_CACHE="true" # Enable/disable new local account registrations. # diff --git a/.env.example b/.env.example index d4d7228d1..79ce65337 100644 --- a/.env.example +++ b/.env.example @@ -8,6 +8,7 @@ OPEN_REGISTRATION="false" ENFORCE_EMAIL_VERIFICATION="false" PF_MAX_USERS="1000" OAUTH_ENABLED="true" +ENABLE_CONFIG_CACHE=true # Media Configuration PF_OPTIMIZE_IMAGES="true" diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e75ba0c8..b532a454f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ # Release Notes -## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.11.13...dev) +## [Unreleased](https://github.com/pixelfed/pixelfed/compare/v0.12.1...dev) + +### Updates +- Update DirectMessageController, add 72 hour delay for new accounts before they can send a DM ([61d105fd](https://github.com/pixelfed/pixelfed/commit/61d105fd)) +- Update AdminCuratedRegisterController, increase message length from 1000 to 3000 ([9a5e3471](https://github.com/pixelfed/pixelfed/commit/)) +- ([](https://github.com/pixelfed/pixelfed/commit/9a5e3471)) + +## [v0.12.1 (2024-05-07)](https://github.com/pixelfed/pixelfed/compare/v0.12.0...v0.12.1) + +### Updates +- Update ApiV1Dot1Controller, fix in app registration bug that prevents proper auth flow due to missing oauth scopes ([cbf996c9](https://github.com/pixelfed/pixelfed/commit/cbf996c9)) +- Update ConfigCacheService, fix database race condition and fallback to file config and enable by default ([60a62b59](https://github.com/pixelfed/pixelfed/commit/60a62b59)) + +## [v0.12.0 (2024-04-29)](https://github.com/pixelfed/pixelfed/compare/v0.11.13...v0.12.0) ### Updates @@ -66,7 +79,11 @@ - Update UnfollowPipeline, fix follower count cache bug ([6bdf73de](https://github.com/pixelfed/pixelfed/commit/6bdf73de)) - Update VideoPresenter component, add webkit-playsinline attribute to video element to prevent the full screen video player ([ad032916](https://github.com/pixelfed/pixelfed/commit/ad032916)) - Update VideoPlayer component, add playsinline attribute to video element ([8af23607](https://github.com/pixelfed/pixelfed/commit/8af23607)) -- ([](https://github.com/pixelfed/pixelfed/commit/)) +- Update StatusController, refactor status embeds ([9a7acc12](https://github.com/pixelfed/pixelfed/commit/9a7acc12)) +- Update ProfileController, refactor profile embeds ([8b8b1ffc](https://github.com/pixelfed/pixelfed/commit/8b8b1ffc)) +- Update profile embed view, fix height bug ([65166570](https://github.com/pixelfed/pixelfed/commit/65166570)) +- Update CustomEmojiService, only return local emoji ([7f8bba44](https://github.com/pixelfed/pixelfed/commit/7f8bba44)) +- Update Like model, increase max likes per day from 500 to 1500 ([4223119f](https://github.com/pixelfed/pixelfed/commit/4223119f)) ## [v0.11.13 (2024-03-05)](https://github.com/pixelfed/pixelfed/compare/v0.11.12...v0.11.13) diff --git a/app/Http/Controllers/AdminCuratedRegisterController.php b/app/Http/Controllers/AdminCuratedRegisterController.php index 7b25ac369..4e1d0eec9 100644 --- a/app/Http/Controllers/AdminCuratedRegisterController.php +++ b/app/Http/Controllers/AdminCuratedRegisterController.php @@ -174,7 +174,7 @@ class AdminCuratedRegisterController extends Controller public function apiMessageSendStore(Request $request, $id) { $this->validate($request, [ - 'message' => 'required|string|min:5|max:1000', + 'message' => 'required|string|min:5|max:3000', ]); $record = CuratedRegister::findOrFail($id); abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email'); diff --git a/app/Http/Controllers/Api/ApiV1Dot1Controller.php b/app/Http/Controllers/Api/ApiV1Dot1Controller.php index 6d051866b..59fb1c93e 100644 --- a/app/Http/Controllers/Api/ApiV1Dot1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Dot1Controller.php @@ -2,914 +2,919 @@ namespace App\Http\Controllers\Api; -use Cache; -use DB; -use App\Http\Controllers\Controller; -use Illuminate\Http\Request; -use League\Fractal; -use League\Fractal\Serializer\ArraySerializer; -use League\Fractal\Pagination\IlluminatePaginatorAdapter; use App\AccountLog; use App\EmailVerification; -use App\Follower; +use App\Http\Controllers\Controller; +use App\Http\Resources\StatusStateless; +use App\Jobs\ReportPipeline\ReportNotifyAdminViaEmail; +use App\Jobs\StatusPipeline\RemoteStatusDelete; +use App\Jobs\StatusPipeline\StatusDelete; +use App\Mail\ConfirmAppEmail; +use App\Mail\PasswordChange; use App\Place; -use App\Status; -use App\Report; use App\Profile; +use App\Report; +use App\Services\AccountService; +use App\Services\BouncerService; +use App\Services\EmailService; +use App\Services\FollowerService; +use App\Services\NetworkTimelineService; +use App\Services\ProfileStatusService; +use App\Services\PublicTimelineService; +use App\Services\StatusService; +use App\Status; use App\StatusArchived; use App\User; use App\UserSetting; -use App\Services\AccountService; -use App\Services\FollowerService; -use App\Services\StatusService; -use App\Services\ProfileStatusService; -use App\Services\LikeService; -use App\Services\ReblogService; -use App\Services\PublicTimelineService; -use App\Services\NetworkTimelineService; use App\Util\Lexer\RestrictedNames; -use App\Services\BouncerService; -use App\Services\EmailService; -use Illuminate\Support\Str; +use Cache; +use DB; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; -use Jenssegers\Agent\Agent; -use Mail; -use App\Mail\PasswordChange; -use App\Mail\ConfirmAppEmail; -use App\Http\Resources\StatusStateless; -use App\Jobs\StatusPipeline\StatusDelete; -use App\Jobs\StatusPipeline\RemoteStatusDelete; -use App\Jobs\ReportPipeline\ReportNotifyAdminViaEmail; use Illuminate\Support\Facades\RateLimiter; +use Illuminate\Support\Str; +use Jenssegers\Agent\Agent; +use League\Fractal; +use League\Fractal\Serializer\ArraySerializer; +use Mail; class ApiV1Dot1Controller extends Controller { - protected $fractal; - - public function __construct() - { - $this->fractal = new Fractal\Manager(); - $this->fractal->setSerializer(new ArraySerializer()); - } - - public function json($res, $code = 200, $headers = []) - { - return response()->json($res, $code, $headers, JSON_UNESCAPED_SLASHES); - } - - public function error($msg, $code = 400, $extra = [], $headers = []) - { - $res = [ - "msg" => $msg, - "code" => $code - ]; - return response()->json(array_merge($res, $extra), $code, $headers, JSON_UNESCAPED_SLASHES); - } - - public function report(Request $request) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('write'), 403); - - $user = $request->user(); - abort_if($user->status != null, 403); - - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $report_type = $request->input('report_type'); - $object_id = $request->input('object_id'); - $object_type = $request->input('object_type'); - - $types = [ - 'spam', - 'sensitive', - 'abusive', - 'underage', - 'violence', - 'copyright', - 'impersonation', - 'scam', - 'terrorism' - ]; - - if (!$report_type || !$object_id || !$object_type) { - return $this->error("Invalid or missing parameters", 400, ["error_code" => "ERROR_INVALID_PARAMS"]); - } - - if (!in_array($report_type, $types)) { - return $this->error("Invalid report type", 400, ["error_code" => "ERROR_TYPE_INVALID"]); - } - - if ($object_type === "user" && $object_id == $user->profile_id) { - return $this->error("Cannot self report", 400, ["error_code" => "ERROR_NO_SELF_REPORTS"]); - } - - $rpid = null; - - switch ($object_type) { - case 'post': - $object = Status::find($object_id); - if (!$object) { - return $this->error("Invalid object id", 400, ["error_code" => "ERROR_INVALID_OBJECT_ID"]); - } - $object_type = 'App\Status'; - $exists = Report::whereUserId($user->id) - ->whereObjectId($object->id) - ->whereObjectType('App\Status') - ->count(); - - $rpid = $object->profile_id; - break; - - case 'user': - $object = Profile::find($object_id); - if (!$object) { - return $this->error("Invalid object id", 400, ["error_code" => "ERROR_INVALID_OBJECT_ID"]); - } - $object_type = 'App\Profile'; - $exists = Report::whereUserId($user->id) - ->whereObjectId($object->id) - ->whereObjectType('App\Profile') - ->count(); - $rpid = $object->id; - break; - - default: - return $this->error("Invalid report type", 400, ["error_code" => "ERROR_REPORT_OBJECT_TYPE_INVALID"]); - break; - } - - if ($exists !== 0) { - return $this->error("Duplicate report", 400, ["error_code" => "ERROR_REPORT_DUPLICATE"]); - } - - if ($object->profile_id == $user->profile_id) { - return $this->error("Cannot self report", 400, ["error_code" => "ERROR_NO_SELF_REPORTS"]); - } - - $report = new Report; - $report->profile_id = $user->profile_id; - $report->user_id = $user->id; - $report->object_id = $object->id; - $report->object_type = $object_type; - $report->reported_profile_id = $rpid; - $report->type = $report_type; - $report->save(); - - if(config('instance.reports.email.enabled')) { - ReportNotifyAdminViaEmail::dispatch($report)->onQueue('default'); - } - - $res = [ - "msg" => "Successfully sent report", - "code" => 200 - ]; - return $this->json($res); - } - - /** - * DELETE /api/v1.1/accounts/avatar - * - * @return \App\Transformer\Api\AccountTransformer - */ - public function deleteAvatar(Request $request) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('write'), 403); - - $user = $request->user(); - abort_if($user->status != null, 403); - - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $avatar = $user->profile->avatar; - - if( $avatar->media_path == 'public/avatars/default.png' || - $avatar->media_path == 'public/avatars/default.jpg' - ) { - return AccountService::get($user->profile_id); - } - - if(is_file(storage_path('app/' . $avatar->media_path))) { - @unlink(storage_path('app/' . $avatar->media_path)); - } - - $avatar->media_path = 'public/avatars/default.jpg'; - $avatar->change_count = $avatar->change_count + 1; - $avatar->save(); - - Cache::forget('avatar:' . $user->profile_id); - Cache::forget("avatar:{$user->profile_id}"); - Cache::forget('user:account:id:'.$user->id); - AccountService::del($user->profile_id); - - return AccountService::get($user->profile_id); - } - - /** - * GET /api/v1.1/accounts/{id}/posts - * - * @return \App\Transformer\Api\StatusTransformer - */ - public function accountPosts(Request $request, $id) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('read'), 403); - - $user = $request->user(); - abort_if($user->status != null, 403); - - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $account = AccountService::get($id); - - if(!$account || $account['username'] !== $request->input('username')) { - return $this->json([]); - } - - $posts = ProfileStatusService::get($id); - - if(!$posts) { - return $this->json([]); - } - - $res = collect($posts) - ->map(function($id) { - return StatusService::get($id); - }) - ->filter(function($post) { - return $post && isset($post['account']); - }) - ->toArray(); - - return $this->json($res); - } - - /** - * POST /api/v1.1/accounts/change-password - * - * @return \App\Transformer\Api\AccountTransformer - */ - public function accountChangePassword(Request $request) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('write'), 403); - - $user = $request->user(); - abort_if($user->status != null, 403); - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $this->validate($request, [ - 'current_password' => 'bail|required|current_password', - 'new_password' => 'required|min:' . config('pixelfed.min_password_length', 8), - 'confirm_password' => 'required|same:new_password' - ],[ - 'current_password' => 'The password you entered is incorrect' - ]); - - $user->password = bcrypt($request->input('new_password')); - $user->save(); - - $log = new AccountLog; - $log->user_id = $user->id; - $log->item_id = $user->id; - $log->item_type = 'App\User'; - $log->action = 'account.edit.password'; - $log->message = 'Password changed'; - $log->link = null; - $log->ip_address = $request->ip(); - $log->user_agent = $request->userAgent(); - $log->save(); - - Mail::to($request->user())->send(new PasswordChange($user)); - - return $this->json(AccountService::get($user->profile_id)); - } - - /** - * GET /api/v1.1/accounts/login-activity - * - * @return array - */ - public function accountLoginActivity(Request $request) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('read'), 403); - - $user = $request->user(); - abort_if($user->status != null, 403); - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - $agent = new Agent(); - $currentIp = $request->ip(); - - $activity = AccountLog::whereUserId($user->id) - ->whereAction('auth.login') - ->orderBy('created_at', 'desc') - ->groupBy('ip_address') - ->limit(10) - ->get() - ->map(function($item) use($agent, $currentIp) { - $agent->setUserAgent($item->user_agent); - return [ - 'id' => $item->id, - 'action' => $item->action, - 'ip' => $item->ip_address, - 'ip_current' => $item->ip_address === $currentIp, - 'is_mobile' => $agent->isMobile(), - 'device' => $agent->device(), - 'browser' => $agent->browser(), - 'platform' => $agent->platform(), - 'created_at' => $item->created_at->format('c') - ]; - }); - - return $this->json($activity); - } - - /** - * GET /api/v1.1/accounts/two-factor - * - * @return array - */ - public function accountTwoFactor(Request $request) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('read'), 403); - - $user = $request->user(); - abort_if($user->status != null, 403); - - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $res = [ - 'active' => (bool) $user->{'2fa_enabled'}, - 'setup_at' => $user->{'2fa_setup_at'} - ]; - return $this->json($res); - } - - /** - * GET /api/v1.1/accounts/emails-from-pixelfed - * - * @return array - */ - public function accountEmailsFromPixelfed(Request $request) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('read'), 403); - - $user = $request->user(); - abort_if($user->status != null, 403); - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - $from = config('mail.from.address'); - - $emailVerifications = EmailVerification::whereUserId($user->id) - ->orderByDesc('id') - ->where('created_at', '>', now()->subDays(14)) - ->limit(10) - ->get() - ->map(function($mail) use($user, $from) { - return [ - 'type' => 'Email Verification', - 'subject' => 'Confirm Email', - 'to_address' => $user->email, - 'from_address' => $from, - 'created_at' => str_replace('@', 'at', $mail->created_at->format('M j, Y @ g:i:s A')) - ]; - }) - ->toArray(); - - $passwordResets = DB::table('password_resets') - ->whereEmail($user->email) - ->where('created_at', '>', now()->subDays(14)) - ->orderByDesc('created_at') - ->limit(10) - ->get() - ->map(function($mail) use($user, $from) { - return [ - 'type' => 'Password Reset', - 'subject' => 'Reset Password Notification', - 'to_address' => $user->email, - 'from_address' => $from, - 'created_at' => str_replace('@', 'at', now()->parse($mail->created_at)->format('M j, Y @ g:i:s A')) - ]; - }) - ->toArray(); - - $passwordChanges = AccountLog::whereUserId($user->id) - ->whereAction('account.edit.password') - ->where('created_at', '>', now()->subDays(14)) - ->orderByDesc('created_at') - ->limit(10) - ->get() - ->map(function($mail) use($user, $from) { - return [ - 'type' => 'Password Change', - 'subject' => 'Password Change', - 'to_address' => $user->email, - 'from_address' => $from, - 'created_at' => str_replace('@', 'at', now()->parse($mail->created_at)->format('M j, Y @ g:i:s A')) - ]; - }) - ->toArray(); - - $res = collect([]) - ->merge($emailVerifications) - ->merge($passwordResets) - ->merge($passwordChanges) - ->sortByDesc('created_at') - ->values(); - - return $this->json($res); - } - - /** - * GET /api/v1.1/accounts/apps-and-applications - * - * @return array - */ - public function accountApps(Request $request) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('read'), 403); - - $user = $request->user(); - abort_if($user->status != null, 403); - - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $res = $user->tokens->sortByDesc('created_at')->take(10)->map(function($token, $key) use($request) { - return [ - 'id' => $token->id, - 'current_session' => $request->user()->token()->id == $token->id, - 'name' => $token->client->name, - 'scopes' => $token->scopes, - 'revoked' => $token->revoked, - 'created_at' => str_replace('@', 'at', now()->parse($token->created_at)->format('M j, Y @ g:i:s A')), - 'expires_at' => str_replace('@', 'at', now()->parse($token->expires_at)->format('M j, Y @ g:i:s A')) - ]; - }); - - return $this->json($res); - } - - public function inAppRegistrationPreFlightCheck(Request $request) - { - return [ - 'open' => (bool) config_cache('pixelfed.open_registration'), - 'iara' => (bool) config_cache('pixelfed.allow_app_registration'), - ]; - } - - public function inAppRegistration(Request $request) - { - abort_if($request->user(), 404); - abort_unless((bool) config_cache('pixelfed.open_registration'), 404); - abort_unless((bool) config_cache('pixelfed.allow_app_registration'), 404); - abort_unless($request->hasHeader('X-PIXELFED-APP'), 403); - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $rl = RateLimiter::attempt('pf:apiv1.1:iar:'.$request->ip(), config('pixelfed.app_registration_rate_limit_attempts', 3), function(){}, config('pixelfed.app_registration_rate_limit_decay', 1800)); - abort_if(!$rl, 400, 'Too many requests'); - - $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', - ]); - - $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(40); - $user->save(); - - $rtoken = Str::random(64); - - $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(); - - $params = http_build_query([ - 'ut' => $user->app_register_token, - 'rt' => $rtoken, - 'ea' => base64_encode($user->email) - ]); - $appUrl = url('/api/v1.1/auth/iarer?'. $params); - - Mail::to($user->email)->send(new ConfirmAppEmail($verify, $appUrl)); - - return response()->json([ - 'success' => true, - ]); - } - - public function inAppRegistrationEmailRedirect(Request $request) - { - $this->validate($request, [ - 'ut' => 'required', - 'rt' => 'required', - 'ea' => 'required' - ]); - $ut = $request->input('ut'); - $rt = $request->input('rt'); - $ea = $request->input('ea'); - $params = http_build_query([ - 'ut' => $ut, - 'rt' => $rt, - 'domain' => config('pixelfed.domain.app'), - 'ea' => $ea - ]); - $url = 'pixelfed://confirm-account/'. $ut . '?' . $params; - return redirect()->away($url); - } - - public function inAppRegistrationConfirm(Request $request) - { - abort_if($request->user(), 404); - abort_unless((bool) config_cache('pixelfed.open_registration'), 404); - abort_unless((bool) config_cache('pixelfed.allow_app_registration'), 404); - abort_unless($request->hasHeader('X-PIXELFED-APP'), 403); - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $rl = RateLimiter::attempt('pf:apiv1.1:iarc:'.$request->ip(), config('pixelfed.app_registration_confirm_rate_limit_attempts', 20), function(){}, config('pixelfed.app_registration_confirm_rate_limit_decay', 1800)); - abort_if(!$rl, 429, 'Too many requests'); - - $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); - } - - if($verify->created_at->lt(now()->subHours(24))) { - $verify->delete(); - 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(); - - $token = $user->createToken('Pixelfed'); - - return response()->json([ - 'access_token' => $token->accessToken - ]); - } - - public function archive(Request $request, $id) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('write'), 403); - - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $status = Status::whereNull('in_reply_to_id') - ->whereNull('reblog_of_id') - ->whereProfileId($request->user()->profile_id) - ->findOrFail($id); - - if($status->scope === 'archived') { - return [200]; - } - - $archive = new StatusArchived; - $archive->status_id = $status->id; - $archive->profile_id = $status->profile_id; - $archive->original_scope = $status->scope; - $archive->save(); - - $status->scope = 'archived'; - $status->visibility = 'draft'; - $status->save(); - StatusService::del($status->id, true); - AccountService::syncPostCount($status->profile_id); - - return [200]; - } - - public function unarchive(Request $request, $id) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('write'), 403); - - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $status = Status::whereNull('in_reply_to_id') - ->whereNull('reblog_of_id') - ->whereProfileId($request->user()->profile_id) - ->findOrFail($id); - - if($status->scope !== 'archived') { - return [200]; - } - - $archive = StatusArchived::whereStatusId($status->id) - ->whereProfileId($status->profile_id) - ->firstOrFail(); - - $status->scope = $archive->original_scope; - $status->visibility = $archive->original_scope; - $status->save(); - $archive->delete(); - StatusService::del($status->id, true); - AccountService::syncPostCount($status->profile_id); - - return [200]; - } - - public function archivedPosts(Request $request) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('read'), 403); - - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $statuses = Status::whereProfileId($request->user()->profile_id) - ->whereScope('archived') - ->orderByDesc('id') - ->cursorPaginate(10); - - return StatusStateless::collection($statuses); - } - - public function placesById(Request $request, $id, $slug) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('read'), 403); - - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $place = Place::whereSlug($slug)->findOrFail($id); - - $posts = Cache::remember('pf-api:v1.1:places-by-id:' . $place->id, 3600, function() use($place) { - return Status::wherePlaceId($place->id) - ->whereNull('uri') - ->whereScope('public') - ->orderByDesc('created_at') - ->limit(60) - ->pluck('id'); - }); - - $posts = $posts->map(function($id) { - return StatusService::get($id); - }) - ->filter() - ->values(); - - return [ - 'place' => - [ - 'id' => $place->id, - 'name' => $place->name, - 'slug' => $place->slug, - 'country' => $place->country, - 'lat' => $place->lat, - 'long' => $place->long - ], - 'posts' => $posts]; - } - - public function moderatePost(Request $request, $id) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_if($request->user()->is_admin != true, 403); - abort_unless($request->user()->tokenCan('admin:write'), 403); - - if(config('pixelfed.bouncer.cloud_ips.ban_signups')) { - abort_if(BouncerService::checkIp($request->ip()), 404); - } - - $this->validate($request, [ - 'action' => 'required|in:cw,mark-public,mark-unlisted,mark-private,mark-spammer,delete' - ]); - - $action = $request->input('action'); - $status = Status::find($id); - - if(!$status) { - return response()->json(['error' => 'Cannot find status'], 400); - } - - if($status->uri == null) { - if($status->profile->user && $status->profile->user->is_admin) { - return response()->json(['error' => 'Cannot moderate admin accounts'], 400); - } - } - - if($action == 'mark-spammer') { - $status->profile->update([ - 'unlisted' => true, - 'cw' => true, - 'no_autolink' => true - ]); - - Status::whereProfileId($status->profile_id) - ->get() - ->each(function($s) { - if(in_array($s->scope, ['public', 'unlisted'])) { - $s->scope = 'private'; - $s->visibility = 'private'; - } - $s->is_nsfw = true; - $s->save(); - StatusService::del($s->id, true); - }); - - Cache::forget('pf:bouncer_v0:exemption_by_pid:' . $status->profile_id); - Cache::forget('pf:bouncer_v0:recent_by_pid:' . $status->profile_id); - Cache::forget('admin-dash:reports:spam-count'); - } else if ($action == 'cw') { - $state = $status->is_nsfw; - $status->is_nsfw = !$state; - $status->save(); - StatusService::del($status->id); - } else if ($action == 'mark-public') { - $state = $status->scope; - $status->scope = 'public'; - $status->visibility = 'public'; - $status->save(); - StatusService::del($status->id, true); - if($state !== 'public') { - if($status->uri) { - if($status->in_reply_to_id == null && $status->reblog_of_id == null) { - NetworkTimelineService::add($status->id); - } - } else { - if($status->in_reply_to_id == null && $status->reblog_of_id == null) { - PublicTimelineService::add($status->id); - } - } - } - } else if ($action == 'mark-unlisted') { - $state = $status->scope; - $status->scope = 'unlisted'; - $status->visibility = 'unlisted'; - $status->save(); - StatusService::del($status->id); - if($state == 'public') { - PublicTimelineService::del($status->id); - NetworkTimelineService::del($status->id); - } - } else if ($action == 'mark-private') { - $state = $status->scope; - $status->scope = 'private'; - $status->visibility = 'private'; - $status->save(); - StatusService::del($status->id); - if($state == 'public') { - PublicTimelineService::del($status->id); - NetworkTimelineService::del($status->id); - } - } else if ($action == 'delete') { - PublicTimelineService::del($status->id); - NetworkTimelineService::del($status->id); - Cache::forget('_api:statuses:recent_9:' . $status->profile_id); - Cache::forget('profile:status_count:' . $status->profile_id); - Cache::forget('profile:embed:' . $status->profile_id); - StatusService::del($status->id, true); - Cache::forget('profile:status_count:'.$status->profile_id); - $status->uri ? RemoteStatusDelete::dispatch($status) : StatusDelete::dispatch($status); - return []; - } - - Cache::forget('_api:statuses:recent_9:'.$status->profile_id); - - return StatusService::get($status->id, false); - } - - public function getWebSettings(Request $request) - { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('read'), 403); + protected $fractal; + + public function __construct() + { + $this->fractal = new Fractal\Manager(); + $this->fractal->setSerializer(new ArraySerializer()); + } + + public function json($res, $code = 200, $headers = []) + { + return response()->json($res, $code, $headers, JSON_UNESCAPED_SLASHES); + } + + public function error($msg, $code = 400, $extra = [], $headers = []) + { + $res = [ + 'msg' => $msg, + 'code' => $code, + ]; + + return response()->json(array_merge($res, $extra), $code, $headers, JSON_UNESCAPED_SLASHES); + } + + public function report(Request $request) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('write'), 403); + + $user = $request->user(); + abort_if($user->status != null, 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $report_type = $request->input('report_type'); + $object_id = $request->input('object_id'); + $object_type = $request->input('object_type'); + + $types = [ + 'spam', + 'sensitive', + 'abusive', + 'underage', + 'violence', + 'copyright', + 'impersonation', + 'scam', + 'terrorism', + ]; + + if (! $report_type || ! $object_id || ! $object_type) { + return $this->error('Invalid or missing parameters', 400, ['error_code' => 'ERROR_INVALID_PARAMS']); + } + + if (! in_array($report_type, $types)) { + return $this->error('Invalid report type', 400, ['error_code' => 'ERROR_TYPE_INVALID']); + } + + if ($object_type === 'user' && $object_id == $user->profile_id) { + return $this->error('Cannot self report', 400, ['error_code' => 'ERROR_NO_SELF_REPORTS']); + } + + $rpid = null; + + switch ($object_type) { + case 'post': + $object = Status::find($object_id); + if (! $object) { + return $this->error('Invalid object id', 400, ['error_code' => 'ERROR_INVALID_OBJECT_ID']); + } + $object_type = 'App\Status'; + $exists = Report::whereUserId($user->id) + ->whereObjectId($object->id) + ->whereObjectType('App\Status') + ->count(); + + $rpid = $object->profile_id; + break; + + case 'user': + $object = Profile::find($object_id); + if (! $object) { + return $this->error('Invalid object id', 400, ['error_code' => 'ERROR_INVALID_OBJECT_ID']); + } + $object_type = 'App\Profile'; + $exists = Report::whereUserId($user->id) + ->whereObjectId($object->id) + ->whereObjectType('App\Profile') + ->count(); + $rpid = $object->id; + break; + + default: + return $this->error('Invalid report type', 400, ['error_code' => 'ERROR_REPORT_OBJECT_TYPE_INVALID']); + break; + } + + if ($exists !== 0) { + return $this->error('Duplicate report', 400, ['error_code' => 'ERROR_REPORT_DUPLICATE']); + } + + if ($object->profile_id == $user->profile_id) { + return $this->error('Cannot self report', 400, ['error_code' => 'ERROR_NO_SELF_REPORTS']); + } + + $report = new Report; + $report->profile_id = $user->profile_id; + $report->user_id = $user->id; + $report->object_id = $object->id; + $report->object_type = $object_type; + $report->reported_profile_id = $rpid; + $report->type = $report_type; + $report->save(); + + if (config('instance.reports.email.enabled')) { + ReportNotifyAdminViaEmail::dispatch($report)->onQueue('default'); + } + + $res = [ + 'msg' => 'Successfully sent report', + 'code' => 200, + ]; + + return $this->json($res); + } + + /** + * DELETE /api/v1.1/accounts/avatar + * + * @return \App\Transformer\Api\AccountTransformer + */ + public function deleteAvatar(Request $request) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('write'), 403); + + $user = $request->user(); + abort_if($user->status != null, 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $avatar = $user->profile->avatar; + + if ($avatar->media_path == 'public/avatars/default.png' || + $avatar->media_path == 'public/avatars/default.jpg' + ) { + return AccountService::get($user->profile_id); + } + + if (is_file(storage_path('app/'.$avatar->media_path))) { + @unlink(storage_path('app/'.$avatar->media_path)); + } + + $avatar->media_path = 'public/avatars/default.jpg'; + $avatar->change_count = $avatar->change_count + 1; + $avatar->save(); + + Cache::forget('avatar:'.$user->profile_id); + Cache::forget("avatar:{$user->profile_id}"); + Cache::forget('user:account:id:'.$user->id); + AccountService::del($user->profile_id); + + return AccountService::get($user->profile_id); + } + + /** + * GET /api/v1.1/accounts/{id}/posts + * + * @return \App\Transformer\Api\StatusTransformer + */ + public function accountPosts(Request $request, $id) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('read'), 403); + + $user = $request->user(); + abort_if($user->status != null, 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $account = AccountService::get($id); + + if (! $account || $account['username'] !== $request->input('username')) { + return $this->json([]); + } + + $posts = ProfileStatusService::get($id); + + if (! $posts) { + return $this->json([]); + } + + $res = collect($posts) + ->map(function ($id) { + return StatusService::get($id); + }) + ->filter(function ($post) { + return $post && isset($post['account']); + }) + ->toArray(); + + return $this->json($res); + } + + /** + * POST /api/v1.1/accounts/change-password + * + * @return \App\Transformer\Api\AccountTransformer + */ + public function accountChangePassword(Request $request) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('write'), 403); + + $user = $request->user(); + abort_if($user->status != null, 403); + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $this->validate($request, [ + 'current_password' => 'bail|required|current_password', + 'new_password' => 'required|min:'.config('pixelfed.min_password_length', 8), + 'confirm_password' => 'required|same:new_password', + ], [ + 'current_password' => 'The password you entered is incorrect', + ]); + + $user->password = bcrypt($request->input('new_password')); + $user->save(); + + $log = new AccountLog; + $log->user_id = $user->id; + $log->item_id = $user->id; + $log->item_type = 'App\User'; + $log->action = 'account.edit.password'; + $log->message = 'Password changed'; + $log->link = null; + $log->ip_address = $request->ip(); + $log->user_agent = $request->userAgent(); + $log->save(); + + Mail::to($request->user())->send(new PasswordChange($user)); + + return $this->json(AccountService::get($user->profile_id)); + } + + /** + * GET /api/v1.1/accounts/login-activity + * + * @return array + */ + public function accountLoginActivity(Request $request) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('read'), 403); + + $user = $request->user(); + abort_if($user->status != null, 403); + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + $agent = new Agent(); + $currentIp = $request->ip(); + + $activity = AccountLog::whereUserId($user->id) + ->whereAction('auth.login') + ->orderBy('created_at', 'desc') + ->groupBy('ip_address') + ->limit(10) + ->get() + ->map(function ($item) use ($agent, $currentIp) { + $agent->setUserAgent($item->user_agent); + + return [ + 'id' => $item->id, + 'action' => $item->action, + 'ip' => $item->ip_address, + 'ip_current' => $item->ip_address === $currentIp, + 'is_mobile' => $agent->isMobile(), + 'device' => $agent->device(), + 'browser' => $agent->browser(), + 'platform' => $agent->platform(), + 'created_at' => $item->created_at->format('c'), + ]; + }); + + return $this->json($activity); + } + + /** + * GET /api/v1.1/accounts/two-factor + * + * @return array + */ + public function accountTwoFactor(Request $request) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('read'), 403); + + $user = $request->user(); + abort_if($user->status != null, 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $res = [ + 'active' => (bool) $user->{'2fa_enabled'}, + 'setup_at' => $user->{'2fa_setup_at'}, + ]; + + return $this->json($res); + } + + /** + * GET /api/v1.1/accounts/emails-from-pixelfed + * + * @return array + */ + public function accountEmailsFromPixelfed(Request $request) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('read'), 403); + + $user = $request->user(); + abort_if($user->status != null, 403); + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + $from = config('mail.from.address'); + + $emailVerifications = EmailVerification::whereUserId($user->id) + ->orderByDesc('id') + ->where('created_at', '>', now()->subDays(14)) + ->limit(10) + ->get() + ->map(function ($mail) use ($user, $from) { + return [ + 'type' => 'Email Verification', + 'subject' => 'Confirm Email', + 'to_address' => $user->email, + 'from_address' => $from, + 'created_at' => str_replace('@', 'at', $mail->created_at->format('M j, Y @ g:i:s A')), + ]; + }) + ->toArray(); + + $passwordResets = DB::table('password_resets') + ->whereEmail($user->email) + ->where('created_at', '>', now()->subDays(14)) + ->orderByDesc('created_at') + ->limit(10) + ->get() + ->map(function ($mail) use ($user, $from) { + return [ + 'type' => 'Password Reset', + 'subject' => 'Reset Password Notification', + 'to_address' => $user->email, + 'from_address' => $from, + 'created_at' => str_replace('@', 'at', now()->parse($mail->created_at)->format('M j, Y @ g:i:s A')), + ]; + }) + ->toArray(); + + $passwordChanges = AccountLog::whereUserId($user->id) + ->whereAction('account.edit.password') + ->where('created_at', '>', now()->subDays(14)) + ->orderByDesc('created_at') + ->limit(10) + ->get() + ->map(function ($mail) use ($user, $from) { + return [ + 'type' => 'Password Change', + 'subject' => 'Password Change', + 'to_address' => $user->email, + 'from_address' => $from, + 'created_at' => str_replace('@', 'at', now()->parse($mail->created_at)->format('M j, Y @ g:i:s A')), + ]; + }) + ->toArray(); + + $res = collect([]) + ->merge($emailVerifications) + ->merge($passwordResets) + ->merge($passwordChanges) + ->sortByDesc('created_at') + ->values(); + + return $this->json($res); + } + + /** + * GET /api/v1.1/accounts/apps-and-applications + * + * @return array + */ + public function accountApps(Request $request) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('read'), 403); + + $user = $request->user(); + abort_if($user->status != null, 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $res = $user->tokens->sortByDesc('created_at')->take(10)->map(function ($token, $key) use ($request) { + return [ + 'id' => $token->id, + 'current_session' => $request->user()->token()->id == $token->id, + 'name' => $token->client->name, + 'scopes' => $token->scopes, + 'revoked' => $token->revoked, + 'created_at' => str_replace('@', 'at', now()->parse($token->created_at)->format('M j, Y @ g:i:s A')), + 'expires_at' => str_replace('@', 'at', now()->parse($token->expires_at)->format('M j, Y @ g:i:s A')), + ]; + }); + + return $this->json($res); + } + + public function inAppRegistrationPreFlightCheck(Request $request) + { + return [ + 'open' => (bool) config_cache('pixelfed.open_registration'), + 'iara' => (bool) config_cache('pixelfed.allow_app_registration'), + ]; + } + + public function inAppRegistration(Request $request) + { + abort_if($request->user(), 404); + abort_unless((bool) config_cache('pixelfed.open_registration'), 404); + abort_unless((bool) config_cache('pixelfed.allow_app_registration'), 404); + abort_unless($request->hasHeader('X-PIXELFED-APP'), 403); + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $rl = RateLimiter::attempt('pf:apiv1.1:iar:'.$request->ip(), config('pixelfed.app_registration_rate_limit_attempts', 3), function () { + }, config('pixelfed.app_registration_rate_limit_decay', 1800)); + abort_if(! $rl, 400, 'Too many requests'); + + $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', + ]); + + $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(40); + $user->save(); + + $rtoken = Str::random(64); + + $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(); + + $params = http_build_query([ + 'ut' => $user->app_register_token, + 'rt' => $rtoken, + 'ea' => base64_encode($user->email), + ]); + $appUrl = url('/api/v1.1/auth/iarer?'.$params); + + Mail::to($user->email)->send(new ConfirmAppEmail($verify, $appUrl)); + + return response()->json([ + 'success' => true, + ]); + } + + public function inAppRegistrationEmailRedirect(Request $request) + { + $this->validate($request, [ + 'ut' => 'required', + 'rt' => 'required', + 'ea' => 'required', + ]); + $ut = $request->input('ut'); + $rt = $request->input('rt'); + $ea = $request->input('ea'); + $params = http_build_query([ + 'ut' => $ut, + 'rt' => $rt, + 'domain' => config('pixelfed.domain.app'), + 'ea' => $ea, + ]); + $url = 'pixelfed://confirm-account/'.$ut.'?'.$params; + + return redirect()->away($url); + } + + public function inAppRegistrationConfirm(Request $request) + { + abort_if($request->user(), 404); + abort_unless((bool) config_cache('pixelfed.open_registration'), 404); + abort_unless((bool) config_cache('pixelfed.allow_app_registration'), 404); + abort_unless($request->hasHeader('X-PIXELFED-APP'), 403); + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $rl = RateLimiter::attempt('pf:apiv1.1:iarc:'.$request->ip(), config('pixelfed.app_registration_confirm_rate_limit_attempts', 20), function () { + }, config('pixelfed.app_registration_confirm_rate_limit_decay', 1800)); + abort_if(! $rl, 429, 'Too many requests'); + + $request->validate([ + '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); + } + + if ($verify->created_at->lt(now()->subHours(24))) { + $verify->delete(); + + 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(); + + $token = $user->createToken('Pixelfed', ['read', 'write', 'follow', 'admin:read', 'admin:write', 'push']); + + return response()->json([ + 'access_token' => $token->accessToken, + ]); + } + + public function archive(Request $request, $id) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('write'), 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $status = Status::whereNull('in_reply_to_id') + ->whereNull('reblog_of_id') + ->whereProfileId($request->user()->profile_id) + ->findOrFail($id); + + if ($status->scope === 'archived') { + return [200]; + } + + $archive = new StatusArchived; + $archive->status_id = $status->id; + $archive->profile_id = $status->profile_id; + $archive->original_scope = $status->scope; + $archive->save(); + + $status->scope = 'archived'; + $status->visibility = 'draft'; + $status->save(); + StatusService::del($status->id, true); + AccountService::syncPostCount($status->profile_id); + + return [200]; + } + + public function unarchive(Request $request, $id) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('write'), 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $status = Status::whereNull('in_reply_to_id') + ->whereNull('reblog_of_id') + ->whereProfileId($request->user()->profile_id) + ->findOrFail($id); + + if ($status->scope !== 'archived') { + return [200]; + } + + $archive = StatusArchived::whereStatusId($status->id) + ->whereProfileId($status->profile_id) + ->firstOrFail(); + + $status->scope = $archive->original_scope; + $status->visibility = $archive->original_scope; + $status->save(); + $archive->delete(); + StatusService::del($status->id, true); + AccountService::syncPostCount($status->profile_id); + + return [200]; + } + + public function archivedPosts(Request $request) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('read'), 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $statuses = Status::whereProfileId($request->user()->profile_id) + ->whereScope('archived') + ->orderByDesc('id') + ->cursorPaginate(10); + + return StatusStateless::collection($statuses); + } + + public function placesById(Request $request, $id, $slug) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('read'), 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $place = Place::whereSlug($slug)->findOrFail($id); + + $posts = Cache::remember('pf-api:v1.1:places-by-id:'.$place->id, 3600, function () use ($place) { + return Status::wherePlaceId($place->id) + ->whereNull('uri') + ->whereScope('public') + ->orderByDesc('created_at') + ->limit(60) + ->pluck('id'); + }); + + $posts = $posts->map(function ($id) { + return StatusService::get($id); + }) + ->filter() + ->values(); + + return [ + 'place' => [ + 'id' => $place->id, + 'name' => $place->name, + 'slug' => $place->slug, + 'country' => $place->country, + 'lat' => $place->lat, + 'long' => $place->long, + ], + 'posts' => $posts]; + } + + public function moderatePost(Request $request, $id) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_if($request->user()->is_admin != true, 403); + abort_unless($request->user()->tokenCan('admin:write'), 403); + + if (config('pixelfed.bouncer.cloud_ips.ban_signups')) { + abort_if(BouncerService::checkIp($request->ip()), 404); + } + + $this->validate($request, [ + 'action' => 'required|in:cw,mark-public,mark-unlisted,mark-private,mark-spammer,delete', + ]); + + $action = $request->input('action'); + $status = Status::find($id); + + if (! $status) { + return response()->json(['error' => 'Cannot find status'], 400); + } + + if ($status->uri == null) { + if ($status->profile->user && $status->profile->user->is_admin) { + return response()->json(['error' => 'Cannot moderate admin accounts'], 400); + } + } + + if ($action == 'mark-spammer') { + $status->profile->update([ + 'unlisted' => true, + 'cw' => true, + 'no_autolink' => true, + ]); + + Status::whereProfileId($status->profile_id) + ->get() + ->each(function ($s) { + if (in_array($s->scope, ['public', 'unlisted'])) { + $s->scope = 'private'; + $s->visibility = 'private'; + } + $s->is_nsfw = true; + $s->save(); + StatusService::del($s->id, true); + }); + + Cache::forget('pf:bouncer_v0:exemption_by_pid:'.$status->profile_id); + Cache::forget('pf:bouncer_v0:recent_by_pid:'.$status->profile_id); + Cache::forget('admin-dash:reports:spam-count'); + } elseif ($action == 'cw') { + $state = $status->is_nsfw; + $status->is_nsfw = ! $state; + $status->save(); + StatusService::del($status->id); + } elseif ($action == 'mark-public') { + $state = $status->scope; + $status->scope = 'public'; + $status->visibility = 'public'; + $status->save(); + StatusService::del($status->id, true); + if ($state !== 'public') { + if ($status->uri) { + if ($status->in_reply_to_id == null && $status->reblog_of_id == null) { + NetworkTimelineService::add($status->id); + } + } else { + if ($status->in_reply_to_id == null && $status->reblog_of_id == null) { + PublicTimelineService::add($status->id); + } + } + } + } elseif ($action == 'mark-unlisted') { + $state = $status->scope; + $status->scope = 'unlisted'; + $status->visibility = 'unlisted'; + $status->save(); + StatusService::del($status->id); + if ($state == 'public') { + PublicTimelineService::del($status->id); + NetworkTimelineService::del($status->id); + } + } elseif ($action == 'mark-private') { + $state = $status->scope; + $status->scope = 'private'; + $status->visibility = 'private'; + $status->save(); + StatusService::del($status->id); + if ($state == 'public') { + PublicTimelineService::del($status->id); + NetworkTimelineService::del($status->id); + } + } elseif ($action == 'delete') { + PublicTimelineService::del($status->id); + NetworkTimelineService::del($status->id); + Cache::forget('_api:statuses:recent_9:'.$status->profile_id); + Cache::forget('profile:status_count:'.$status->profile_id); + Cache::forget('profile:embed:'.$status->profile_id); + StatusService::del($status->id, true); + Cache::forget('profile:status_count:'.$status->profile_id); + $status->uri ? RemoteStatusDelete::dispatch($status) : StatusDelete::dispatch($status); + + return []; + } + + Cache::forget('_api:statuses:recent_9:'.$status->profile_id); + + return StatusService::get($status->id, false); + } + + public function getWebSettings(Request $request) + { + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('read'), 403); $uid = $request->user()->id; $settings = UserSetting::firstOrCreate([ - 'user_id' => $uid + 'user_id' => $uid, ]); - if(!$settings->other) { + if (! $settings->other) { return []; } - return $settings->other; - } + + return $settings->other; + } public function setWebSettings(Request $request) { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('write'), 403); + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('write'), 403); $this->validate($request, [ 'field' => 'required|in:enable_reblogs,hide_reblog_banner', - 'value' => 'required' + 'value' => 'required', ]); $field = $request->input('field'); $value = $request->input('value'); $settings = UserSetting::firstOrCreate([ - 'user_id' => $request->user()->id + 'user_id' => $request->user()->id, ]); - if(!$settings->other) { + if (! $settings->other) { $other = []; } else { $other = $settings->other; @@ -923,18 +928,21 @@ class ApiV1Dot1Controller extends Controller public function getMutualAccounts(Request $request, $id) { - abort_if(!$request->user() || !$request->user()->token(), 403); - abort_unless($request->user()->tokenCan('follows'), 403); + abort_if(! $request->user() || ! $request->user()->token(), 403); + abort_unless($request->user()->tokenCan('follows'), 403); $account = AccountService::get($id, true); - if(!$account || !isset($account['id'])) { return []; } + if (! $account || ! isset($account['id'])) { + return []; + } $res = collect(FollowerService::mutualAccounts($request->user()->profile_id, $id)) - ->map(function($accountId) { + ->map(function ($accountId) { return AccountService::get($accountId, true); }) ->filter() ->take(24) ->values(); + return $this->json($res); } } diff --git a/app/Http/Controllers/DirectMessageController.php b/app/Http/Controllers/DirectMessageController.php index 0d91d4f17..af51d5080 100644 --- a/app/Http/Controllers/DirectMessageController.php +++ b/app/Http/Controllers/DirectMessageController.php @@ -309,6 +309,7 @@ class DirectMessageController extends Controller $user = $request->user(); abort_if($user->has_roles && !UserRoleService::can('can-direct-message', $user->id), 403, 'Invalid permissions for this action'); + abort_if($user->created_at->gt(now()->subHours(72)), 400, 'You need to wait a bit before you can DM another account'); $profile = $user->profile; $recipient = Profile::where('id', '!=', $profile->id)->findOrFail($request->input('to_id')); diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index 65a756eaf..3fc877452 100644 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -172,7 +172,7 @@ class ProfileController extends Controller $user = $this->getCachedUser($username); - abort_if(!$user, 404); + abort_if(! $user, 404); return redirect($user->url()); } @@ -254,7 +254,7 @@ class ProfileController extends Controller abort_if(! $profile || $profile['locked'] || ! $profile['local'], 404); - $aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile['id'], 86400, function () use ($profile) { + $aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile['id'], 3600, function () use ($profile) { $uid = User::whereProfileId($profile['id'])->first(); if (! $uid) { return true; @@ -348,7 +348,7 @@ class ProfileController extends Controller return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']); } - $aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile->id, 86400, function () use ($profile) { + $aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile->id, 3600, function () use ($profile) { $exists = AccountInterstitial::whereUserId($profile->user_id)->where('is_spam', 1)->count(); if ($exists) { return true; @@ -373,7 +373,7 @@ class ProfileController extends Controller public function stories(Request $request, $username) { - abort_if(!(bool) config_cache('instance.stories.enabled') || ! $request->user(), 404); + abort_if(! (bool) config_cache('instance.stories.enabled') || ! $request->user(), 404); $profile = Profile::whereNull('domain')->whereUsername($username)->firstOrFail(); $pid = $profile->id; $authed = Auth::user()->profile_id; diff --git a/app/Http/Controllers/StatusController.php b/app/Http/Controllers/StatusController.php index 7f77f9a81..e0864a4a7 100644 --- a/app/Http/Controllers/StatusController.php +++ b/app/Http/Controllers/StatusController.php @@ -8,6 +8,7 @@ use App\Jobs\SharePipeline\UndoSharePipeline; use App\Jobs\StatusPipeline\RemoteStatusDelete; use App\Jobs\StatusPipeline\StatusDelete; use App\Profile; +use App\Services\AccountService; use App\Services\HashidService; use App\Services\ReblogService; use App\Services\StatusService; @@ -113,19 +114,33 @@ class StatusController extends Controller return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']); } - $profile = Profile::whereNull(['domain', 'status']) - ->whereIsPrivate(false) - ->whereUsername($username) - ->first(); + $status = StatusService::get($id); - if (! $profile) { + if ( + ! $status || + ! isset($status['account'], $status['account']['id'], $status['local']) || + ! $status['local'] || + strtolower($status['account']['username']) !== strtolower($username) + ) { + $content = view('status.embed-removed'); + + return response($content, 404)->header('X-Frame-Options', 'ALLOWALL'); + } + + $profile = AccountService::get($status['account']['id'], true); + + if (! $profile || $profile['locked'] || ! $profile['local']) { $content = view('status.embed-removed'); return response($content)->header('X-Frame-Options', 'ALLOWALL'); } - $aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile->id, 86400, function () use ($profile) { - $exists = AccountInterstitial::whereUserId($profile->user_id)->where('is_spam', 1)->count(); + $aiCheck = Cache::remember('profile:ai-check:spam-login:'.$profile['id'], 3600, function () use ($profile) { + $user = Profile::find($profile['id']); + if (! $user) { + return true; + } + $exists = AccountInterstitial::whereUserId($user->user_id)->where('is_spam', 1)->count(); if ($exists) { return true; } @@ -138,17 +153,22 @@ class StatusController extends Controller return response($res)->withHeaders(['X-Frame-Options' => 'ALLOWALL']); } - $status = Status::whereProfileId($profile->id) - ->whereNull('uri') - ->whereScope('public') - ->whereIsNsfw(false) - ->whereIn('type', ['photo', 'video', 'photo:album']) - ->find($id); - if (! $status) { + + $status = StatusService::get($id); + + if ( + ! $status || + ! isset($status['account'], $status['account']['id']) || + intval($status['account']['id']) !== intval($profile['id']) || + $status['sensitive'] || + $status['visibility'] !== 'public' || + $status['pf_type'] !== 'photo' + ) { $content = view('status.embed-removed'); return response($content)->header('X-Frame-Options', 'ALLOWALL'); } + $showLikes = $request->filled('likes') && $request->likes == true; $showCaption = $request->filled('caption') && $request->caption !== false; $layout = $request->filled('layout') && $request->layout == 'compact' ? 'compact' : 'full'; diff --git a/app/Like.php b/app/Like.php index c5b000c66..0c2c7f363 100644 --- a/app/Like.php +++ b/app/Like.php @@ -9,7 +9,7 @@ class Like extends Model { use SoftDeletes; - const MAX_PER_DAY = 500; + const MAX_PER_DAY = 1500; /** * The attributes that should be mutated to dates. diff --git a/app/Services/ConfigCacheService.php b/app/Services/ConfigCacheService.php index 626982781..b18c02e36 100644 --- a/app/Services/ConfigCacheService.php +++ b/app/Services/ConfigCacheService.php @@ -4,6 +4,7 @@ namespace App\Services; use App\Models\ConfigCache as ConfigCacheModel; use Cache; +use Illuminate\Database\QueryException; class ConfigCacheService { @@ -25,156 +26,159 @@ class ConfigCacheService return config($key); } - return Cache::remember($cacheKey, $ttl, function () use ($key) { + try { + return Cache::remember($cacheKey, $ttl, function () use ($key) { + $allowed = [ + 'app.name', + 'app.short_description', + 'app.description', + 'app.rules', - $allowed = [ - 'app.name', - 'app.short_description', - 'app.description', - 'app.rules', + 'pixelfed.max_photo_size', + 'pixelfed.max_album_length', + 'pixelfed.image_quality', + 'pixelfed.media_types', - 'pixelfed.max_photo_size', - 'pixelfed.max_album_length', - 'pixelfed.image_quality', - 'pixelfed.media_types', + 'pixelfed.open_registration', + 'federation.activitypub.enabled', + 'instance.stories.enabled', + 'pixelfed.oauth_enabled', + 'pixelfed.import.instagram.enabled', + 'pixelfed.bouncer.enabled', - 'pixelfed.open_registration', - 'federation.activitypub.enabled', - 'instance.stories.enabled', - 'pixelfed.oauth_enabled', - 'pixelfed.import.instagram.enabled', - 'pixelfed.bouncer.enabled', + 'pixelfed.enforce_email_verification', + 'pixelfed.max_account_size', + 'pixelfed.enforce_account_limit', - 'pixelfed.enforce_email_verification', - 'pixelfed.max_account_size', - 'pixelfed.enforce_account_limit', + 'uikit.custom.css', + 'uikit.custom.js', + 'uikit.show_custom.css', + 'uikit.show_custom.js', + 'about.title', - 'uikit.custom.css', - 'uikit.custom.js', - 'uikit.show_custom.css', - 'uikit.show_custom.js', - 'about.title', + 'pixelfed.cloud_storage', - 'pixelfed.cloud_storage', + 'account.autofollow', + 'account.autofollow_usernames', + 'config.discover.features', - 'account.autofollow', - 'account.autofollow_usernames', - 'config.discover.features', + 'instance.has_legal_notice', + 'instance.avatar.local_to_cloud', - 'instance.has_legal_notice', - 'instance.avatar.local_to_cloud', + 'pixelfed.directory', + 'app.banner_image', + 'pixelfed.directory.submission-key', + 'pixelfed.directory.submission-ts', + 'pixelfed.directory.has_submitted', + 'pixelfed.directory.latest_response', + 'pixelfed.directory.is_synced', + 'pixelfed.directory.testimonials', - 'pixelfed.directory', - 'app.banner_image', - 'pixelfed.directory.submission-key', - 'pixelfed.directory.submission-ts', - 'pixelfed.directory.has_submitted', - 'pixelfed.directory.latest_response', - 'pixelfed.directory.is_synced', - 'pixelfed.directory.testimonials', + 'instance.landing.show_directory', + 'instance.landing.show_explore', + 'instance.admin.pid', + 'instance.banner.blurhash', - 'instance.landing.show_directory', - 'instance.landing.show_explore', - 'instance.admin.pid', - 'instance.banner.blurhash', + 'autospam.nlp.enabled', - 'autospam.nlp.enabled', + 'instance.curated_registration.enabled', - 'instance.curated_registration.enabled', + 'federation.migration', - 'federation.migration', + 'pixelfed.max_caption_length', + 'pixelfed.max_bio_length', + 'pixelfed.max_name_length', + 'pixelfed.min_password_length', + 'pixelfed.max_avatar_size', + 'pixelfed.max_altext_length', + 'pixelfed.allow_app_registration', + 'pixelfed.app_registration_rate_limit_attempts', + 'pixelfed.app_registration_rate_limit_decay', + 'pixelfed.app_registration_confirm_rate_limit_attempts', + 'pixelfed.app_registration_confirm_rate_limit_decay', + 'instance.embed.profile', + 'instance.embed.post', - 'pixelfed.max_caption_length', - 'pixelfed.max_bio_length', - 'pixelfed.max_name_length', - 'pixelfed.min_password_length', - 'pixelfed.max_avatar_size', - 'pixelfed.max_altext_length', - 'pixelfed.allow_app_registration', - 'pixelfed.app_registration_rate_limit_attempts', - 'pixelfed.app_registration_rate_limit_decay', - 'pixelfed.app_registration_confirm_rate_limit_attempts', - 'pixelfed.app_registration_confirm_rate_limit_decay', - 'instance.embed.profile', - 'instance.embed.post', + 'captcha.enabled', + 'captcha.secret', + 'captcha.sitekey', + 'captcha.active.login', + 'captcha.active.register', + 'captcha.triggers.login.enabled', + 'captcha.triggers.login.attempts', + 'federation.custom_emoji.enabled', - 'captcha.enabled', - 'captcha.secret', - 'captcha.sitekey', - 'captcha.active.login', - 'captcha.active.register', - 'captcha.triggers.login.enabled', - 'captcha.triggers.login.attempts', - 'federation.custom_emoji.enabled', + 'pixelfed.optimize_image', + 'pixelfed.optimize_video', + 'pixelfed.max_collection_length', + 'media.delete_local_after_cloud', + 'instance.user_filters.max_user_blocks', + 'instance.user_filters.max_user_mutes', + 'instance.user_filters.max_domain_blocks', - 'pixelfed.optimize_image', - 'pixelfed.optimize_video', - 'pixelfed.max_collection_length', - 'media.delete_local_after_cloud', - 'instance.user_filters.max_user_blocks', - 'instance.user_filters.max_user_mutes', - 'instance.user_filters.max_domain_blocks', + 'filesystems.disks.s3.key', + 'filesystems.disks.s3.secret', + 'filesystems.disks.s3.region', + 'filesystems.disks.s3.bucket', + 'filesystems.disks.s3.visibility', + 'filesystems.disks.s3.url', + 'filesystems.disks.s3.endpoint', + 'filesystems.disks.s3.use_path_style_endpoint', - 'filesystems.disks.s3.key', - 'filesystems.disks.s3.secret', - 'filesystems.disks.s3.region', - 'filesystems.disks.s3.bucket', - 'filesystems.disks.s3.visibility', - 'filesystems.disks.s3.url', - 'filesystems.disks.s3.endpoint', - 'filesystems.disks.s3.use_path_style_endpoint', + 'filesystems.disks.spaces.key', + 'filesystems.disks.spaces.secret', + 'filesystems.disks.spaces.region', + 'filesystems.disks.spaces.bucket', + 'filesystems.disks.spaces.visibility', + 'filesystems.disks.spaces.url', + 'filesystems.disks.spaces.endpoint', + 'filesystems.disks.spaces.use_path_style_endpoint', + // 'system.user_mode' + ]; - 'filesystems.disks.spaces.key', - 'filesystems.disks.spaces.secret', - 'filesystems.disks.spaces.region', - 'filesystems.disks.spaces.bucket', - 'filesystems.disks.spaces.visibility', - 'filesystems.disks.spaces.url', - 'filesystems.disks.spaces.endpoint', - 'filesystems.disks.spaces.use_path_style_endpoint', - // 'system.user_mode' - ]; - - if (! config('instance.enable_cc')) { - return config($key); - } - - if (! in_array($key, $allowed)) { - return config($key); - } - - $protect = false; - $protected = null; - if(in_array($key, self::PROTECTED_KEYS)) { - $protect = true; - } - - $v = config($key); - $c = ConfigCacheModel::where('k', $key)->first(); - - if ($c) { - if($protect) { - return decrypt($c->v) ?? config($key); - } else { - return $c->v ?? config($key); + if (! config('instance.enable_cc')) { + return config($key); } - } - if (! $v) { - return; - } + if (! in_array($key, $allowed)) { + return config($key); + } - if($protect && $v) { - $protected = encrypt($v); - } + $protect = false; + $protected = null; + if(in_array($key, self::PROTECTED_KEYS)) { + $protect = true; + } - $cc = new ConfigCacheModel; - $cc->k = $key; - $cc->v = $protect ? $protected : $v; - $cc->save(); + $v = config($key); + $c = ConfigCacheModel::where('k', $key)->first(); - return $v; - }); + if ($c) { + if($protect) { + return decrypt($c->v) ?? config($key); + } else { + return $c->v ?? config($key); + } + } + + if (! $v) { + return; + } + + if($protect && $v) { + $protected = encrypt($v); + } + + $cc = new ConfigCacheModel; + $cc->k = $key; + $cc->v = $protect ? $protected : $v; + $cc->save(); + + return $v; + }); + } catch (Exception | QueryException $e) { + return config($key); + } } public static function put($key, $val) diff --git a/app/Services/CustomEmojiService.php b/app/Services/CustomEmojiService.php index 468772b5f..f9f267174 100644 --- a/app/Services/CustomEmojiService.php +++ b/app/Services/CustomEmojiService.php @@ -133,6 +133,7 @@ class CustomEmojiService return CustomEmoji::when(!$pgsql, function($q, $pgsql) { return $q->groupBy('shortcode'); }) + ->whereNull('uri') ->get() ->map(function($emojo) { $url = url('storage/' . $emojo->media_path); diff --git a/composer.lock b/composer.lock index 3acbe5192..6b4019c3e 100644 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "aws/aws-crt-php", - "version": "v1.2.4", + "version": "v1.2.5", "source": { "type": "git", "url": "https://github.com/awslabs/aws-crt-php.git", - "reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2" + "reference": "0ea1f04ec5aa9f049f97e012d1ed63b76834a31b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/eb0c6e4e142224a10b08f49ebf87f32611d162b2", - "reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/0ea1f04ec5aa9f049f97e012d1ed63b76834a31b", + "reference": "0ea1f04ec5aa9f049f97e012d1ed63b76834a31b", "shasum": "" }, "require": { @@ -56,22 +56,22 @@ ], "support": { "issues": "https://github.com/awslabs/aws-crt-php/issues", - "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.4" + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.5" }, - "time": "2023-11-08T00:42:13+00:00" + "time": "2024-04-19T21:30:56+00:00" }, { "name": "aws/aws-sdk-php", - "version": "3.303.4", + "version": "3.306.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "9ae5429f7699701cb158780cd287d1549f45ad32" + "reference": "dc228b55a4224fe3160a0a2ca430b80c5348d943" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/9ae5429f7699701cb158780cd287d1549f45ad32", - "reference": "9ae5429f7699701cb158780cd287d1549f45ad32", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/dc228b55a4224fe3160a0a2ca430b80c5348d943", + "reference": "dc228b55a4224fe3160a0a2ca430b80c5348d943", "shasum": "" }, "require": { @@ -151,9 +151,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.303.4" + "source": "https://github.com/aws/aws-sdk-php/tree/3.306.0" }, - "time": "2024-04-05T18:04:15+00:00" + "time": "2024-05-06T18:11:49+00:00" }, { "name": "bacon/bacon-qr-code", @@ -838,16 +838,16 @@ }, { "name": "doctrine/dbal", - "version": "3.8.3", + "version": "3.8.4", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "db922ba9436b7b18a23d1653a0b41ff2369ca41c" + "reference": "b05e48a745f722801f55408d0dbd8003b403dbbd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/db922ba9436b7b18a23d1653a0b41ff2369ca41c", - "reference": "db922ba9436b7b18a23d1653a0b41ff2369ca41c", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/b05e48a745f722801f55408d0dbd8003b403dbbd", + "reference": "b05e48a745f722801f55408d0dbd8003b403dbbd", "shasum": "" }, "require": { @@ -931,7 +931,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.8.3" + "source": "https://github.com/doctrine/dbal/tree/3.8.4" }, "funding": [ { @@ -947,7 +947,7 @@ "type": "tidelift" } ], - "time": "2024-03-03T15:55:06+00:00" + "time": "2024-04-25T07:04:44+00:00" }, { "name": "doctrine/deprecations", @@ -2369,16 +2369,16 @@ }, { "name": "jaybizzle/crawler-detect", - "version": "v1.2.117", + "version": "v1.2.118", "source": { "type": "git", "url": "https://github.com/JayBizzle/Crawler-Detect.git", - "reference": "6785557f03d0fa9e2205352ebae9a12a4484cc8e" + "reference": "9b8912ac5b78b780a0ead552b4c3dc9ddfdea4fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/6785557f03d0fa9e2205352ebae9a12a4484cc8e", - "reference": "6785557f03d0fa9e2205352ebae9a12a4484cc8e", + "url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/9b8912ac5b78b780a0ead552b4c3dc9ddfdea4fd", + "reference": "9b8912ac5b78b780a0ead552b4c3dc9ddfdea4fd", "shasum": "" }, "require": { @@ -2415,9 +2415,9 @@ ], "support": { "issues": "https://github.com/JayBizzle/Crawler-Detect/issues", - "source": "https://github.com/JayBizzle/Crawler-Detect/tree/v1.2.117" + "source": "https://github.com/JayBizzle/Crawler-Detect/tree/v1.2.118" }, - "time": "2024-03-19T22:51:22+00:00" + "time": "2024-04-23T17:07:05+00:00" }, { "name": "jenssegers/agent", @@ -2562,16 +2562,16 @@ }, { "name": "laravel/framework", - "version": "v10.48.4", + "version": "v10.48.10", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "7e0701bf59cb76a51f7c1f7bea51c0c0c29c0b72" + "reference": "91e2b9e218afa4e5c377510faa11957042831ba3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/7e0701bf59cb76a51f7c1f7bea51c0c0c29c0b72", - "reference": "7e0701bf59cb76a51f7c1f7bea51c0c0c29c0b72", + "url": "https://api.github.com/repos/laravel/framework/zipball/91e2b9e218afa4e5c377510faa11957042831ba3", + "reference": "91e2b9e218afa4e5c377510faa11957042831ba3", "shasum": "" }, "require": { @@ -2765,7 +2765,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2024-03-21T13:36:36+00:00" + "time": "2024-04-30T12:52:59+00:00" }, { "name": "laravel/helpers", @@ -2826,16 +2826,16 @@ }, { "name": "laravel/horizon", - "version": "v5.23.2", + "version": "v5.24.4", "source": { "type": "git", "url": "https://github.com/laravel/horizon.git", - "reference": "96d154340f1223bcc161ea7cee355c8fc29ff81e" + "reference": "8d31ff178bf5493efc2b2629c10612054f31f584" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/horizon/zipball/96d154340f1223bcc161ea7cee355c8fc29ff81e", - "reference": "96d154340f1223bcc161ea7cee355c8fc29ff81e", + "url": "https://api.github.com/repos/laravel/horizon/zipball/8d31ff178bf5493efc2b2629c10612054f31f584", + "reference": "8d31ff178bf5493efc2b2629c10612054f31f584", "shasum": "" }, "require": { @@ -2899,9 +2899,9 @@ ], "support": { "issues": "https://github.com/laravel/horizon/issues", - "source": "https://github.com/laravel/horizon/tree/v5.23.2" + "source": "https://github.com/laravel/horizon/tree/v5.24.4" }, - "time": "2024-03-23T12:11:34+00:00" + "time": "2024-05-03T13:34:14+00:00" }, { "name": "laravel/passport", @@ -2983,16 +2983,16 @@ }, { "name": "laravel/prompts", - "version": "v0.1.17", + "version": "v0.1.21", "source": { "type": "git", "url": "https://github.com/laravel/prompts.git", - "reference": "8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5" + "reference": "23ea808e8a145653e0ab29e30d4385e49f40a920" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/prompts/zipball/8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5", - "reference": "8ee9f87f7f9eadcbe21e9e72cd4176b2f06cd5b5", + "url": "https://api.github.com/repos/laravel/prompts/zipball/23ea808e8a145653e0ab29e30d4385e49f40a920", + "reference": "23ea808e8a145653e0ab29e30d4385e49f40a920", "shasum": "" }, "require": { @@ -3032,11 +3032,12 @@ "license": [ "MIT" ], + "description": "Add beautiful and user-friendly forms to your command-line applications.", "support": { "issues": "https://github.com/laravel/prompts/issues", - "source": "https://github.com/laravel/prompts/tree/v0.1.17" + "source": "https://github.com/laravel/prompts/tree/v0.1.21" }, - "time": "2024-03-13T16:05:43+00:00" + "time": "2024-04-30T12:46:16+00:00" }, { "name": "laravel/serializable-closure", @@ -3229,34 +3230,34 @@ }, { "name": "lcobucci/clock", - "version": "3.0.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/lcobucci/clock.git", - "reference": "039ef98c6b57b101d10bd11d8fdfda12cbd996dc" + "reference": "6f28b826ea01306b07980cb8320ab30b966cd715" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/clock/zipball/039ef98c6b57b101d10bd11d8fdfda12cbd996dc", - "reference": "039ef98c6b57b101d10bd11d8fdfda12cbd996dc", + "url": "https://api.github.com/repos/lcobucci/clock/zipball/6f28b826ea01306b07980cb8320ab30b966cd715", + "reference": "6f28b826ea01306b07980cb8320ab30b966cd715", "shasum": "" }, "require": { - "php": "~8.1.0 || ~8.2.0", + "php": "~8.2.0 || ~8.3.0", "psr/clock": "^1.0" }, "provide": { "psr/clock-implementation": "1.0" }, "require-dev": { - "infection/infection": "^0.26", - "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" + "infection/infection": "^0.27", + "lcobucci/coding-standard": "^11.0.0", + "phpstan/extension-installer": "^1.3.1", + "phpstan/phpstan": "^1.10.25", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.13", + "phpstan/phpstan-strict-rules": "^1.5.1", + "phpunit/phpunit": "^10.2.3" }, "type": "library", "autoload": { @@ -3277,7 +3278,7 @@ "description": "Yet another clock abstraction", "support": { "issues": "https://github.com/lcobucci/clock/issues", - "source": "https://github.com/lcobucci/clock/tree/3.0.0" + "source": "https://github.com/lcobucci/clock/tree/3.2.0" }, "funding": [ { @@ -3289,20 +3290,20 @@ "type": "patreon" } ], - "time": "2022-12-19T15:00:24+00:00" + "time": "2023-11-17T17:00:27+00:00" }, { "name": "lcobucci/jwt", - "version": "5.2.0", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "0ba88aed12c04bd2ed9924f500673f32b67a6211" + "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/0ba88aed12c04bd2ed9924f500673f32b67a6211", - "reference": "0ba88aed12c04bd2ed9924f500673f32b67a6211", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/08071d8d2c7f4b00222cc4b1fb6aa46990a80f83", + "reference": "08071d8d2c7f4b00222cc4b1fb6aa46990a80f83", "shasum": "" }, "require": { @@ -3350,7 +3351,7 @@ ], "support": { "issues": "https://github.com/lcobucci/jwt/issues", - "source": "https://github.com/lcobucci/jwt/tree/5.2.0" + "source": "https://github.com/lcobucci/jwt/tree/5.3.0" }, "funding": [ { @@ -3362,7 +3363,7 @@ "type": "patreon" } ], - "time": "2023-11-20T21:17:42+00:00" + "time": "2024-04-11T23:07:54+00:00" }, { "name": "league/commonmark", @@ -3608,16 +3609,16 @@ }, { "name": "league/flysystem", - "version": "3.26.0", + "version": "3.27.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "072735c56cc0da00e10716dd90d5a7f7b40b36be" + "reference": "4729745b1ab737908c7d055148c9a6b3e959832f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/072735c56cc0da00e10716dd90d5a7f7b40b36be", - "reference": "072735c56cc0da00e10716dd90d5a7f7b40b36be", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4729745b1ab737908c7d055148c9a6b3e959832f", + "reference": "4729745b1ab737908c7d055148c9a6b3e959832f", "shasum": "" }, "require": { @@ -3682,7 +3683,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.26.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.27.0" }, "funding": [ { @@ -3694,20 +3695,20 @@ "type": "github" } ], - "time": "2024-03-25T11:49:53+00:00" + "time": "2024-04-07T19:17:50+00:00" }, { "name": "league/flysystem-aws-s3-v3", - "version": "3.26.0", + "version": "3.27.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", - "reference": "885d0a758c71ae3cd6c503544573a1fdb8dc754f" + "reference": "3e6ce2f972f1470db779f04d29c289dcd2c32837" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/885d0a758c71ae3cd6c503544573a1fdb8dc754f", - "reference": "885d0a758c71ae3cd6c503544573a1fdb8dc754f", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/3e6ce2f972f1470db779f04d29c289dcd2c32837", + "reference": "3e6ce2f972f1470db779f04d29c289dcd2c32837", "shasum": "" }, "require": { @@ -3747,7 +3748,7 @@ "storage" ], "support": { - "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.26.0" + "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.27.0" }, "funding": [ { @@ -3759,7 +3760,7 @@ "type": "github" } ], - "time": "2024-03-24T21:11:18+00:00" + "time": "2024-04-07T19:16:54+00:00" }, { "name": "league/flysystem-local", @@ -4327,16 +4328,16 @@ }, { "name": "monolog/monolog", - "version": "3.5.0", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448" + "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/c915e2634718dbc8a4a15c61b0e62e7a44e14448", - "reference": "c915e2634718dbc8a4a15c61b0e62e7a44e14448", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/4b18b21a5527a3d5ffdac2fd35d3ab25a9597654", + "reference": "4b18b21a5527a3d5ffdac2fd35d3ab25a9597654", "shasum": "" }, "require": { @@ -4359,7 +4360,7 @@ "phpstan/phpstan": "^1.9", "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-strict-rules": "^1.4", - "phpunit/phpunit": "^10.1", + "phpunit/phpunit": "^10.5.17", "predis/predis": "^1.1 || ^2", "ruflin/elastica": "^7", "symfony/mailer": "^5.4 || ^6", @@ -4412,7 +4413,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.5.0" + "source": "https://github.com/Seldaek/monolog/tree/3.6.0" }, "funding": [ { @@ -4424,7 +4425,7 @@ "type": "tidelift" } ], - "time": "2023-10-27T15:32:31+00:00" + "time": "2024-04-12T21:02:21+00:00" }, { "name": "mtdowling/jmespath.php", @@ -5088,16 +5089,16 @@ }, { "name": "paragonie/sodium_compat", - "version": "v1.20.1", + "version": "v1.21.1", "source": { "type": "git", "url": "https://github.com/paragonie/sodium_compat.git", - "reference": "1840b98d228bdad83869b191d7e51f9bb6624d8d" + "reference": "bb312875dcdd20680419564fe42ba1d9564b9e37" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/1840b98d228bdad83869b191d7e51f9bb6624d8d", - "reference": "1840b98d228bdad83869b191d7e51f9bb6624d8d", + "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/bb312875dcdd20680419564fe42ba1d9564b9e37", + "reference": "bb312875dcdd20680419564fe42ba1d9564b9e37", "shasum": "" }, "require": { @@ -5168,9 +5169,9 @@ ], "support": { "issues": "https://github.com/paragonie/sodium_compat/issues", - "source": "https://github.com/paragonie/sodium_compat/tree/v1.20.1" + "source": "https://github.com/paragonie/sodium_compat/tree/v1.21.1" }, - "time": "2024-04-05T21:00:10+00:00" + "time": "2024-04-22T22:05:04+00:00" }, { "name": "pbmedia/laravel-ffmpeg", @@ -6548,20 +6549,20 @@ }, { "name": "ramsey/uuid", - "version": "4.7.5", + "version": "4.7.6", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e" + "reference": "91039bc1faa45ba123c4328958e620d382ec7088" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", - "reference": "5f0df49ae5ad6efb7afa69e6bfab4e5b1e080d8e", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088", + "reference": "91039bc1faa45ba123c4328958e620d382ec7088", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11", + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12", "ext-json": "*", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" @@ -6624,7 +6625,7 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.7.5" + "source": "https://github.com/ramsey/uuid/tree/4.7.6" }, "funding": [ { @@ -6636,7 +6637,7 @@ "type": "tidelift" } ], - "time": "2023-11-08T05:53:05+00:00" + "time": "2024-04-27T21:32:50+00:00" }, { "name": "ratchet/rfc6455", @@ -7239,16 +7240,16 @@ }, { "name": "spatie/db-dumper", - "version": "3.4.3", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/spatie/db-dumper.git", - "reference": "c566852826f3e9dceea27eef5173bad93b83e61c" + "reference": "faca5056830bccea04eadf07e8074669cb9e905e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/db-dumper/zipball/c566852826f3e9dceea27eef5173bad93b83e61c", - "reference": "c566852826f3e9dceea27eef5173bad93b83e61c", + "url": "https://api.github.com/repos/spatie/db-dumper/zipball/faca5056830bccea04eadf07e8074669cb9e905e", + "reference": "faca5056830bccea04eadf07e8074669cb9e905e", "shasum": "" }, "require": { @@ -7286,7 +7287,7 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/db-dumper/tree/3.4.3" + "source": "https://github.com/spatie/db-dumper/tree/3.6.0" }, "funding": [ { @@ -7298,20 +7299,20 @@ "type": "github" } ], - "time": "2024-04-01T07:37:06+00:00" + "time": "2024-04-24T14:54:13+00:00" }, { "name": "spatie/image-optimizer", - "version": "1.7.2", + "version": "1.7.4", "source": { "type": "git", "url": "https://github.com/spatie/image-optimizer.git", - "reference": "62f7463483d1bd975f6f06025d89d42a29608fe1" + "reference": "ed39c7bfce7a2ecf676174a2d4286ab3a1c4f4f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/image-optimizer/zipball/62f7463483d1bd975f6f06025d89d42a29608fe1", - "reference": "62f7463483d1bd975f6f06025d89d42a29608fe1", + "url": "https://api.github.com/repos/spatie/image-optimizer/zipball/ed39c7bfce7a2ecf676174a2d4286ab3a1c4f4f7", + "reference": "ed39c7bfce7a2ecf676174a2d4286ab3a1c4f4f7", "shasum": "" }, "require": { @@ -7351,22 +7352,22 @@ ], "support": { "issues": "https://github.com/spatie/image-optimizer/issues", - "source": "https://github.com/spatie/image-optimizer/tree/1.7.2" + "source": "https://github.com/spatie/image-optimizer/tree/1.7.4" }, - "time": "2023-11-03T10:08:02+00:00" + "time": "2024-05-06T09:12:30+00:00" }, { "name": "spatie/laravel-backup", - "version": "8.6.0", + "version": "8.8.0", "source": { "type": "git", "url": "https://github.com/spatie/laravel-backup.git", - "reference": "c6a7607c0eea80efc2cf6628ffcd172f73a2088f" + "reference": "7e74431fc5c46319a27daa44897df1c7bf4afe5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/laravel-backup/zipball/c6a7607c0eea80efc2cf6628ffcd172f73a2088f", - "reference": "c6a7607c0eea80efc2cf6628ffcd172f73a2088f", + "url": "https://api.github.com/repos/spatie/laravel-backup/zipball/7e74431fc5c46319a27daa44897df1c7bf4afe5a", + "reference": "7e74431fc5c46319a27daa44897df1c7bf4afe5a", "shasum": "" }, "require": { @@ -7440,7 +7441,7 @@ ], "support": { "issues": "https://github.com/spatie/laravel-backup/issues", - "source": "https://github.com/spatie/laravel-backup/tree/8.6.0" + "source": "https://github.com/spatie/laravel-backup/tree/8.8.0" }, "funding": [ { @@ -7452,7 +7453,7 @@ "type": "other" } ], - "time": "2024-02-06T20:39:11+00:00" + "time": "2024-05-02T13:09:01+00:00" }, { "name": "spatie/laravel-image-optimizer", @@ -7850,31 +7851,31 @@ }, { "name": "symfony/cache", - "version": "v6.4.6", + "version": "v7.0.7", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "b59bbf9c093b592d77110f9ee70c74dff89294cb" + "reference": "48e3508338987d63b0114a00c208c4cbb76e5303" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/b59bbf9c093b592d77110f9ee70c74dff89294cb", - "reference": "b59bbf9c093b592d77110f9ee70c74dff89294cb", + "url": "https://api.github.com/repos/symfony/cache/zipball/48e3508338987d63b0114a00c208c4cbb76e5303", + "reference": "48e3508338987d63b0114a00c208c4cbb76e5303", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/cache": "^2.0|^3.0", "psr/log": "^1.1|^2|^3", "symfony/cache-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.3.6|^7.0" + "symfony/var-exporter": "^6.4|^7.0" }, "conflict": { - "doctrine/dbal": "<2.13.1", - "symfony/dependency-injection": "<5.4", - "symfony/http-kernel": "<5.4", - "symfony/var-dumper": "<5.4" + "doctrine/dbal": "<3.6", + "symfony/dependency-injection": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" }, "provide": { "psr/cache-implementation": "2.0|3.0", @@ -7883,15 +7884,15 @@ }, "require-dev": { "cache/integration-tests": "dev-master", - "doctrine/dbal": "^2.13.1|^3|^4", + "doctrine/dbal": "^3.6|^4", "predis/predis": "^1.1|^2.0", "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -7926,7 +7927,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.6" + "source": "https://github.com/symfony/cache/tree/v7.0.7" }, "funding": [ { @@ -7942,20 +7943,20 @@ "type": "tidelift" } ], - "time": "2024-03-27T13:27:42+00:00" + "time": "2024-04-18T09:29:19+00:00" }, { "name": "symfony/cache-contracts", - "version": "v3.4.2", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/cache-contracts.git", - "reference": "2c9db6509a1b21dad229606897639d3284f54b2a" + "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/2c9db6509a1b21dad229606897639d3284f54b2a", - "reference": "2c9db6509a1b21dad229606897639d3284f54b2a", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/df6a1a44c890faded49a5fca33c2d5c5fd3c2197", + "reference": "df6a1a44c890faded49a5fca33c2d5c5fd3c2197", "shasum": "" }, "require": { @@ -7965,7 +7966,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -8002,7 +8003,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.4.2" + "source": "https://github.com/symfony/cache-contracts/tree/v3.5.0" }, "funding": [ { @@ -8018,20 +8019,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/console", - "version": "v6.4.6", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "a2708a5da5c87d1d0d52937bdeac625df659e11f" + "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a2708a5da5c87d1d0d52937bdeac625df659e11f", - "reference": "a2708a5da5c87d1d0d52937bdeac625df659e11f", + "url": "https://api.github.com/repos/symfony/console/zipball/a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", + "reference": "a170e64ae10d00ba89e2acbb590dc2e54da8ad8f", "shasum": "" }, "require": { @@ -8096,7 +8097,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.6" + "source": "https://github.com/symfony/console/tree/v6.4.7" }, "funding": [ { @@ -8112,24 +8113,24 @@ "type": "tidelift" } ], - "time": "2024-03-29T19:07:53+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/css-selector", - "version": "v6.4.3", + "version": "v7.0.7", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "ee0f7ed5cf298cc019431bb3b3977ebc52b86229" + "reference": "b08a4ad89e84b29cec285b7b1f781a7ae51cf4bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/ee0f7ed5cf298cc019431bb3b3977ebc52b86229", - "reference": "ee0f7ed5cf298cc019431bb3b3977ebc52b86229", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/b08a4ad89e84b29cec285b7b1f781a7ae51cf4bc", + "reference": "b08a4ad89e84b29cec285b7b1f781a7ae51cf4bc", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "type": "library", "autoload": { @@ -8161,7 +8162,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.4.3" + "source": "https://github.com/symfony/css-selector/tree/v7.0.7" }, "funding": [ { @@ -8177,20 +8178,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-04-18T09:29:19+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "shasum": "" }, "require": { @@ -8199,7 +8200,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -8228,7 +8229,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, "funding": [ { @@ -8244,20 +8245,20 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/error-handler", - "version": "v6.4.6", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "64db1c1802e3a4557e37ba33031ac39f452ac5d4" + "reference": "667a072466c6a53827ed7b119af93806b884cbb3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/64db1c1802e3a4557e37ba33031ac39f452ac5d4", - "reference": "64db1c1802e3a4557e37ba33031ac39f452ac5d4", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/667a072466c6a53827ed7b119af93806b884cbb3", + "reference": "667a072466c6a53827ed7b119af93806b884cbb3", "shasum": "" }, "require": { @@ -8303,7 +8304,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.4.6" + "source": "https://github.com/symfony/error-handler/tree/v6.4.7" }, "funding": [ { @@ -8319,28 +8320,28 @@ "type": "tidelift" } ], - "time": "2024-03-19T11:56:30+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.4.3", + "version": "v7.0.7", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "ae9d3a6f3003a6caf56acd7466d8d52378d44fef" + "reference": "db2a7fab994d67d92356bb39c367db115d9d30f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ae9d3a6f3003a6caf56acd7466d8d52378d44fef", - "reference": "ae9d3a6f3003a6caf56acd7466d8d52378d44fef", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/db2a7fab994d67d92356bb39c367db115d9d30f9", + "reference": "db2a7fab994d67d92356bb39c367db115d9d30f9", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<5.4", + "symfony/dependency-injection": "<6.4", "symfony/service-contracts": "<2.5" }, "provide": { @@ -8349,13 +8350,13 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^5.4|^6.0|^7.0" + "symfony/stopwatch": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -8383,7 +8384,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.4.3" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.0.7" }, "funding": [ { @@ -8399,20 +8400,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-04-18T09:29:19+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.4.2", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "4e64b49bf370ade88e567de29465762e316e4224" + "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/4e64b49bf370ade88e567de29465762e316e4224", - "reference": "4e64b49bf370ade88e567de29465762e316e4224", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50", + "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50", "shasum": "" }, "require": { @@ -8422,7 +8423,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -8459,7 +8460,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.2" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0" }, "funding": [ { @@ -8475,20 +8476,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/finder", - "version": "v6.4.0", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "11d736e97f116ac375a81f96e662911a34cd50ce" + "reference": "511c48990be17358c23bf45c5d71ab85d40fb764" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/11d736e97f116ac375a81f96e662911a34cd50ce", - "reference": "11d736e97f116ac375a81f96e662911a34cd50ce", + "url": "https://api.github.com/repos/symfony/finder/zipball/511c48990be17358c23bf45c5d71ab85d40fb764", + "reference": "511c48990be17358c23bf45c5d71ab85d40fb764", "shasum": "" }, "require": { @@ -8523,7 +8524,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.0" + "source": "https://github.com/symfony/finder/tree/v6.4.7" }, "funding": [ { @@ -8539,20 +8540,20 @@ "type": "tidelift" } ], - "time": "2023-10-31T17:30:12+00:00" + "time": "2024-04-23T10:36:43+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.6", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "6a46c0ea9b099f9a5132d560a51833ffcbd5b0d9" + "reference": "3683d8107cf1efdd24795cc5f7482be1eded34ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/6a46c0ea9b099f9a5132d560a51833ffcbd5b0d9", - "reference": "6a46c0ea9b099f9a5132d560a51833ffcbd5b0d9", + "url": "https://api.github.com/repos/symfony/http-client/zipball/3683d8107cf1efdd24795cc5f7482be1eded34ac", + "reference": "3683d8107cf1efdd24795cc5f7482be1eded34ac", "shasum": "" }, "require": { @@ -8616,7 +8617,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.6" + "source": "https://github.com/symfony/http-client/tree/v6.4.7" }, "funding": [ { @@ -8632,20 +8633,20 @@ "type": "tidelift" } ], - "time": "2024-04-01T20:35:50+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/http-client-contracts", - "version": "v3.4.2", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "b6b5c876b3a4ed74460e2c5ac53bbce2f12e2a7e" + "reference": "20414d96f391677bf80078aa55baece78b82647d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/b6b5c876b3a4ed74460e2c5ac53bbce2f12e2a7e", - "reference": "b6b5c876b3a4ed74460e2c5ac53bbce2f12e2a7e", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/20414d96f391677bf80078aa55baece78b82647d", + "reference": "20414d96f391677bf80078aa55baece78b82647d", "shasum": "" }, "require": { @@ -8654,7 +8655,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -8694,7 +8695,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.4.2" + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.0" }, "funding": [ { @@ -8710,20 +8711,20 @@ "type": "tidelift" } ], - "time": "2024-04-01T18:51:09+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.4.4", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304" + "reference": "b4db6b833035477cb70e18d0ae33cb7c2b521759" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ebc713bc6e6f4b53f46539fc158be85dfcd77304", - "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b4db6b833035477cb70e18d0ae33cb7c2b521759", + "reference": "b4db6b833035477cb70e18d0ae33cb7c2b521759", "shasum": "" }, "require": { @@ -8771,7 +8772,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.4.4" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.7" }, "funding": [ { @@ -8787,20 +8788,20 @@ "type": "tidelift" } ], - "time": "2024-02-08T15:01:18+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.6", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "060038863743fd0cd982be06acecccf246d35653" + "reference": "b7b5e6cdef670a0c82d015a966ffc7e855861a98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/060038863743fd0cd982be06acecccf246d35653", - "reference": "060038863743fd0cd982be06acecccf246d35653", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/b7b5e6cdef670a0c82d015a966ffc7e855861a98", + "reference": "b7b5e6cdef670a0c82d015a966ffc7e855861a98", "shasum": "" }, "require": { @@ -8855,6 +8856,7 @@ "symfony/translation-contracts": "^2.5|^3", "symfony/uid": "^5.4|^6.0|^7.0", "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^5.4|^6.4|^7.0", "symfony/var-exporter": "^6.2|^7.0", "twig/twig": "^2.13|^3.0.4" }, @@ -8884,7 +8886,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.4.6" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.7" }, "funding": [ { @@ -8900,20 +8902,20 @@ "type": "tidelift" } ], - "time": "2024-04-03T06:09:15+00:00" + "time": "2024-04-29T11:24:44+00:00" }, { "name": "symfony/mailer", - "version": "v6.4.6", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "677f34a6f4b4559e08acf73ae0aec460479e5859" + "reference": "2c446d4e446995bed983c0b5bb9ff837e8de7dbd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/677f34a6f4b4559e08acf73ae0aec460479e5859", - "reference": "677f34a6f4b4559e08acf73ae0aec460479e5859", + "url": "https://api.github.com/repos/symfony/mailer/zipball/2c446d4e446995bed983c0b5bb9ff837e8de7dbd", + "reference": "2c446d4e446995bed983c0b5bb9ff837e8de7dbd", "shasum": "" }, "require": { @@ -8964,7 +8966,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.4.6" + "source": "https://github.com/symfony/mailer/tree/v6.4.7" }, "funding": [ { @@ -8980,20 +8982,20 @@ "type": "tidelift" } ], - "time": "2024-03-27T21:14:17+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/mailgun-mailer", - "version": "v6.4.4", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/mailgun-mailer.git", - "reference": "8c018872b40ce050590b6d18cf741db0c8313435" + "reference": "044eede71c3eb5fbe7192042b8c0d04987b5653d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/8c018872b40ce050590b6d18cf741db0c8313435", - "reference": "8c018872b40ce050590b6d18cf741db0c8313435", + "url": "https://api.github.com/repos/symfony/mailgun-mailer/zipball/044eede71c3eb5fbe7192042b8c0d04987b5653d", + "reference": "044eede71c3eb5fbe7192042b8c0d04987b5653d", "shasum": "" }, "require": { @@ -9033,7 +9035,7 @@ "description": "Symfony Mailgun Mailer Bridge", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailgun-mailer/tree/v6.4.4" + "source": "https://github.com/symfony/mailgun-mailer/tree/v6.4.7" }, "funding": [ { @@ -9049,20 +9051,20 @@ "type": "tidelift" } ], - "time": "2024-02-14T06:31:46+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/mime", - "version": "v6.4.6", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "14762b86918823cb42e3558cdcca62e58b5227fe" + "reference": "decadcf3865918ecfcbfa90968553994ce935a5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/14762b86918823cb42e3558cdcca62e58b5227fe", - "reference": "14762b86918823cb42e3558cdcca62e58b5227fe", + "url": "https://api.github.com/repos/symfony/mime/zipball/decadcf3865918ecfcbfa90968553994ce935a5e", + "reference": "decadcf3865918ecfcbfa90968553994ce935a5e", "shasum": "" }, "require": { @@ -9118,7 +9120,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.6" + "source": "https://github.com/symfony/mime/tree/v6.4.7" }, "funding": [ { @@ -9134,7 +9136,7 @@ "type": "tidelift" } ], - "time": "2024-03-21T19:36:20+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/polyfill-ctype", @@ -9849,16 +9851,16 @@ }, { "name": "symfony/process", - "version": "v6.4.4", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "710e27879e9be3395de2b98da3f52a946039f297" + "reference": "cdb1c81c145fd5aa9b0038bab694035020943381" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/710e27879e9be3395de2b98da3f52a946039f297", - "reference": "710e27879e9be3395de2b98da3f52a946039f297", + "url": "https://api.github.com/repos/symfony/process/zipball/cdb1c81c145fd5aa9b0038bab694035020943381", + "reference": "cdb1c81c145fd5aa9b0038bab694035020943381", "shasum": "" }, "require": { @@ -9890,7 +9892,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.4" + "source": "https://github.com/symfony/process/tree/v6.4.7" }, "funding": [ { @@ -9906,7 +9908,7 @@ "type": "tidelift" } ], - "time": "2024-02-20T12:31:00+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -9999,16 +10001,16 @@ }, { "name": "symfony/routing", - "version": "v6.4.6", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "f2591fd1f8c6e3734656b5d6b3829e8bf81f507c" + "reference": "276e06398f71fa2a973264d94f28150f93cfb907" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/f2591fd1f8c6e3734656b5d6b3829e8bf81f507c", - "reference": "f2591fd1f8c6e3734656b5d6b3829e8bf81f507c", + "url": "https://api.github.com/repos/symfony/routing/zipball/276e06398f71fa2a973264d94f28150f93cfb907", + "reference": "276e06398f71fa2a973264d94f28150f93cfb907", "shasum": "" }, "require": { @@ -10062,7 +10064,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.6" + "source": "https://github.com/symfony/routing/tree/v6.4.7" }, "funding": [ { @@ -10078,25 +10080,26 @@ "type": "tidelift" } ], - "time": "2024-03-28T13:28:49+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.4.2", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "11bbf19a0fb7b36345861e85c5768844c552906e" + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/11bbf19a0fb7b36345861e85c5768844c552906e", - "reference": "11bbf19a0fb7b36345861e85c5768844c552906e", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", + "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^1.1|^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -10104,7 +10107,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -10144,7 +10147,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.2" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.0" }, "funding": [ { @@ -10160,24 +10163,24 @@ "type": "tidelift" } ], - "time": "2023-12-19T21:51:00+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/string", - "version": "v6.4.4", + "version": "v7.0.7", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9" + "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9", - "reference": "4e465a95bdc32f49cf4c7f07f751b843bbd6dcd9", + "url": "https://api.github.com/repos/symfony/string/zipball/e405b5424dc2528e02e31ba26b83a79fd4eb8f63", + "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", @@ -10187,11 +10190,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/intl": "^6.2|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0|^7.0" + "symfony/var-exporter": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -10230,7 +10233,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.4" + "source": "https://github.com/symfony/string/tree/v7.0.7" }, "funding": [ { @@ -10246,20 +10249,20 @@ "type": "tidelift" } ], - "time": "2024-02-01T13:16:41+00:00" + "time": "2024-04-18T09:29:19+00:00" }, { "name": "symfony/translation", - "version": "v6.4.4", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "bce6a5a78e94566641b2594d17e48b0da3184a8e" + "reference": "7495687c58bfd88b7883823747b0656d90679123" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/bce6a5a78e94566641b2594d17e48b0da3184a8e", - "reference": "bce6a5a78e94566641b2594d17e48b0da3184a8e", + "url": "https://api.github.com/repos/symfony/translation/zipball/7495687c58bfd88b7883823747b0656d90679123", + "reference": "7495687c58bfd88b7883823747b0656d90679123", "shasum": "" }, "require": { @@ -10325,7 +10328,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.4.4" + "source": "https://github.com/symfony/translation/tree/v6.4.7" }, "funding": [ { @@ -10341,20 +10344,20 @@ "type": "tidelift" } ], - "time": "2024-02-20T13:16:58+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.4.2", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "43810bdb2ddb5400e5c5e778e27b210a0ca83b6b" + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/43810bdb2ddb5400e5c5e778e27b210a0ca83b6b", - "reference": "43810bdb2ddb5400e5c5e778e27b210a0ca83b6b", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", + "reference": "b9d2189887bb6b2e0367a9fc7136c5239ab9b05a", "shasum": "" }, "require": { @@ -10363,7 +10366,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -10403,7 +10406,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.4.2" + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.0" }, "funding": [ { @@ -10419,20 +10422,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/uid", - "version": "v6.4.3", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/uid.git", - "reference": "1d31267211cc3a2fff32bcfc7c1818dac41b6fc0" + "reference": "a66efcb71d8bc3a207d9d78e0bd67f3321510355" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/uid/zipball/1d31267211cc3a2fff32bcfc7c1818dac41b6fc0", - "reference": "1d31267211cc3a2fff32bcfc7c1818dac41b6fc0", + "url": "https://api.github.com/repos/symfony/uid/zipball/a66efcb71d8bc3a207d9d78e0bd67f3321510355", + "reference": "a66efcb71d8bc3a207d9d78e0bd67f3321510355", "shasum": "" }, "require": { @@ -10477,7 +10480,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/uid/tree/v6.4.3" + "source": "https://github.com/symfony/uid/tree/v6.4.7" }, "funding": [ { @@ -10493,20 +10496,20 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.6", + "version": "v6.4.7", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "95bd2706a97fb875185b51ecaa6112ec184233d4" + "reference": "7a9cd977cd1c5fed3694bee52990866432af07d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/95bd2706a97fb875185b51ecaa6112ec184233d4", - "reference": "95bd2706a97fb875185b51ecaa6112ec184233d4", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7a9cd977cd1c5fed3694bee52990866432af07d7", + "reference": "7a9cd977cd1c5fed3694bee52990866432af07d7", "shasum": "" }, "require": { @@ -10562,7 +10565,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.6" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.7" }, "funding": [ { @@ -10578,30 +10581,29 @@ "type": "tidelift" } ], - "time": "2024-03-19T11:56:30+00:00" + "time": "2024-04-18T09:22:46+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.6", + "version": "v7.0.7", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "20888cf4d11de203613515cf0587828bf5af0fe7" + "reference": "cdecc0022e40e90340ba1a59a3d5ccf069777078" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/20888cf4d11de203613515cf0587828bf5af0fe7", - "reference": "20888cf4d11de203613515cf0587828bf5af0fe7", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/cdecc0022e40e90340ba1a59a3d5ccf069777078", + "reference": "cdecc0022e40e90340ba1a59a3d5ccf069777078", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3" + "php": ">=8.2" }, "require-dev": { "symfony/property-access": "^6.4|^7.0", "symfony/serializer": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/var-dumper": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -10639,7 +10641,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.6" + "source": "https://github.com/symfony/var-exporter/tree/v7.0.7" }, "funding": [ { @@ -10655,7 +10657,7 @@ "type": "tidelift" } ], - "time": "2024-03-20T21:07:14+00:00" + "time": "2024-04-18T09:29:19+00:00" }, { "name": "tightenco/collect", @@ -11831,16 +11833,16 @@ }, { "name": "laravel/pint", - "version": "v1.15.1", + "version": "v1.15.3", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "5f288b5e79938cc72f5c298d384e639de87507c6" + "reference": "3600b5d17aff52f6100ea4921849deacbbeb8656" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/5f288b5e79938cc72f5c298d384e639de87507c6", - "reference": "5f288b5e79938cc72f5c298d384e639de87507c6", + "url": "https://api.github.com/repos/laravel/pint/zipball/3600b5d17aff52f6100ea4921849deacbbeb8656", + "reference": "3600b5d17aff52f6100ea4921849deacbbeb8656", "shasum": "" }, "require": { @@ -11851,13 +11853,13 @@ "php": "^8.1.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.52.1", - "illuminate/view": "^10.48.4", - "larastan/larastan": "^2.9.2", + "friendsofphp/php-cs-fixer": "^3.54.0", + "illuminate/view": "^10.48.8", + "larastan/larastan": "^2.9.5", "laravel-zero/framework": "^10.3.0", "mockery/mockery": "^1.6.11", "nunomaduro/termwind": "^1.15.1", - "pestphp/pest": "^2.34.5" + "pestphp/pest": "^2.34.7" }, "bin": [ "builds/pint" @@ -11893,7 +11895,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2024-04-02T14:28:47+00:00" + "time": "2024-04-30T15:02:26+00:00" }, { "name": "laravel/telescope", diff --git a/config/pixelfed.php b/config/pixelfed.php index 9da274434..c4dc5828b 100644 --- a/config/pixelfed.php +++ b/config/pixelfed.php @@ -23,7 +23,7 @@ return [ | This value is the version of your Pixelfed instance. | */ - 'version' => '0.11.13', + 'version' => '0.12.1', /* |-------------------------------------------------------------------------- diff --git a/public/embed.js b/public/embed.js index 5acc20efe..ab7f9a539 100644 Binary files a/public/embed.js and b/public/embed.js differ diff --git a/resources/assets/components/partials/post/PostContent.vue b/resources/assets/components/partials/post/PostContent.vue index 0a88acb19..9672d52e9 100644 --- a/resources/assets/components/partials/post/PostContent.vue +++ b/resources/assets/components/partials/post/PostContent.vue @@ -169,7 +169,7 @@ diff --git a/resources/assets/components/presenter/PhotoAlbumPresenter.vue b/resources/assets/components/presenter/PhotoAlbumPresenter.vue new file mode 100644 index 000000000..3adda10df --- /dev/null +++ b/resources/assets/components/presenter/PhotoAlbumPresenter.vue @@ -0,0 +1,188 @@ + + + + + + diff --git a/resources/assets/components/presenter/PhotoPresenter.vue b/resources/assets/components/presenter/PhotoPresenter.vue new file mode 100644 index 000000000..eca896b0f --- /dev/null +++ b/resources/assets/components/presenter/PhotoPresenter.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/resources/assets/components/presenter/VideoAlbumPresenter.vue b/resources/assets/components/presenter/VideoAlbumPresenter.vue new file mode 100644 index 000000000..97285b158 --- /dev/null +++ b/resources/assets/components/presenter/VideoAlbumPresenter.vue @@ -0,0 +1,44 @@ + + + diff --git a/resources/assets/components/presenter/VideoPresenter.vue b/resources/assets/components/presenter/VideoPresenter.vue new file mode 100644 index 000000000..217dbb3de --- /dev/null +++ b/resources/assets/components/presenter/VideoPresenter.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/resources/assets/js/landing.js b/resources/assets/js/landing.js index 6d903bcb5..cdaf0233b 100644 --- a/resources/assets/js/landing.js +++ b/resources/assets/js/landing.js @@ -48,27 +48,27 @@ Vue.use(VueTimeago, { Vue.component( 'photo-presenter', - require('./components/presenter/PhotoPresenter.vue').default + require('./../components/presenter/PhotoPresenter.vue').default ); Vue.component( 'video-presenter', - require('./components/presenter/VideoPresenter.vue').default + require('./../components/presenter/VideoPresenter.vue').default ); Vue.component( 'photo-album-presenter', - require('./components/presenter/PhotoAlbumPresenter.vue').default + require('./../components/presenter/PhotoAlbumPresenter.vue').default ); Vue.component( 'video-album-presenter', - require('./components/presenter/VideoAlbumPresenter.vue').default + require('./../components/presenter/VideoAlbumPresenter.vue').default ); Vue.component( 'mixed-album-presenter', - require('./components/presenter/MixedAlbumPresenter.vue').default + require('./../components/presenter/MixedAlbumPresenter.vue').default ); Vue.component( diff --git a/resources/assets/js/profile.js b/resources/assets/js/profile.js index 452445ed6..ab72c974e 100644 --- a/resources/assets/js/profile.js +++ b/resources/assets/js/profile.js @@ -1,26 +1,26 @@ Vue.component( 'photo-presenter', - require('./components/presenter/PhotoPresenter.vue').default + require('./../components/presenter/PhotoPresenter.vue').default ); Vue.component( 'video-presenter', - require('./components/presenter/VideoPresenter.vue').default + require('./../components/presenter/VideoPresenter.vue').default ); Vue.component( 'photo-album-presenter', - require('./components/presenter/PhotoAlbumPresenter.vue').default + require('./../components/presenter/PhotoAlbumPresenter.vue').default ); Vue.component( 'video-album-presenter', - require('./components/presenter/VideoAlbumPresenter.vue').default + require('./../components/presenter/VideoAlbumPresenter.vue').default ); Vue.component( 'mixed-album-presenter', - require('./components/presenter/MixedAlbumPresenter.vue').default + require('./../components/presenter/MixedAlbumPresenter.vue').default ); Vue.component( diff --git a/resources/assets/js/spa.js b/resources/assets/js/spa.js index be31b5371..c99763170 100644 --- a/resources/assets/js/spa.js +++ b/resources/assets/js/spa.js @@ -60,27 +60,27 @@ Vue.component( Vue.component( 'photo-presenter', - require('./components/presenter/PhotoPresenter.vue').default + require('./../components/presenter/PhotoPresenter.vue').default ); Vue.component( 'video-presenter', - require('./components/presenter/VideoPresenter.vue').default + require('./../components/presenter/VideoPresenter.vue').default ); Vue.component( 'photo-album-presenter', - require('./components/presenter/PhotoAlbumPresenter.vue').default + require('./../components/presenter/PhotoAlbumPresenter.vue').default ); Vue.component( 'video-album-presenter', - require('./components/presenter/VideoAlbumPresenter.vue').default + require('./../components/presenter/VideoAlbumPresenter.vue').default ); Vue.component( 'mixed-album-presenter', - require('./components/presenter/MixedAlbumPresenter.vue').default + require('./../components/presenter/MixedAlbumPresenter.vue').default ); Vue.component( diff --git a/resources/assets/js/status.js b/resources/assets/js/status.js index ddd29a4ef..43a1a76ae 100644 --- a/resources/assets/js/status.js +++ b/resources/assets/js/status.js @@ -1,26 +1,26 @@ Vue.component( 'photo-presenter', - require('./components/presenter/PhotoPresenter.vue').default + require('./../components/presenter/PhotoPresenter.vue').default ); Vue.component( 'video-presenter', - require('./components/presenter/VideoPresenter.vue').default + require('./../components/presenter/VideoPresenter.vue').default ); Vue.component( 'photo-album-presenter', - require('./components/presenter/PhotoAlbumPresenter.vue').default + require('./../components/presenter/PhotoAlbumPresenter.vue').default ); Vue.component( 'video-album-presenter', - require('./components/presenter/VideoAlbumPresenter.vue').default + require('./../components/presenter/VideoAlbumPresenter.vue').default ); Vue.component( 'mixed-album-presenter', - require('./components/presenter/MixedAlbumPresenter.vue').default + require('./../components/presenter/MixedAlbumPresenter.vue').default ); Vue.component( @@ -32,3 +32,13 @@ Vue.component( 'post-component', require('./components/PostComponent.vue').default ); + +// Vue.component( +// 'post-next', +// require('./components/PostNext.vue').default +// ); + +// Vue.component( +// 'video-component', +// require('./components/VideoComponent.vue').default +// ); diff --git a/resources/assets/js/timeline.js b/resources/assets/js/timeline.js index 5858ac8e3..8858c3691 100644 --- a/resources/assets/js/timeline.js +++ b/resources/assets/js/timeline.js @@ -5,27 +5,27 @@ Vue.component( Vue.component( 'photo-presenter', - require('./components/presenter/PhotoPresenter.vue').default + require('./../components/presenter/PhotoPresenter.vue').default ); Vue.component( 'video-presenter', - require('./components/presenter/VideoPresenter.vue').default + require('./../components/presenter/VideoPresenter.vue').default ); Vue.component( 'photo-album-presenter', - require('./components/presenter/PhotoAlbumPresenter.vue').default + require('./../components/presenter/PhotoAlbumPresenter.vue').default ); Vue.component( 'video-album-presenter', - require('./components/presenter/VideoAlbumPresenter.vue').default + require('./../components/presenter/VideoAlbumPresenter.vue').default ); Vue.component( 'mixed-album-presenter', - require('./components/presenter/MixedAlbumPresenter.vue').default + require('./../components/presenter/MixedAlbumPresenter.vue').default ); Vue.component( @@ -46,4 +46,4 @@ Vue.component( Vue.component( 'story-component', require('./components/StoryTimelineComponent.vue').default -); \ No newline at end of file +); diff --git a/resources/views/profile/embed.blade.php b/resources/views/profile/embed.blade.php index aeb6a5b99..98b8b2692 100644 --- a/resources/views/profile/embed.blade.php +++ b/resources/views/profile/embed.blade.php @@ -1,118 +1,108 @@ - - - + + - - {{ $title ?? config('app.name', 'Pixelfed') }} - + {{ $title ?? config_cache('app.name', 'Pixelfed') }} - + - - + -
-
-
-
- - - {{$profile['username']}} - -
-
- {{config('pixelfed.domain.app')}} - +
+
+ +
+
+
+

+

Posts

+
+
+

+

Followers

+
+
+

Follow

+
+
+
+
+ +
-
-
-
-
-

-

Posts

-
-
-

-

Followers

-
-
-

Follow

-
-
-
-
- -
-
- - - - - - - + diff --git a/resources/views/status/embed.blade.php b/resources/views/status/embed.blade.php index 54d9b7330..02ab2de90 100644 --- a/resources/views/status/embed.blade.php +++ b/resources/views/status/embed.blade.php @@ -1,172 +1,72 @@ - + - - - - - - - {{ $title ?? config('app.name', 'Pixelfed') }} - - - - - - - - - - - - + + + + + {{ $title ?? config_cache('app.name', 'Pixelfed') }} + + + + + + + + + + -
- @php($item = $status) -
- - - @php($status = $item) - @switch($status->viewType()) - @case('photo') - @case('image') - @if($status->is_nsfw) -
- -

CW / NSFW / Hidden Media

-

(click to show)

-
-
- - -
- @else -
- -
- @endif - @break - @case('photo:album') - - @break - @case('video') - @if($status->is_nsfw) -
- -

CW / NSFW / Hidden Media

-

(click to show)

-
-
- -
-
- @else -
- -
- @endif - @break - @case('video-album') - @if($status->is_nsfw) -
- -

CW / NSFW / Hidden Media

-

(click to show)

-
-
- -
-
- @else -
- -
- @endif - @break - @endswitch - - @if($layout != 'compact') -
- -
-
-

- - {{$item->profile->username}} - - @if($showCaption) - {!! $item->rendered ?? e($item->caption) !!} - @endif -

-
-
- @endif - -
-
- - - - - +
+
+ + +
+ +
+
+ @if($layout != 'compact') +
+ +
+
+

+ + {{$status['account']['username']}} + + @if($showCaption) + {{ $status['content_text'] }} + @endif +

+
+
+ @endif + +
+
+ diff --git a/webpack.mix.js b/webpack.mix.js index 8d78b82c8..aadcac397 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -1,8 +1,10 @@ let mix = require('laravel-mix'); const fs = require("fs"); +const path = require("path"); mix.before(() => { - fs.rmSync('public/js', { recursive: true, force: true }); + fs.rmSync('public/css', { recursive: true, force: true }); + fs.rmSync('public/js', { recursive: true, force: true }); }); @@ -46,31 +48,35 @@ mix.version(); const TerserPlugin = require('terser-webpack-plugin'); mix.options({ - processCssUrls: false, - terser: { - parallel: true, - terserOptions: { - compress: true, - output: { - comments: false - } - } - } + processCssUrls: false, + terser: { + parallel: true, + terserOptions: { + compress: true, + output: { + comments: false + } + } + } }) +mix.alias({ + '@': path.join(__dirname, 'resources/assets/components'), + '~': path.join(__dirname, 'resources/assets/js/components'), +}); mix.webpackConfig({ - optimization: { - providedExports: false, - sideEffects: false, - usedExports: false, - minimize: true, - minimizer: [ new TerserPlugin({ - extractComments: false, - })] - }, - output: { - chunkFilename: 'js/[name].[chunkhash].js', - } + optimization: { + providedExports: false, + sideEffects: false, + usedExports: false, + minimize: true, + minimizer: [ new TerserPlugin({ + extractComments: false, + })] + }, + output: { + chunkFilename: 'js/[name].[chunkhash].js', + } }); mix.autoload({ - jquery: ['$', 'jQuery', 'window.jQuery'] + jquery: ['$', 'jQuery', 'window.jQuery'] });