From 3762d6eb11e7242f18e65ef6cd8077516ec94430 Mon Sep 17 00:00:00 2001 From: HDVinnie Date: Tue, 30 Apr 2024 14:10:06 -0400 Subject: [PATCH 1/6] (Add) Request #3792 (#3795) * add: #3792 - closes #3792 --- .../Controllers/Staff/MassEmailController.php | 42 +++++++++ app/Http/Requests/Staff/MassEmailRequest.php | 45 ++++++++++ app/Jobs/SendMassEmail.php | 54 ++++++++++++ app/Notifications/MassEmail.php | 52 +++++++++++ lang/en/common.php | 2 + lang/en/staff.php | 1 + .../views/Staff/dashboard/index.blade.php | 9 ++ .../views/Staff/mass_email/create.blade.php | 88 +++++++++++++++++++ routes/web.php | 8 ++ 9 files changed, 301 insertions(+) create mode 100644 app/Http/Controllers/Staff/MassEmailController.php create mode 100644 app/Http/Requests/Staff/MassEmailRequest.php create mode 100644 app/Jobs/SendMassEmail.php create mode 100644 app/Notifications/MassEmail.php create mode 100644 resources/views/Staff/mass_email/create.blade.php diff --git a/app/Http/Controllers/Staff/MassEmailController.php b/app/Http/Controllers/Staff/MassEmailController.php new file mode 100644 index 0000000000..f9e80814fa --- /dev/null +++ b/app/Http/Controllers/Staff/MassEmailController.php @@ -0,0 +1,42 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +namespace App\Http\Controllers\Staff; + +use App\Http\Controllers\Controller; +use App\Http\Requests\Staff\MassEmailRequest; +use App\Jobs\SendMassEmail; +use App\Models\Group; +use App\Models\User; + +class MassEmailController extends Controller +{ + public function create(): \Illuminate\Contracts\View\View|\Illuminate\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\Foundation\Application + { + return view('Staff.mass_email.create', ['groups' => Group::orderBy('position')->get()]); + } + + public function store(MassEmailRequest $request): \Illuminate\Http\RedirectResponse + { + $request->validated(); + + $users = User::whereIntegerInRaw('group_id', $request->groups)->get(); + + foreach ($users as $user) { + dispatch(new SendMassEmail($user, $request->subject, $request->message)); + } + + return to_route('staff.dashboard.index') + ->withSuccess('Emails have been queued for processing to avoid spamming the mail server'); + } +} diff --git a/app/Http/Requests/Staff/MassEmailRequest.php b/app/Http/Requests/Staff/MassEmailRequest.php new file mode 100644 index 0000000000..1f9513866e --- /dev/null +++ b/app/Http/Requests/Staff/MassEmailRequest.php @@ -0,0 +1,45 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +namespace App\Http\Requests\Staff; + +use Illuminate\Foundation\Http\FormRequest; + +class MassEmailRequest extends FormRequest +{ + /** + * Get the validation rules that apply to the request. + * + * @return array|string> + */ + public function rules(): array + { + return [ + 'groups' => [ + 'required', + 'array' + ], + 'groups.*' => [ + 'exists:groups,id' + ], + 'subject' => [ + 'required', + 'string' + ], + 'message' => [ + 'required', + 'string' + ], + ]; + } +} diff --git a/app/Jobs/SendMassEmail.php b/app/Jobs/SendMassEmail.php new file mode 100644 index 0000000000..792371298c --- /dev/null +++ b/app/Jobs/SendMassEmail.php @@ -0,0 +1,54 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +namespace App\Jobs; + +use App\Models\User; +use App\Notifications\MassEmail; +use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldQueue; +use Illuminate\Foundation\Bus\Dispatchable; +use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Queue\SerializesModels; + +class SendMassEmail implements ShouldQueue +{ + use Dispatchable; + use InteractsWithQueue; + use Queueable; + use SerializesModels; + + /** + * The number of times the job may be attempted. + */ + public int $tries = 3; + + /** + * Create a new job instance. + */ + public function __construct(public User $user, public string $subject, public string $message) + { + } + + /** + * Execute the job. + */ + public function handle(): void + { + if ($this->attempts() > 2) { + $this->delay(min(5 * $this->attempts(), 300)); + } + + $this->user->notify(new MassEmail($this->subject, $this->message)); + } +} diff --git a/app/Notifications/MassEmail.php b/app/Notifications/MassEmail.php new file mode 100644 index 0000000000..34c629798c --- /dev/null +++ b/app/Notifications/MassEmail.php @@ -0,0 +1,52 @@ + + * @license https://www.gnu.org/licenses/agpl-3.0.en.html/ GNU Affero General Public License v3.0 + */ + +namespace App\Notifications; + +use Illuminate\Bus\Queueable; +use Illuminate\Notifications\Messages\MailMessage; +use Illuminate\Notifications\Notification; + +class MassEmail extends Notification +{ + use Queueable; + + /** + * Create a new notification instance. + */ + public function __construct(public string $subject, public string $message) + { + } + + /** + * Get the notification's delivery channels. + * + * @return array + */ + public function via(object $notifiable): array + { + return ['mail']; + } + + /** + * Get the mail representation of the notification. + */ + public function toMail(object $notifiable): MailMessage + { + return (new MailMessage()) + ->subject($this->subject) + ->line($this->message) + ->action('Login Now', route('login')) + ->line('Thank you for using 🚀'.config('other.title')); + } +} diff --git a/lang/en/common.php b/lang/en/common.php index 27682b6434..f2727d0c7e 100644 --- a/lang/en/common.php +++ b/lang/en/common.php @@ -184,6 +184,7 @@ 'search-results' => 'Search Results', 'search-results-desc' => 'Please see your results below', 'second' => 'Second', + 'send' => 'Send', 'select' => 'Select', 'similar' => 'Similar', 'something-went-wrong' => 'Something Went Wrong!', @@ -195,6 +196,7 @@ 'stats' => 'Stats', 'status' => 'Status', 'sticked' => 'Sticked', + 'subject' => 'Subject', 'submit' => 'Submit', 'subscriptions' => 'Subscriptions', 'subtitle' => 'Subtitle', diff --git a/lang/en/staff.php b/lang/en/staff.php index 929588e910..a69f76d45a 100644 --- a/lang/en/staff.php +++ b/lang/en/staff.php @@ -41,6 +41,7 @@ 'link' => 'Link', 'links' => 'Links', 'logs' => 'Logs', + 'mass-email' => 'Mass Email', 'mass-pm' => 'Mass PM', 'mass-validate-users' => 'Mass Validate Users', 'media-languages-desc' => '(Languages Used To Populate Language Dropdowns For Subtitles / Audios / Etc.)', diff --git a/resources/views/Staff/dashboard/index.blade.php b/resources/views/Staff/dashboard/index.blade.php index f1ef963a89..d673f63521 100644 --- a/resources/views/Staff/dashboard/index.blade.php +++ b/resources/views/Staff/dashboard/index.blade.php @@ -441,6 +441,15 @@ class="form__button form__button--text" {{ __('staff.mass-pm') }}

+

+ + + {{ __('staff.mass-email') }} + +

+ {{ __('staff.mass-email') }} - {{ __('staff.staff-dashboard') }} - + {{ config('other.title') }} + +@endsection + +@section('meta') + +@endsection + +@section('breadcrumbs') + + +@endsection + +@section('page', 'page__mass_email--index') + +@section('main') +
+

{{ __('staff.mass-email') }}

+
+ + @csrf +
+
+ Groups +
+ @foreach ($groups as $group) +

+ +

+ @endforeach +
+
+
+

+ + +

+ @livewire('bbcode-input', ['name' => 'message', 'label' => __('common.message'), 'required' => true]) +

+ +

+ +
+
+@endsection diff --git a/routes/web.php b/routes/web.php index ace40accce..506d24838f 100644 --- a/routes/web.php +++ b/routes/web.php @@ -921,6 +921,14 @@ Route::post('/mass-pm/store', [App\Http\Controllers\Staff\MassActionController::class, 'store'])->name('mass-pm.store'); }); + // Mass Email + Route::prefix('mass-email')->group(function (): void { + Route::name('mass_email.')->group(function (): void { + Route::get('/create', [App\Http\Controllers\Staff\MassEmailController::class, 'create'])->name('create'); + Route::post('/', [App\Http\Controllers\Staff\MassEmailController::class, 'store'])->name('store'); + }); + }); + // Media Lanuages (Languages Used To Populate Language Dropdowns For Subtitles / Audios / Etc.) Route::prefix('media-languages')->group(function (): void { Route::name('media_languages.')->group(function (): void { From 705432430620d5b45e472616a35163116406842e Mon Sep 17 00:00:00 2001 From: Roardom Date: Wed, 1 May 2024 01:28:33 +0000 Subject: [PATCH 2/6] add: phonetic soundex email and username searching --- app/Http/Livewire/UserSearch.php | 18 ++++++++++++++ .../views/livewire/user-search.blade.php | 24 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/app/Http/Livewire/UserSearch.php b/app/Http/Livewire/UserSearch.php index b2cbd00471..5f6799eb12 100644 --- a/app/Http/Livewire/UserSearch.php +++ b/app/Http/Livewire/UserSearch.php @@ -39,9 +39,15 @@ class UserSearch extends Component #[Url(history: true)] public string $username = ''; + #[Url(history: true)] + public string $soundexUsername = ''; + #[Url(history: true)] public string $email = ''; + #[Url(history: true)] + public string $soundexEmail = ''; + #[Url(history: true)] public string $rsskey = ''; @@ -81,7 +87,19 @@ final public function users(): \Illuminate\Contracts\Pagination\LengthAwarePagin return User::query() ->with('group') ->when($this->username !== '', fn ($query) => $query->where('username', 'LIKE', '%'.$this->username.'%')) + ->when( + $this->soundexUsername !== '', + fn ($query) => $query->whereRaw('SOUNDEX(username) = SOUNDEX(?)', [$this->soundexUsername]), + ) ->when($this->email !== '', fn ($query) => $query->where('email', 'LIKE', '%'.$this->email.'%')) + ->when( + $this->soundexEmail !== '', + fn ($query) => $query->when( + str_contains($this->soundexEmail, '@'), + fn ($query) => $query->whereRaw('SOUNDEX(email) = SOUNDEX(?)', [$this->soundexEmail]), + fn ($query) => $query->whereRaw("SOUNDEX(SUBSTRING_INDEX(email, '@', 1)) = SOUNDEX(SUBSTRING_INDEX(?, '@', 1))", [$this->soundexEmail]) + ) + ) ->when($this->rsskey !== '', fn ($query) => $query->where('rsskey', 'LIKE', '%'.$this->rsskey.'%')) ->when($this->apikey !== '', fn ($query) => $query->where('api_token', 'LIKE', '%'.$this->apikey.'%')) ->when($this->passkey !== '', fn ($query) => $query->where('passkey', 'LIKE', '%'.$this->passkey.'%')) diff --git a/resources/views/livewire/user-search.blade.php b/resources/views/livewire/user-search.blade.php index 7da924b9f7..db7ed89287 100644 --- a/resources/views/livewire/user-search.blade.php +++ b/resources/views/livewire/user-search.blade.php @@ -18,6 +18,18 @@ class="form__text" {{ __('common.username') }}

+

+ + +

+

+ + +

Date: Tue, 30 Apr 2024 09:15:37 +0000 Subject: [PATCH 3/6] refactor: simplify chatroom get echoes/audibles exist condition --- app/Http/Controllers/API/ChatController.php | 4 ++-- phpstan-baseline.neon | 10 ---------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/app/Http/Controllers/API/ChatController.php b/app/Http/Controllers/API/ChatController.php index 98fa063555..293bf31983 100644 --- a/app/Http/Controllers/API/ChatController.php +++ b/app/Http/Controllers/API/ChatController.php @@ -54,7 +54,7 @@ public function echoes(Request $request): \Illuminate\Http\Resources\Json\Anonym { $user = $request->user()->load(['echoes']); - if (!$user->echoes || (is_countable($user->echoes->toArray()) ? \count($user->echoes->toArray()) : 0) < 1) { + if ($user->echoes->isEmpty()) { $userEcho = new UserEcho(); $userEcho->user_id = $request->user()->id; $userEcho->room_id = 1; @@ -69,7 +69,7 @@ public function audibles(Request $request): \Illuminate\Http\Resources\Json\Anon { $user = $request->user()->load(['audibles']); - if (!$user->audibles || (is_countable($user->audibles->toArray()) ? \count($user->audibles->toArray()) : 0) < 1) { + if ($user->audibles->isEmpty()) { $userAudible = new UserAudible(); $userAudible->user_id = $request->user()->id; $userAudible->room_id = 1; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 5672fc1a05..33e4d833a0 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -525,11 +525,6 @@ parameters: count: 6 path: app/Http/Controllers/API/ChatController.php - - - message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#" - count: 2 - path: app/Http/Controllers/API/ChatController.php - - message: "#^Method App\\\\Http\\\\Controllers\\\\API\\\\ChatController\\:\\:botMessages\\(\\) has parameter \\$botId with no type specified\\.$#" count: 1 @@ -555,11 +550,6 @@ parameters: count: 1 path: app/Http/Controllers/API/ChatController.php - - - message: "#^Negated boolean expression is always false\\.$#" - count: 2 - path: app/Http/Controllers/API/ChatController.php - - message: "#^Property App\\\\Models\\\\UserAudible\\:\\:\\$status \\(int\\) does not accept bool\\.$#" count: 3 From d59ef3ba8decd96edb81b562dbb99ef636c4b03c Mon Sep 17 00:00:00 2001 From: Roardom Date: Tue, 30 Apr 2024 09:18:49 +0000 Subject: [PATCH 4/6] remove: unused action from chat controller --- app/Http/Controllers/API/ChatController.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/Http/Controllers/API/ChatController.php b/app/Http/Controllers/API/ChatController.php index 293bf31983..2682051071 100644 --- a/app/Http/Controllers/API/ChatController.php +++ b/app/Http/Controllers/API/ChatController.php @@ -567,11 +567,4 @@ public function updateUserTarget(Request $request): \Illuminate\Contracts\Routin return response($user); } - - public function updateBotTarget(Request $request): \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response - { - $user = $request->user()->load(['chatStatus', 'chatroom', 'group', 'echoes']); - - return response($user); - } } From 7a71cc7935a5f08ecbee31c1470ada63cde82fd0 Mon Sep 17 00:00:00 2001 From: Roardom Date: Wed, 1 May 2024 07:38:24 +0000 Subject: [PATCH 5/6] refactor: simplify echo/audible creation logic Refactor the code to be more idiomatic code. --- app/Bots/NerdBot.php | 82 ++++----- app/Bots/SystemBot.php | 83 ++++----- app/Http/Controllers/API/ChatController.php | 188 +++++--------------- app/Models/UserAudible.php | 7 + app/Models/UserEcho.php | 7 + phpstan-baseline.neon | 10 -- 6 files changed, 120 insertions(+), 257 deletions(-) diff --git a/app/Bots/NerdBot.php b/app/Bots/NerdBot.php index 8ede58b7ce..4549e076b6 100644 --- a/app/Bots/NerdBot.php +++ b/app/Bots/NerdBot.php @@ -282,70 +282,48 @@ public function pm(): true|\Illuminate\Http\Response|\Illuminate\Contracts\Routi $message = $this->message; if ($type === 'message' || $type === 'private') { - $receiverDirty = false; - $receiverEchoes = cache()->get('user-echoes'.$target->id); + // Create echo for user if missing + $echoes = cache()->remember( + 'user-echoes'.$target->id, + 3600, + fn () => UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get() + ); - if (!$receiverEchoes || !\is_array($receiverEchoes)) { - $receiverEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); - } - - $receiverListening = false; - - foreach ($receiverEchoes as $receiverEcho) { - if ($receiverEcho->bot_id === $this->bot->id) { - $receiverListening = true; - - break; - } - } + if ($echoes->doesntContain(fn ($echo) => $echo->bot_id == $this->bot->id)) { + UserEcho::create([ + 'user_id' => $target->id, + 'target_id' => $this->bot->id, + ]); - if (!$receiverListening) { - $receiverPort = new UserEcho(); - $receiverPort->user_id = $target->id; - $receiverPort->bot_id = $this->bot->id; - $receiverPort->save(); - $receiverEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); - $receiverDirty = true; - } - - if ($receiverDirty) { - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-echoes'.$target->id, $receiverEchoes, $expiresAt); - event(new Chatter('echo', $target->id, UserEchoResource::collection($receiverEchoes))); - } + $echoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); - $receiverDirty = false; - $receiverAudibles = cache()->get('user-audibles'.$target->id); + cache()->put('user-echoes'.$target->id, $echoes, 3600); - if (!$receiverAudibles || !\is_array($receiverAudibles)) { - $receiverAudibles = UserAudible::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); + Chatter::dispatch('echo', $target->id, UserEchoResource::collection($echoes)); } - $receiverListening = false; + // Create audible for user if missing + $audibles = cache()->remember( + 'user-audibles'.$target->id, + 3600, + fn () => UserAudible::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get() + ); - foreach ($receiverAudibles as $receiverEcho) { - if ($receiverEcho->bot_id === $this->bot->id) { - $receiverListening = true; + if ($audibles->doesntContain(fn ($audible) => $audible->bot_id == $this->bot->id)) { + UserAudible::create([ + 'user_id' => $target->id, + 'target_id' => $this->bot->id, + 'status' => false, + ]); - break; - } - } + $audibles = UserAudible::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); - if (!$receiverListening) { - $receiverPort = new UserAudible(); - $receiverPort->user_id = $target->id; - $receiverPort->bot_id = $this->bot->id; - $receiverPort->save(); - $receiverAudibles = UserAudible::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); - $receiverDirty = true; - } + cache()->put('user-audibles'.$target->id, $audibles, 3600); - if ($receiverDirty) { - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-audibles'.$target->id, $receiverAudibles, $expiresAt); - event(new Chatter('audible', $target->id, UserAudibleResource::collection($receiverAudibles))); + Chatter::dispatch('audible', $target->id, UserAudibleResource::collection($audibles)); } + // Create message if ($txt !== '') { $roomId = 0; $this->chatRepository->privateMessage($target->id, $roomId, $message, 1, $this->bot->id); diff --git a/app/Bots/SystemBot.php b/app/Bots/SystemBot.php index c9608d9eb4..e63d0d500b 100644 --- a/app/Bots/SystemBot.php +++ b/app/Bots/SystemBot.php @@ -23,7 +23,6 @@ use App\Models\UserEcho; use App\Notifications\NewBon; use App\Repositories\ChatRepository; -use Illuminate\Support\Carbon; class SystemBot { @@ -178,70 +177,48 @@ public function pm(): \Illuminate\Http\Response|bool|\Illuminate\Contracts\Found $message = $this->message; if ($type === 'message' || $type === 'private') { - $receiverDirty = false; - $receiverEchoes = cache()->get('user-echoes'.$target->id); - - if (!$receiverEchoes || !\is_array($receiverEchoes)) { - $receiverEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); - } - - $receiverListening = false; - - foreach ($receiverEchoes as $receiverEcho) { - if ($receiverEcho->bot_id === $this->bot->id) { - $receiverListening = true; - - break; - } - } + // Create echo for user if missing + $echoes = cache()->remember( + 'user-echoes'.$target->id, + 3600, + fn () => UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get() + ); - if (!$receiverListening) { - $receiverPort = new UserEcho(); - $receiverPort->user_id = $target->id; - $receiverPort->bot_id = $this->bot->id; - $receiverPort->save(); - $receiverEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); - $receiverDirty = true; - } + if ($echoes->doesntContain(fn ($echo) => $echo->bot_id == $this->bot->id)) { + UserEcho::create([ + 'user_id' => $target->id, + 'target_id' => $this->bot->id, + ]); - if ($receiverDirty) { - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-echoes'.$target->id, $receiverEchoes, $expiresAt); - event(new Chatter('echo', $target->id, UserEchoResource::collection($receiverEchoes))); - } + $echoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); - $receiverDirty = false; - $receiverAudibles = cache()->get('user-audibles'.$target->id); + cache()->put('user-echoes'.$target->id, $echoes, 3600); - if (!$receiverAudibles || !\is_array($receiverAudibles)) { - $receiverAudibles = UserAudible::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); + Chatter::dispatch('echo', $target->id, UserEchoResource::collection($echoes)); } - $receiverListening = false; + // Create audible for user if missing + $audibles = cache()->remember( + 'user-audibles'.$target->id, + 3600, + fn () => UserAudible::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get() + ); - foreach ($receiverAudibles as $se => $receiverEcho) { - if ($receiverEcho->bot_id === $this->bot->id) { - $receiverListening = true; + if ($audibles->doesntContain(fn ($audible) => $audible->bot_id == $this->bot->id)) { + UserAudible::create([ + 'user_id' => $target->id, + 'target_id' => $this->bot->id, + 'status' => false, + ]); - break; - } - } + $audibles = UserAudible::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); - if (!$receiverListening) { - $receiverPort = new UserAudible(); - $receiverPort->user_id = $target->id; - $receiverPort->bot_id = $this->bot->id; - $receiverPort->save(); - $receiverAudibles = UserAudible::with(['room', 'target', 'bot'])->where('user_id', '=', $target->id)->get(); - $receiverDirty = true; - } + cache()->put('user-audibles'.$target->id, $audibles, 3600); - if ($receiverDirty) { - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-audibles'.$target->id, $receiverAudibles, $expiresAt); - event(new Chatter('audible', $target->id, UserAudibleResource::collection($receiverAudibles))); + Chatter::dispatch('audible', $target->id, UserAudibleResource::collection($audibles)); } + // Create message if ($txt !== '') { $roomId = 0; $this->chatRepository->privateMessage($target->id, $roomId, $message, 1, $this->bot->id); diff --git a/app/Http/Controllers/API/ChatController.php b/app/Http/Controllers/API/ChatController.php index 2682051071..2871fc1c4b 100644 --- a/app/Http/Controllers/API/ChatController.php +++ b/app/Http/Controllers/API/ChatController.php @@ -148,18 +148,7 @@ public function createMessage(Request $request): \Illuminate\Contracts\Routing\R return response('error', 401); } - $botDirty = 0; - $bots = cache()->get('bots'); - - if (!$bots || !\is_array($bots) || \count($bots) < 1) { - $bots = Bot::where('active', '=', 1)->oldest('position')->get(); - $botDirty = 1; - } - - if ($botDirty == 1) { - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('bots', $bots, $expiresAt); - } + $bots = cache()->remember('bots', 3600, fn () => Bot::where('active', '=', 1)->orderByDesc('position')->get()); $which = null; $target = null; @@ -239,126 +228,51 @@ public function createMessage(Request $request): \Illuminate\Contracts\Routing\R $echo = false; if ($receiverId && $receiverId > 0) { - $senderDirty = 0; - $receiverDirty = 0; - $senderEchoes = cache()->get('user-echoes'.$userId); - $receiverEchoes = cache()->get('user-echoes'.$receiverId); - - if (!$senderEchoes || !\is_array($senderEchoes) || \count($senderEchoes) < 1) { - $senderEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', $userId)->get(); - } - - if (!$receiverEchoes || !\is_array($receiverEchoes) || \count($receiverEchoes) < 1) { - $receiverEchoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$receiverId])->get(); - } + // Create echo for both users if missing + foreach ([[$userId, $receiverId], [$receiverId, $userId]] as [$user1Id, $user2Id]) { + $echoes = cache()->remember( + 'user-echoes'.$user1Id, + 3600, + fn () => UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $user1Id)->get() + ); - $senderListening = false; - - foreach ($senderEchoes as $senderEcho) { - if ($senderEcho['target_id'] == $receiverId) { - $senderListening = true; - } - } + if ($echoes->doesntContain(fn ($echo) => $echo->target_id == $user2Id)) { + UserEcho::create([ + 'user_id' => $user1Id, + 'target_id' => $user2Id, + ]); - if (!$senderListening) { - $senderPort = new UserEcho(); - $senderPort->user_id = $userId; - $senderPort->target_id = $receiverId; - $senderPort->save(); - $senderEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', $userId)->get(); - $senderDirty = 1; - } + $echoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $user1Id)->get(); - $receiverListening = false; + cache()->put('user-echoes'.$user1Id, $echoes, 3600); - foreach ($receiverEchoes as $receiverEcho) { - if ($receiverEcho['target_id'] == $userId) { - $receiverListening = true; + Chatter::dispatch('echo', $user1Id, UserEchoResource::collection($echoes)); } } - if (!$receiverListening) { - $receiverPort = new UserEcho(); - $receiverPort->user_id = $receiverId; - $receiverPort->target_id = $userId; - $receiverPort->save(); - $receiverEchoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$receiverId])->get(); - $receiverDirty = 1; - } - - if ($senderDirty == 1) { - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-echoes'.$userId, $senderEchoes, $expiresAt); - event(new Chatter('echo', $userId, UserEchoResource::collection($senderEchoes))); - } - - if ($receiverDirty == 1) { - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-echoes'.$receiverId, $receiverEchoes, $expiresAt); - event(new Chatter('echo', $receiverId, UserEchoResource::collection($receiverEchoes))); - } + // Create audible for both users if missing + foreach ([[$userId, $receiverId], [$receiverId, $userId]] as [$user1Id, $user2Id]) { + $audibles = cache()->remember( + 'user-audibles'.$user1Id, + 3600, + fn () => UserAudible::with(['room', 'target', 'bot'])->where('user_id', '=', $user1Id)->get() + ); - $senderDirty = 0; - $receiverDirty = 0; - $senderAudibles = cache()->get('user-audibles'.$userId); - $receiverAudibles = cache()->get('user-audibles'.$receiverId); + if ($audibles->doesntContain(fn ($audible) => $audible->target_id == $user2Id)) { + UserAudible::create([ + 'user_id' => $user1Id, + 'target_id' => $user2Id, + 'status' => false, + ]); - if (!$senderAudibles || !\is_array($senderAudibles) || \count($senderAudibles) < 1) { - $senderAudibles = UserAudible::with(['room', 'target', 'bot'])->where('user_id', $userId)->get(); - } - - if (!$receiverAudibles || !\is_array($receiverAudibles) || \count($receiverAudibles) < 1) { - $receiverAudibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$receiverId])->get(); - } + $audibles = UserAudible::with(['room', 'target', 'bot'])->where('user_id', '=', $user1Id)->get(); - $senderListening = false; + cache()->put('user-audibles'.$user1Id, $audibles, 3600); - foreach ($senderAudibles as $senderEcho) { - if ($senderEcho['target_id'] == $receiverId) { - $senderListening = true; + Chatter::dispatch('audible', $user1Id, UserAudibleResource::collection($audibles)); } } - if (!$senderListening) { - $senderPort = new UserAudible(); - $senderPort->user_id = $userId; - $senderPort->target_id = $receiverId; - $senderPort->status = false; - $senderPort->save(); - $senderAudibles = UserAudible::with(['room', 'target', 'bot'])->where('user_id', $userId)->get(); - $senderDirty = 1; - } - - $receiverListening = false; - - foreach ($receiverAudibles as $receiverEcho) { - if ($receiverEcho['target_id'] == $userId) { - $receiverListening = true; - } - } - - if (!$receiverListening) { - $receiverPort = new UserAudible(); - $receiverPort->user_id = $receiverId; - $receiverPort->target_id = $userId; - $receiverPort->status = false; - $receiverPort->save(); - $receiverAudibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$receiverId])->get(); - $receiverDirty = 1; - } - - if ($senderDirty == 1) { - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-audibles'.$userId, $senderAudibles, $expiresAt); - event(new Chatter('audible', $userId, UserAudibleResource::collection($senderAudibles))); - } - - if ($receiverDirty == 1) { - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-audibles'.$receiverId, $receiverAudibles, $expiresAt); - event(new Chatter('audible', $receiverId, UserAudibleResource::collection($receiverAudibles))); - } - $roomId = 0; $ignore = $botId > 0 && $receiverId == 1 ? true : null; $save = true; @@ -528,34 +442,24 @@ public function updateUserRoom(Request $request): \Illuminate\Contracts\Routing\ $user->save(); - $senderDirty = 0; - $senderEchoes = cache()->get('user-echoes'.$user->id); + // Create echo for user if missing + $echoes = cache()->remember( + 'user-echoes'.$user->id, + 3600, + fn () => UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $user->id)->get(), + ); - if (!$senderEchoes || !\is_array($senderEchoes) || \count($senderEchoes) < 1) { - $senderEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $user->id)->get(); - } + if ($echoes->doesntContain(fn ($echo) => $echo->room_id == $room->id)) { + UserEcho::create([ + 'user_id' => $user->id, + 'room_id' => $room->id, + ]); - $senderListening = false; + $echoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $user->id)->get(); - foreach ($senderEchoes as $senderEcho) { - if ($senderEcho['room_id'] == $room->id) { - $senderListening = true; - } - } - - if (!$senderListening) { - $userEcho = new UserEcho(); - $userEcho->user_id = $user->id; - $userEcho->room_id = $room->id; - $userEcho->save(); - $senderEchoes = UserEcho::with(['room', 'target', 'bot'])->where('user_id', '=', $user->id)->get(); - $senderDirty = 1; - } + cache()->put('user-echoes'.$user->id, $echoes, 3600); - if ($senderDirty == 1) { - $expiresAt = Carbon::now()->addMinutes(60); - cache()->put('user-echoes'.$user->id, $senderEchoes, $expiresAt); - event(new Chatter('echo', $user->id, UserEchoResource::collection($senderEchoes))); + Chatter::dispatch('echo', $user->id, UserEchoResource::collection($echoes)); } return response($user); diff --git a/app/Models/UserAudible.php b/app/Models/UserAudible.php index 4e1540124c..1fbba0185f 100644 --- a/app/Models/UserAudible.php +++ b/app/Models/UserAudible.php @@ -32,6 +32,13 @@ class UserAudible extends Model { use HasFactory; + /** + * The attributes that aren't mass assignable. + * + * @var string[] + */ + protected $guarded = []; + /** * Belongs To A User. * diff --git a/app/Models/UserEcho.php b/app/Models/UserEcho.php index 826225ca57..d868b61d3a 100644 --- a/app/Models/UserEcho.php +++ b/app/Models/UserEcho.php @@ -31,6 +31,13 @@ class UserEcho extends Model { use HasFactory; + /** + * The attributes that aren't mass assignable. + * + * @var string[] + */ + protected $guarded = []; + /** * Belongs To A User. * diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 33e4d833a0..38da49b94d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -520,11 +520,6 @@ parameters: count: 2 path: app/Http/Controllers/API/ChatController.php - - - message: "#^Comparison operation \"\\<\" between int\\<1, max\\> and 1 is always false\\.$#" - count: 6 - path: app/Http/Controllers/API/ChatController.php - - message: "#^Method App\\\\Http\\\\Controllers\\\\API\\\\ChatController\\:\\:botMessages\\(\\) has parameter \\$botId with no type specified\\.$#" count: 1 @@ -555,11 +550,6 @@ parameters: count: 3 path: app/Http/Controllers/API/ChatController.php - - - message: "#^Property App\\\\Models\\\\UserAudible\\:\\:\\$status \\(int\\) does not accept false\\.$#" - count: 2 - path: app/Http/Controllers/API/ChatController.php - - message: "#^Property App\\\\Models\\\\UserAudible\\:\\:\\$status \\(int\\) does not accept true\\.$#" count: 1 From 4c5cfc2a46c0818d4d7ba54b1d52622e1402de12 Mon Sep 17 00:00:00 2001 From: HDVinnie Date: Wed, 1 May 2024 15:21:34 -0400 Subject: [PATCH 6/6] update: unit3d config --- config/unit3d.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/unit3d.php b/config/unit3d.php index ac2b2e3327..0f9a5f929c 100755 --- a/config/unit3d.php +++ b/config/unit3d.php @@ -21,7 +21,7 @@ | */ - 'powered-by' => 'Powered By UNIT3D Community Edition v8.1.2', + 'powered-by' => 'Powered By UNIT3D Community Edition v8.1.3', /* |-------------------------------------------------------------------------- @@ -43,7 +43,7 @@ | */ - 'version' => 'v8.1.2', + 'version' => 'v8.1.3', /* |--------------------------------------------------------------------------