diff --git a/app/Bot.php b/app/Bot.php new file mode 100644 index 0000000000..3eee223ff4 --- /dev/null +++ b/app/Bot.php @@ -0,0 +1,49 @@ + 'string', + ]; + + /** + * The attributes that should be mutated to dates. + * + * @var array + */ + protected $dates = ['deleted_at']; +} diff --git a/app/BotTransaction.php b/app/BotTransaction.php new file mode 100644 index 0000000000..8c8457bc1f --- /dev/null +++ b/app/BotTransaction.php @@ -0,0 +1,79 @@ +belongsTo(User::class)->withDefault([ + 'username' => 'System', + 'id' => '1', + ]); + } + + /** + * Belongs To A Bot. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + + // Bad name to not conflict with sender (not sender_id) + + public function bot() + { + return $this->belongsTo(Bot::class)->withDefault([ + 'username' => 'System', + 'id' => '1', + ]); + } + + /** + * Get the Bot transaction type answer as string. + * + * @return int + */ + public function forHumans() + { + if ($this->type == 'bon') { + return 'BON'; + } + + return 'Unknown'; + } +} diff --git a/app/Bots/CasinoBot.php b/app/Bots/CasinoBot.php new file mode 100644 index 0000000000..3e5ddac993 --- /dev/null +++ b/app/Bots/CasinoBot.php @@ -0,0 +1,279 @@ +firstOrFail(); + $this->chat = $chat; + $this->bot = $bot; + $this->expiresAt = Carbon::now()->addMinutes(60); + $this->current = today(); + } + + /** + * Replace Vars. + */ + public function replaceVars($output) + { + $output = str_replace('{me}', $this->bot->name, $output); + $output = str_replace('{command}', $this->bot->command, $output); + if (strstr($output, '{bots}')) { + $bot_help = ''; + $bots = Bot::where('active', '=', 1)->where('id', '!=', $this->bot->id)->orderBy('position', 'asc')->get(); + foreach ($bots as $bot) { + $bot_help .= '( ! | / | @)'.$bot->command.' help triggers help file for '.$bot->name."\n"; + } + $output = str_replace('{bots}', $bot_help, $output); + } + + return $output; + } + + /** + * Send Bot Donation. + */ + public function putDonate($amount = 0, $note = '') + { + $output = implode(' ', $note); + $v = validator(['bot_id' => $this->bot->id, 'amount'=> $amount, 'note'=> $output], [ + 'bot_id' => 'required|exists:bots,id|max:999', + 'amount' => "required|numeric|min:1|max:{$this->target->seedbonus}", + 'note' => 'required|string', + ]); + if ($v->passes()) { + $value = $amount; + $this->bot->seedbonus += $value; + $this->bot->save(); + + $this->target->seedbonus -= $value; + $this->target->save(); + + $transaction = new BotTransaction(); + $transaction->type = 'bon'; + $transaction->cost = $value; + $transaction->user_id = $this->target->id; + $transaction->bot_id = $this->bot->id; + $transaction->to_bot = 1; + $transaction->comment = $output; + $transaction->save(); + + $donations = BotTransaction::with('user', 'bot')->where('bot_id', '=', $this->bot->id)->where('to_bot', '=', 1)->latest()->limit(10)->get(); + cache()->put('casinobot-donations', $donations, $this->expiresAt); + + return 'Your donation to '.$this->bot->name.' for '.$amount.' BON has been sent!'; + } + + return 'Your donation to '.$output.' could not be sent.'; + } + + /** + * Get Bot Donations. + */ + public function getDonations($duration = 'default') + { + $donations = cache()->get('casinobot-donations'); + if (! $donations || $donations == null) { + $donations = BotTransaction::with('user', 'bot')->where('bot_id', '=', $this->bot->id)->where('to_bot', '=', 1)->latest()->limit(10)->get(); + cache()->put('casinobot-donations', $donations, $this->expiresAt); + } + $donation_dump = ''; + $i = 1; + foreach ($donations as $donation) { + $donation_dump .= '#'.$i.'. '.$donation->user->username.' sent '.$donation->cost.' '.$donation->forHumans().' with note: '.$donation->comment.".\n"; + $i++; + } + + return "The Most Recent Donations To Me Are As Follows:\n\n".trim($donation_dump); + } + + /** + * Get Help. + */ + public function getHelp() + { + return $this->replaceVars($this->bot->help); + } + + /** + * Process Message. + */ + public function process($type, User $target, $message = '', $targeted = 0) + { + $this->target = $target; + if ($type == 'message') { + $x = 0; + $y = 1; + $z = 2; + } else { + $x = 1; + $y = 2; + $z = 3; + } + + if ($message == '') { + $log = ''; + } else { + $log = 'All '.$this->bot->name.' commands must be a private message or begin with /'.$this->bot->command.' or !'.$this->bot->command.'. Need help? Type /'.$this->bot->command.' help and you shall be helped.'; + } + $command = @explode(' ', $message); + + $wildcard = null; + $params = null; + if (array_key_exists($y, $command)) { + $params = $command[$y]; + } + + if ($params != null) { + $clone = $command; + array_shift($clone); + array_shift($clone); + array_shift($clone); + $wildcard = $clone; + } + + if (array_key_exists($x, $command)) { + if ($command[$x] == 'donations') { + $log = $this->getDonations($params); + } + if ($command[$x] == 'donate') { + $log = $this->putDonate($params, $wildcard); + } + } + $this->targeted = $targeted; + $this->type = $type; + $this->message = $message; + $this->log = $log; + + return $this->pm(); + } + + /** + * Output Message. + */ + public function pm() + { + $type = $this->type; + $target = $this->target; + $txt = $this->log; + $message = $this->message; + $targeted = $this->targeted; + + if ($targeted) { + // future holder + } + + if ($type == 'message' || $type == 'private') { + $receiver_dirty = 0; + $receiver_echoes = cache()->get('user-echoes'.$target->id); + if (! $receiver_echoes || ! is_array($receiver_echoes) || count($receiver_echoes) < 1) { + $receiver_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + } + $receiver_listening = false; + foreach ($receiver_echoes as $se => $receiver_echo) { + if ($receiver_echo['bot_id'] == $this->bot->id) { + $receiver_listening = true; + } + } + if (! $receiver_listening) { + $receiver_port = new UserEcho(); + $receiver_port->user_id = $target->id; + $receiver_port->bot_id = $this->bot->id; + $receiver_port->save(); + $receiver_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + $receiver_dirty = 1; + } + if ($receiver_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-echoes'.$target->id, $receiver_echoes, $expiresAt); + event(new Chatter('echo', $target->id, UserEchoResource::collection($receiver_echoes))); + } + $receiver_dirty = 0; + $receiver_audibles = cache()->get('user-audibles'.$target->id); + if (! $receiver_audibles || ! is_array($receiver_audibles) || count($receiver_audibles) < 1) { + $receiver_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + } + $receiver_listening = false; + foreach ($receiver_audibles as $se => $receiver_echo) { + if ($receiver_echo['bot_id'] == $this->bot->id) { + $receiver_listening = true; + } + } + if (! $receiver_listening) { + $receiver_port = new UserAudible(); + $receiver_port->user_id = $target->id; + $receiver_port->bot_id = $this->bot->id; + $receiver_port->save(); + $receiver_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + $receiver_dirty = 1; + } + if ($receiver_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-audibles'.$target->id, $receiver_audibles, $expiresAt); + event(new Chatter('audible', $target->id, UserAudibleResource::collection($receiver_audibles))); + } + + if ($txt != '') { + $room_id = 0; + $message = $this->chat->privateMessage($target->id, $room_id, $message, 1, $this->bot->id); + $message = $this->chat->privateMessage(1, $room_id, $txt, $target->id, $this->bot->id); + } + + return response('success', 200); + } elseif ($type == 'echo') { + if ($txt != '') { + $room_id = 0; + $message = $this->chat->botMessage($this->bot->id, $room_id, $txt, $target->id); + } + + return response('success', 200); + } elseif ($type == 'public') { + if ($txt != '') { + $dumproom = $this->chat->message($target->id, $target->chatroom->id, $message, null, null); + $dumproom = $this->chat->message(1, $target->chatroom->id, $txt, null, $this->bot->id); + } + + return response('success', 200); + } + + return true; + } +} diff --git a/app/Bots/NerdBot.php b/app/Bots/NerdBot.php new file mode 100644 index 0000000000..26cb2567c9 --- /dev/null +++ b/app/Bots/NerdBot.php @@ -0,0 +1,504 @@ +firstOrFail(); + $this->chat = $chat; + $this->bot = $bot; + $this->expiresAt = Carbon::now()->addMinutes(60); + $this->current = today(); + } + + /** + * Replace Vars. + */ + public function replaceVars($output) + { + $output = str_replace('{me}', $this->bot->name, $output); + $output = str_replace('{command}', $this->bot->command, $output); + if (strstr($output, '{bots}')) { + $bot_help = ''; + $bots = Bot::where('active', '=', 1)->where('id', '!=', $this->bot->id)->orderBy('position', 'asc')->get(); + foreach ($bots as $bot) { + $bot_help .= '( ! | / | @)'.$bot->command.' help triggers help file for '.$bot->name."\n"; + } + $output = str_replace('{bots}', $bot_help, $output); + } + + return $output; + } + + /** + * Get Banker. + */ + public function getBanker($duration = 'default') + { + $banker = cache()->get('nerdbot-banker'); + if (! $banker || $banker == null) { + $banker = User::latest('seedbonus')->first(); + cache()->put('nerdbot-banker', $banker, $this->expiresAt); + } + + return "Currently [url=/{$banker->slug}.{$banker->id}]{$banker->username}[/url] Is The Top BON Holder On ".config('other.title').'!'; + } + + /** + * Get Snatched. + */ + public function getSnatched($duration = 'default') + { + $snatched = cache()->get('nerdbot-snatched'); + if (! $snatched || $snatched == null) { + $snatched = Torrent::latest('times_completed')->first(); + cache()->put('nerdbot-snatched', $snatched, $this->expiresAt); + } + + return "Currently [url=/torrents/{$snatched->slug}.{$snatched->id}]{$snatched->name}[/url] Is The Most Snatched Torrent On ".config('other.title').'!'; + } + + /** + * Get Leeched. + */ + public function getLeeched($duration = 'default') + { + $leeched = cache()->get('nerdbot-leeched'); + if (! $leeched || $leeched == null) { + $leeched = Torrent::latest('leechers')->first(); + cache()->put('nerdbot-leeched', $leeched, $this->expiresAt); + } + + return "Currently [url=/torrents/{$leeched->slug}.{$leeched->id}]{$leeched->name}[/url] Is The Most Leeched Torrent On ".config('other.title').'!'; + } + + /** + * Get Seeded. + */ + public function getSeeded($duration = 'default') + { + $seeded = cache()->get('nerdbot-seeded'); + if (! $seeded || $seeded == null) { + $seeded = Torrent::latest('seeders')->first(); + cache()->put('nerdbot-seeded', $seeded, $this->expiresAt); + } + + return "Currently [url=/torrents/{$seeded->slug}.{$seeded->id}]{$seeded->name}[/url] Is The Most Seeded Torrent On ".config('other.title').'!'; + } + + /** + * Get FL. + */ + public function getFreeleech($duration = 'default') + { + $fl = cache()->get('nerdbot-fl'); + if (! $fl || $fl == null) { + $fl = Torrent::where('free', '=', 1)->count(); + cache()->put('nerdbot-fl', $fl, $this->expiresAt); + } + + return "There Are Currently {$fl} Freeleech Torrents On ".config('other.title').'!'; + } + + /** + * Get DU. + */ + public function getDoubleUpload($duration = 'default') + { + $du = cache()->get('nerdbot-doubleup'); + if (! $du || $du == null) { + $du = Torrent::where('doubleup', '=', 1)->count(); + cache()->put('nerdbot-doubleup', $du, $this->expiresAt); + } + + return "There Are Currently {$du} Double Upload Torrents On ".config('other.title').'!'; + } + + /** + * Get Peers. + */ + public function getPeers($duration = 'default') + { + $peers = cache()->get('nerdbot-peers'); + if (! $peers || $peers == null) { + $peers = Peer::count(); + cache()->put('nerdbot-peers', $peers, $this->expiresAt); + } + + return "Currently There Are {$peers} Peers On ".config('other.title').'!'; + } + + /** + * Get Bans. + */ + public function getBans($duration = 'default') + { + $bans = cache()->get('nerdbot-bans'); + if (! $bans || $bans == null) { + $bans = Ban::whereNull('unban_reason')->whereNull('removed_at')->where('created_at', '>', $this->current->subDay())->count(); + cache()->put('nerdbot-bans', $bans, $this->expiresAt); + } + + return "In The Last 24 Hours {$bans} Users Have Been Banned From ".config('other.title').'!'; + } + + /** + * Get Warnings. + */ + public function getWarnings($duration = 'default') + { + $warnings = cache()->get('nerdbot-warnings'); + if (! $warnings || $warnings == null) { + $warnings = Warning::where('created_at', '>', $this->current->subDay())->count(); + cache()->put('nerdbot-warnings', $warnings, $this->expiresAt); + } + + return "In The Last 24 Hours {$warnings} Hit and Run Warnings Have Been Issued On ".config('other.title').'!'; + } + + /** + * Get Uploads. + */ + public function getUploads($duration = 'default') + { + $uploads = cache()->get('nerdbot-uploads'); + if (! $uploads || $uploads == null) { + $uploads = Torrent::where('created_at', '>', $this->current->subDay())->count(); + cache()->put('nerdbot-uploads', $uploads, $this->expiresAt); + } + + return "In The Last 24 Hours {$uploads} Torrents Have Been Uploaded To ".config('other.title').'!'; + } + + /** + * Get Logins. + */ + public function getLogins($duration = 'default') + { + $logins = cache()->get('nerdbot-logins'); + if (! $logins || $logins == null) { + $logins = User::whereNotNull('last_login')->where('last_login', '>', $this->current->subDay())->count(); + cache()->put('nerdbot-logins', $logins, $this->expiresAt); + } + + return "In The Last 24 Hours {$logins} Unique Users Have Logged Into ".config('other.title').'!'; + } + + /** + * Get Registrations. + */ + public function getRegistrations($duration = 'default') + { + $registrations = cache()->get('nerdbot-users'); + if (! $registrations || $registrations == null) { + $users = User::where('created_at', '>', $this->current->subDay())->count(); + cache()->put('nerdbot-users', $users, $this->expiresAt); + } + + return "In The Last 24 Hours {$users} Users Have Registered To ".config('other.title').'!'; + } + + /** + * Get Bot Donations. + */ + public function getDonations($duration = 'default') + { + $donations = cache()->get('nerdbot-donations'); + if (! $donations || $donations == null) { + $donations = BotTransaction::with('user', 'bot')->where('to_bot', '=', 1)->latest()->limit(10)->get(); + cache()->put('nerdbot-donations', $donations, $this->expiresAt); + } + $donation_dump = ''; + $i = 1; + foreach ($donations as $donation) { + $donation_dump .= '#'.$i.'. '.$donation->user->username.' sent '.$donation->bot->name.' '.$donation->cost.' '.$donation->forHumans().".\n"; + $i++; + } + + return "The Most Recent Donations To All Bots Are As Follows:\n\n".trim($donation_dump); + } + + /** + * Get Help. + */ + public function getHelp() + { + return $this->replaceVars($this->bot->help); + } + + /** + * Get King. + */ + public function getKing() + { + return config('other.title').' Is King!'; + } + + /** + * Send Bot Donation. + */ + public function putDonate($amount = 0, $note = '') + { + $output = implode(' ', $note); + $v = validator(['bot_id' => $this->bot->id, 'amount'=> $amount, 'note'=> $output], [ + 'bot_id' => 'required|exists:bots,id|max:999', + 'amount' => "required|numeric|min:1|max:{$this->target->seedbonus}", + 'note' => 'required|string', + ]); + if ($v->passes()) { + $value = $amount; + $this->bot->seedbonus += $value; + $this->bot->save(); + + $this->target->seedbonus -= $value; + $this->target->save(); + + $transaction = new BotTransaction(); + $transaction->type = 'bon'; + $transaction->cost = $value; + $transaction->user_id = $this->target->id; + $transaction->bot_id = $this->bot->id; + $transaction->to_bot = 1; + $transaction->comment = $output; + $transaction->save(); + + $donations = BotTransaction::with('user', 'bot')->where('bot_id', '=', $this->bot->id)->where('to_bot', '=', 1)->latest()->limit(10)->get(); + cache()->put('casinobot-donations', $donations, $this->expiresAt); + + return 'Your donation to '.$this->bot->name.' for '.$amount.' BON has been sent!'; + } + + return 'Your donation to '.$output.' could not be sent.'; + } + + /** + * Process Message. + */ + public function process($type, User $target, $message = '', $targeted = 0) + { + $this->target = $target; + if ($type == 'message') { + $x = 0; + $y = 1; + $z = 2; + } else { + $x = 1; + $y = 2; + $z = 3; + } + + if ($message == '') { + $log = ''; + } else { + $log = 'All '.$this->bot->name.' commands must be a private message or begin with /'.$this->bot->command.' or !'.$this->bot->command.'. Need help? Type /'.$this->bot->command.' help and you shall be helped.'; + } + $command = @explode(' ', $message); + + $wildcard = null; + $params = null; + if (array_key_exists($y, $command)) { + $params = $command[$y]; + } + + if ($params != null) { + $clone = $command; + array_shift($clone); + array_shift($clone); + array_shift($clone); + $wildcard = $clone; + } + + if (array_key_exists($x, $command)) { + if ($command[$x] == 'banker') { + $log = $this->getBanker($params); + } + if ($command[$x] == 'bankers') { + $log = $this->getBankers($params); + } + if ($command[$x] == 'bans') { + $log = $this->getBans($params); + } + if ($command[$x] == 'donations') { + $log = $this->getDonations($params); + } + if ($command[$x] == 'donate') { + $log = $this->putDonate($params, $wildcard); + } + if ($command[$x] == 'doubleupload') { + $log = $this->getDoubleUpload($params); + } + if ($command[$x] == 'freeleech') { + $log = $this->getFreeleech($params); + } + if ($command[$x] == 'help') { + $log = $this->getHelp(); + } + if ($command[$x] == 'king') { + $log = $this->getKing(); + } + if ($command[$x] == 'logins') { + $log = $this->getLogins($params); + } + if ($command[$x] == 'peers') { + $log = $this->getPeers($params); + } + if ($command[$x] == 'registrations') { + $log = $this->getRegistrations($params); + } + if ($command[$x] == 'uploads') { + $log = $this->getUploads($params); + } + if ($command[$x] == 'warnings') { + $log = $this->getWarnings($params); + } + if ($command[$x] == 'seeded') { + $log = $this->getSeeded($params); + } + if ($command[$x] == 'leeched') { + $log = $this->getLeeched($params); + } + if ($command[$x] == 'snatched') { + $log = $this->getSnatched($params); + } + } + $this->targeted = $targeted; + $this->type = $type; + $this->message = $message; + $this->log = $log; + + return $this->pm(); + } + + /** + * Output Message. + */ + public function pm() + { + $type = $this->type; + $target = $this->target; + $txt = $this->log; + $message = $this->message; + $targeted = $this->targeted; + + if ($targeted) { + // future holder + } + + if ($type == 'message' || $type == 'private') { + $receiver_dirty = 0; + $receiver_echoes = cache()->get('user-echoes'.$target->id); + if (! $receiver_echoes || ! is_array($receiver_echoes) || count($receiver_echoes) < 1) { + $receiver_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + } + $receiver_listening = false; + foreach ($receiver_echoes as $se => $receiver_echo) { + if ($receiver_echo['bot_id'] == $this->bot->id) { + $receiver_listening = true; + } + } + if (! $receiver_listening) { + $receiver_port = new UserEcho(); + $receiver_port->user_id = $target->id; + $receiver_port->bot_id = $this->bot->id; + $receiver_port->save(); + $receiver_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + $receiver_dirty = 1; + } + if ($receiver_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-echoes'.$target->id, $receiver_echoes, $expiresAt); + event(new Chatter('echo', $target->id, UserEchoResource::collection($receiver_echoes))); + } + $receiver_dirty = 0; + $receiver_audibles = cache()->get('user-audibles'.$target->id); + if (! $receiver_audibles || ! is_array($receiver_audibles) || count($receiver_audibles) < 1) { + $receiver_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + } + $receiver_listening = false; + foreach ($receiver_audibles as $se => $receiver_echo) { + if ($receiver_echo['bot_id'] == $this->bot->id) { + $receiver_listening = true; + } + } + if (! $receiver_listening) { + $receiver_port = new UserAudible(); + $receiver_port->user_id = $target->id; + $receiver_port->bot_id = $this->bot->id; + $receiver_port->save(); + $receiver_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + $receiver_dirty = 1; + } + if ($receiver_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-audibles'.$target->id, $receiver_audibles, $expiresAt); + event(new Chatter('audible', $target->id, UserAudibleResource::collection($receiver_audibles))); + } + + if ($txt != '') { + $room_id = 0; + $message = $this->chat->privateMessage($target->id, $room_id, $message, 1, $this->bot->id); + $message = $this->chat->privateMessage(1, $room_id, $txt, $target->id, $this->bot->id); + } + + return response('success', 200); + } elseif ($type == 'echo') { + if ($txt != '') { + $room_id = 0; + $message = $this->chat->botMessage($this->bot->id, $room_id, $txt, $target->id); + } + + return response('success', 200); + } elseif ($type == 'public') { + if ($txt != '') { + $dumproom = $this->chat->message($target->id, $target->chatroom->id, $message, null, null); + $dumproom = $this->chat->message(1, $target->chatroom->id, $txt, null, $this->bot->id); + } + + return response('success', 200); + } + + return true; + } +} diff --git a/app/Bots/SystemBot.php b/app/Bots/SystemBot.php new file mode 100644 index 0000000000..41444b496b --- /dev/null +++ b/app/Bots/SystemBot.php @@ -0,0 +1,262 @@ +firstOrFail(); + $this->chat = $chat; + $this->bot = $bot; + } + + /** + * Replace Vars. + */ + public function replaceVars($output) + { + $output = str_replace('{me}', $this->bot->name, $output); + $output = str_replace('{command}', $this->bot->command, $output); + if (strstr($output, '{bots}')) { + $bot_help = ''; + $bots = Bot::where('active', '=', 1)->where('id', '!=', $this->bot->id)->orderBy('position', 'asc')->get(); + foreach ($bots as $bot) { + $bot_help .= '( ! | / | @)'.$bot->command.' help triggers help file for '.$bot->name."\n"; + } + $output = str_replace('{bots}', $bot_help, $output); + } + + return $output; + } + + /** + * Get Help. + */ + public function getHelp() + { + return $this->replaceVars($this->bot->help); + } + + /** + * Send Gift. + */ + public function putGift($receiver = '', $amount = 0, $note = '') + { + $output = implode(' ', $note); + $v = validator(['receiver' => $receiver, 'amount'=> $amount, 'note'=> $output], [ + 'receiver' => 'required|string|exists:users,username', + 'amount' => "required|numeric|min:1|max:{$this->target->seedbonus}", + 'note' => 'required|string', + ]); + if ($v->passes()) { + $recipient = User::where('username', 'LIKE', $receiver)->first(); + + if (! $recipient || $recipient->id == $this->target->id) { + return 'Your BON gift could not be sent.'; + } + + $value = $amount; + $recipient->seedbonus += $value; + $recipient->save(); + + $this->target->seedbonus -= $value; + $this->target->save(); + + $transaction = new BonTransactions(); + $transaction->itemID = 0; + $transaction->name = 'gift'; + $transaction->cost = $value; + $transaction->sender = $this->target->id; + $transaction->receiver = $recipient->id; + $transaction->comment = $output; + $transaction->torrent_id = null; + $transaction->save(); + + if ($this->target->id != $recipient->id) { + if ($recipient->acceptsNotification($this->target, $recipient, 'bon', 'show_bon_gift')) { + $recipient->notify(new NewBon('gift', $this->target->username, $transaction)); + } + } + + $profile_url = hrefProfile($this->target); + $recipient_url = hrefProfile($recipient); + + $this->chat->systemMessage( + "[url={$profile_url}]{$this->target->username}[/url] has gifted {$value} BON to [url={$recipient_url}]{$recipient->username}[/url]" + ); + + return 'Your gift to '.$recipient->username.' for '.$amount.' BON has been sent!'; + } + + return 'Your BON gift could not be sent.'; + } + + /** + * Process Message. + */ + public function process($type, User $target, $message = '', $targeted = 0) + { + $this->target = $target; + if ($type == 'message') { + $x = 0; + } else { + $x = 1; + } + + $y = $x + 1; + $z = $y + 1; + + if ($message == '') { + $log = ''; + } else { + $log = 'All '.$this->bot->name.' commands must be a private message or begin with /'.$this->bot->command.' or !'.$this->bot->command.'. Need help? Type /'.$this->bot->command.' help and you shall be helped.'; + } + $command = @explode(' ', $message); + if (array_key_exists($x, $command)) { + if ($command[$x] == 'gift' && array_key_exists($y, $command) && array_key_exists($z, $command) && array_key_exists($z + 1, $command)) { + $clone = $command; + array_shift($clone); + array_shift($clone); + array_shift($clone); + array_shift($clone); + $log = $this->putGift($command[$y], $command[$z], $clone); + } + if ($command[$x] == 'help') { + $log = $this->getHelp(); + } + } + $this->targeted = $targeted; + $this->type = $type; + $this->message = $message; + $this->log = $log; + + return $this->pm(); + } + + /** + * Output Message. + */ + public function pm() + { + $type = $this->type; + $target = $this->target; + $txt = $this->log; + $message = $this->message; + $targeted = $this->targeted; + + if ($targeted) { + // future holder + } + + if ($type == 'message' || $type == 'private') { + $receiver_dirty = 0; + $receiver_echoes = cache()->get('user-echoes'.$target->id); + if (! $receiver_echoes || ! is_array($receiver_echoes) || count($receiver_echoes) < 1) { + $receiver_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + } + $receiver_listening = false; + foreach ($receiver_echoes as $se => $receiver_echo) { + if ($receiver_echo['bot_id'] == $this->bot->id) { + $receiver_listening = true; + } + } + if (! $receiver_listening) { + $receiver_port = new UserEcho(); + $receiver_port->user_id = $target->id; + $receiver_port->bot_id = $this->bot->id; + $receiver_port->save(); + $receiver_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + $receiver_dirty = 1; + } + if ($receiver_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-echoes'.$target->id, $receiver_echoes, $expiresAt); + event(new Chatter('echo', $target->id, UserEchoResource::collection($receiver_echoes))); + } + $receiver_dirty = 0; + $receiver_audibles = cache()->get('user-audibles'.$target->id); + if (! $receiver_audibles || ! is_array($receiver_audibles) || count($receiver_audibles) < 1) { + $receiver_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + } + $receiver_listening = false; + foreach ($receiver_audibles as $se => $receiver_echo) { + if ($receiver_echo['bot_id'] == $this->bot->id) { + $receiver_listening = true; + } + } + if (! $receiver_listening) { + $receiver_port = new UserAudible(); + $receiver_port->user_id = $target->id; + $receiver_port->bot_id = $this->bot->id; + $receiver_port->save(); + $receiver_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$target->id])->get(); + $receiver_dirty = 1; + } + if ($receiver_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-audibles'.$target->id, $receiver_audibles, $expiresAt); + event(new Chatter('audible', $target->id, UserAudibleResource::collection($receiver_audibles))); + } + + if ($txt != '') { + $room_id = 0; + $message = $this->chat->privateMessage($target->id, $room_id, $message, 1, $this->bot->id); + $message = $this->chat->privateMessage(1, $room_id, $txt, $target->id, $this->bot->id); + } + + return response('success', 200); + } elseif ($type == 'echo') { + if ($txt != '') { + $room_id = 0; + $message = $this->chat->botMessage($this->bot->id, $room_id, $txt, $target->id); + } + + return response('success', 200); + } elseif ($type == 'public') { + if ($txt != '') { + $dumproom = $this->chat->message($target->id, $target->chatroom->id, $message, null, null); + $dumproom = $this->chat->message(1, $target->chatroom->id, $txt, null, $this->bot->id); + } + + return response('success', 200); + } + + return true; + } +} diff --git a/app/ChatStatus.php b/app/ChatStatus.php index 7057f91685..ed2fa428cc 100644 --- a/app/ChatStatus.php +++ b/app/ChatStatus.php @@ -17,6 +17,13 @@ class ChatStatus extends Model { + /** + * The Database Table Used By The Model. + * + * @var string + */ + protected $table = 'chat_statuses'; + /** * A Status Has Many Users. * @@ -24,6 +31,6 @@ class ChatStatus extends Model */ public function users() { - return $this->hasMany(User::class, 'chat_status_id'); + return $this->hasMany(User::class, 'chat_status_id', 'id'); } } diff --git a/app/Console/Commands/AutoNerdStat.php b/app/Console/Commands/AutoNerdStat.php index 835935f029..42073b9662 100644 --- a/app/Console/Commands/AutoNerdStat.php +++ b/app/Console/Commands/AutoNerdStat.php @@ -18,6 +18,7 @@ use App\User; use App\Torrent; use App\Warning; +use Carbon\Carbon; use Illuminate\Console\Command; use App\Repositories\ChatRepository; @@ -57,34 +58,61 @@ public function __construct(ChatRepository $chat) public function handle() { if (config('chat.nerd_bot') == true) { + $expiresAt = Carbon::now()->addMinutes(60); + // Current Timestamp $current = today(); + // Site Birthday $bday = config('other.birthdate'); + // Logins Count Last 24hours $logins = User::whereNotNull('last_login')->where('last_login', '>', $current->subDay())->count(); + cache()->put('nerdbot-logins', $logins, $expiresAt); + // Torrents Uploaded Count Last 24hours $uploads = Torrent::where('created_at', '>', $current->subDay())->count(); + cache()->put('nerdbot-uploads', $uploads, $expiresAt); + // New Users Count Last 24hours $users = User::where('created_at', '>', $current->subDay())->count(); + cache()->put('nerdbot-users', $users, $expiresAt); + // Top Banker $banker = User::latest('seedbonus')->first(); + cache()->put('nerdbot-banker', $banker, $expiresAt); + // Most Snatched Torrent $snatched = Torrent::latest('times_completed')->first(); + cache()->put('nerdbot-snatched', $snatched, $expiresAt); + // Most Seeded Torrent - $seeders = Torrent::latest('seeders')->first(); + $seeded = Torrent::latest('seeders')->first(); + cache()->put('nerdbot-seeded', $seeded, $expiresAt); + // Most Leeched Torrent - $leechers = Torrent::latest('leechers')->first(); + $leeched = Torrent::latest('leechers')->first(); + cache()->put('nerdbot-leeched', $leeched, $expiresAt); + // FL Torrents $fl = Torrent::where('free', '=', 1)->count(); + cache()->put('nerdbot-fl', $fl, $expiresAt); + // DU Torrents $du = Torrent::where('doubleup', '=', 1)->count(); + cache()->put('nerdbot-doubleup', $du, $expiresAt); + // Peers Count $peers = Peer::count(); + cache()->put('nerdbot-peers', $peers, $expiresAt); + // New User Bans Count Last 24hours $bans = Ban::whereNull('unban_reason')->whereNull('removed_at')->where('created_at', '>', $current->subDay())->count(); + cache()->put('nerdbot-bans', $bans, $expiresAt); + // Hit and Run Warning Issued In Last 24hours $warnings = Warning::where('created_at', '>', $current->subDay())->count(); + cache()->put('nerdbot-warnings', $warnings, $expiresAt); // Select A Random Nerd Stat $statArray = [ @@ -92,21 +120,21 @@ public function handle() "In The Last 24 Hours {$uploads} Torrents Have Been Uploaded To ".config('other.title').'!', "In The Last 24 Hours {$users} Users Have Registered To ".config('other.title').'!', "There Are Currently {$fl} Freeleech Torrents On ".config('other.title').'!', - "There Are Currently {$du} DoubleUpload Torrents On ".config('other.title').'!', - "Currently {$seeders->name} Is The Best Seeded Torrent On ".config('other.title').'!', - "Currently {$leechers->name} Is The Most Leeched Torrent On ".config('other.title').'!', + "There Are Currently {$du} Double Upload Torrents On ".config('other.title').'!', + "Currently {$seeded->name} Is The Best Seeded Torrent On ".config('other.title').'!', + "Currently {$leeched->name} Is The Most Leeched Torrent On ".config('other.title').'!', "Currently {$snatched->name} Is The Most Snatched Torrent On ".config('other.title').'!', "Currently {$banker->username} Is The Top BON Holder On ".config('other.title').'!', - "Currently There Is {$peers} Peers On ".config('other.title').'!', + "Currently There Are {$peers} Peers On ".config('other.title').'!', "In The Last 24 Hours {$bans} Users Have Been Banned From ".config('other.title').'!', - "In The Last 24 Hours {$warnings} Hit and Run Warnings Have Been Issued On ".config('other.title').'!', + "In The Last 24 Hours {$warnings} Hit and Run Warnings Have Been Issued On ".config('other.title').'!', config('other.title')." Birthday Is {$bday}!", config('other.title').' Is King!', ]; $selected = mt_rand(0, count($statArray) - 1); // Auto Shout Nerd Stat - $this->chat->systemMessage(":nerd: [b][color=#c09fe0]NerdBot[/color][/b] : {$statArray[$selected]}"); + $this->chat->systemMessage("{$statArray[$selected]}", 2); } } } diff --git a/app/Events/Chatter.php b/app/Events/Chatter.php new file mode 100644 index 0000000000..476a721784 --- /dev/null +++ b/app/Events/Chatter.php @@ -0,0 +1,73 @@ +type = $type; + if ($type == 'echo') { + $this->echoes = $payload; + } elseif ($type == 'audible') { + $this->audibles = $payload; + } elseif ($type == 'new.message') { + $this->message = $payload; + } elseif ($type == 'new.bot') { + $this->message = $payload; + } elseif ($type == 'new.ping') { + $this->ping = $payload; + } + $this->target = $target; + } + + /** + * Get the channels the event should broadcast on. + * + * @return Channel|array + */ + public function broadcastOn() + { + // $this->dontBroadcastToCurrentUser(); + + return new PrivateChannel('chatter.'.$this->target); + } +} diff --git a/app/Events/MessageEdited.php b/app/Events/MessageEdited.php index 72afca8746..c01c7331f5 100644 --- a/app/Events/MessageEdited.php +++ b/app/Events/MessageEdited.php @@ -40,7 +40,7 @@ class MessageEdited implements ShouldBroadcastNow */ public function __construct(Message $message) { - $message = Message::with(['user.group', 'user.chatStatus'])->find($message->id); + $message = Message::with(['bot', 'user.group', 'user.chatStatus'])->find($message->id); $this->message = new ChatMessageResource($message); } diff --git a/app/Events/MessageSent.php b/app/Events/MessageSent.php index 1ec82a8595..c722963a68 100644 --- a/app/Events/MessageSent.php +++ b/app/Events/MessageSent.php @@ -40,7 +40,14 @@ class MessageSent implements ShouldBroadcastNow */ public function __construct(Message $message) { - $message = Message::with(['user.group', 'user.chatStatus'])->find($message->id); + $message = Message::with([ + 'bot', + 'user.group', + 'user.chatStatus', + 'receiver.group', + 'receiver.chatStatus', + ])->find($message->id); + $this->message = new ChatMessageResource($message); } diff --git a/app/Events/Ping.php b/app/Events/Ping.php new file mode 100644 index 0000000000..901847f288 --- /dev/null +++ b/app/Events/Ping.php @@ -0,0 +1,57 @@ +room = $room; + $this->ping = ['type' => 'room', 'id' => $id]; + } + + /** + * Get the channels the event should broadcast on. + * + * @return Channel|array + */ + public function broadcastOn() + { + // $this->dontBroadcastToCurrentUser(); + + return new PresenceChannel('chatroom.'.$this->room); + } + + public function broadcastAs() + { + return 'new.ping'; + } +} diff --git a/app/Http/Controllers/API/ChatController.php b/app/Http/Controllers/API/ChatController.php index e2883d082d..6c933f1396 100644 --- a/app/Http/Controllers/API/ChatController.php +++ b/app/Http/Controllers/API/ChatController.php @@ -13,13 +13,24 @@ namespace App\Http\Controllers\API; +use App\Bot; use App\User; +use App\UserEcho; +use Carbon\Carbon; +use App\UserAudible; +use App\Bots\NerdBot; +use App\Bots\CasinoBot; +use App\Bots\SystemBot; +use App\Events\Chatter; use Illuminate\Http\Request; use Illuminate\Auth\AuthManager; +use App\Http\Resources\BotResource; use App\Http\Controllers\Controller; use App\Repositories\ChatRepository; use App\Http\Resources\ChatRoomResource; +use App\Http\Resources\UserEchoResource; use App\Http\Resources\ChatMessageResource; +use App\Http\Resources\UserAudibleResource; class ChatController extends Controller { @@ -45,6 +56,43 @@ public function statuses() return response($this->chat->statuses(), 200); } + /* ECHOES */ + public function echoes() + { + $user = User::with(['echoes'])->findOrFail($this->auth->user()->id); + + if (! $user->echoes || count($user->echoes->toArray()) < 1) { + $echoes = new UserEcho(); + $echoes->user_id = $this->auth->user()->id; + $echoes->room_id = 1; + $echoes->save(); + } + + return UserEchoResource::collection($this->chat->echoes($this->auth->user()->id)); + } + + /* AUDIBLES */ + public function audibles() + { + $user = User::with(['audibles'])->findOrFail($this->auth->user()->id); + + if (! $user->audibles || count($user->audibles->toArray()) < 1) { + $audibles = new UserAudible(); + $audibles->user_id = $this->auth->user()->id; + $audibles->room_id = 1; + $audibles->status = 1; + $audibles->save(); + } + + return UserAudibleResource::collection($this->chat->audibles($this->auth->user()->id)); + } + + /* BOTS */ + public function bots() + { + return BotResource::collection($this->chat->bots()); + } + /* ROOMS */ public function rooms() { @@ -62,11 +110,34 @@ public function messages($room_id) return ChatMessageResource::collection($this->chat->messages($room_id)); } + /* MESSAGES */ + public function privateMessages($target_id) + { + return ChatMessageResource::collection($this->chat->privateMessages($this->auth->user()->id, $target_id)); + } + + /* MESSAGES */ + public function botMessages($bot_id) + { + $bot = Bot::where('id', '=', $bot_id)->firstOrFail(); + if ($bot->is_systembot) { + $runbot = new SystemBot($this->chat); + } elseif ($bot->is_nerdbot) { + $runbot = new NerdBot($this->chat); + } + $runbot->process('message', $this->auth->user(), '', 0); + + return ChatMessageResource::collection($this->chat->botMessages($this->auth->user()->id, $bot->id)); + } + public function createMessage(Request $request) { - $user_id = $request->get('user_id'); - $room_id = $request->get('chatroom_id'); - $message = $request->get('message'); + $user_id = (int) $request->input('user_id'); + $receiver_id = $request->input('receiver_id'); + $room_id = $request->input('chatroom_id'); + $bot_id = $request->input('bot_id'); + $message = $request->input('message'); + $targeted = $request->input('targeted'); $save = $request->get('save'); if ($this->auth->user()->id !== $user_id) { @@ -82,13 +153,201 @@ public function createMessage(Request $request) return response('error', 401); } - $message = $this->chat->message($user_id, $room_id, $message); + $bots = Bot::where('active', '=', 1)->orderBy('position', 'asc')->get(); + $which = null; + $target = null; + $runbot = null; + $trip = 'msg'; + if ($message && substr($message, 0, 1 + (strlen($trip))) == '/'.$trip) { + $which = 'skip'; + $command = @explode(' ', $message); + if (array_key_exists(1, $command)) { + $receiver = User::where('username', 'like', $command[1])->firstOrFail(); + $receiver_id = $receiver->id; + $clone = $command; + array_shift($clone); + array_shift($clone); + $message = trim(implode(' ', $clone)); + } + $bot_id = 1; + } + + $trip = 'gift'; + if ($message && substr($message, 0, 1 + (strlen($trip))) == '/'.$trip) { + $which = 'echo'; + $target = 'system'; + $message = '/bot gift'.substr($message, strlen($trip) + 1, strlen($message)); + } + if ($target == 'system') { + $runbot = new SystemBot($this->chat); + } + if ($which == null) { + foreach ($bots as $bot) { + if ($message && substr($message, 0, 1 + (strlen($bot->command))) == '/'.$bot->command) { + $which = 'echo'; + } + if ($message && substr($message, 0, 1 + (strlen($bot->command))) == '!'.$bot->command) { + $which = 'public'; + } + if ($message && substr($message, 0, 1 + (strlen($bot->command))) == '@'.$bot->command) { + $message = substr($message, 1 + strlen($bot->command), strlen($message)); + $which = 'private'; + } + if ($message && $receiver_id == 1 && $bot->id == $bot_id) { + if ($message && substr($message, 0, 1 + (strlen($bot->command))) == '/'.$bot->command) { + $message = substr($message, 1 + strlen($bot->command), strlen($message)); + } + if ($message && substr($message, 0, 1 + (strlen($bot->command))) == '!'.$bot->command) { + $message = substr($message, 1 + strlen($bot->command), strlen($message)); + } + if ($message && substr($message, 0, 1 + (strlen($bot->command))) == '@'.$bot->command) { + $message = substr($message, 1 + strlen($bot->command), strlen($message)); + } + $which = 'message'; + } + if ($which != null) { + break; + } + } + } + + if ($which != null && $which != 'skip' && ! $runbot) { + if ($bot->is_systembot) { + $runbot = new SystemBot($this->chat); + } elseif ($bot->is_nerdbot) { + $runbot = new NerdBot($this->chat); + } elseif ($bot->is_casinobot) { + $runbot = new CasinoBot($this->chat); + } + } + if ($runbot) { + return $runbot->process($which, $this->auth->user(), $message, 0); + } + + $echo = false; + if ($receiver_id && $receiver_id > 0) { + $sender_dirty = 0; + $receiver_dirty = 0; + $sender_echoes = cache()->get('user-echoes'.$user_id); + $receiver_echoes = cache()->get('user-echoes'.$receiver_id); + if (! $sender_echoes || ! is_array($sender_echoes) || count($sender_echoes) < 1) { + $sender_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$user_id])->get(); + } + if (! $receiver_echoes || ! is_array($receiver_echoes) || count($receiver_echoes) < 1) { + $receiver_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$receiver_id])->get(); + } + $sender_listening = false; + foreach ($sender_echoes as $se => $sender_echo) { + if ($sender_echo['target_id'] == $receiver_id) { + $sender_listening = true; + } + } + if (! $sender_listening) { + $sender_port = new UserEcho(); + $sender_port->user_id = $user_id; + $sender_port->target_id = $receiver_id; + $sender_port->save(); + $sender_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$user_id])->get(); + $sender_dirty = 1; + } + $receiver_listening = false; + foreach ($receiver_echoes as $se => $receiver_echo) { + if ($receiver_echo['target_id'] == $user_id) { + $receiver_listening = true; + } + } + if (! $receiver_listening) { + $receiver_port = new UserEcho(); + $receiver_port->user_id = $receiver_id; + $receiver_port->target_id = $user_id; + $receiver_port->save(); + $receiver_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$receiver_id])->get(); + $receiver_dirty = 1; + } + if ($sender_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-echoes'.$user_id, $sender_echoes, $expiresAt); + event(new Chatter('echo', $user_id, UserEchoResource::collection($sender_echoes))); + } + if ($receiver_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-echoes'.$receiver_id, $receiver_echoes, $expiresAt); + event(new Chatter('echo', $receiver_id, UserEchoResource::collection($receiver_echoes))); + } + + $sender_dirty = 0; + $receiver_dirty = 0; + $sender_audibles = cache()->get('user-audibles'.$user_id); + $receiver_audibles = cache()->get('user-audibles'.$receiver_id); + if (! $sender_audibles || ! is_array($sender_audibles) || count($sender_audibles) < 1) { + $sender_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$user_id])->get(); + } + if (! $receiver_audibles || ! is_array($receiver_audibles) || count($receiver_audibles) < 1) { + $receiver_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$receiver_id])->get(); + } + $sender_listening = false; + foreach ($sender_audibles as $se => $sender_echo) { + if ($sender_echo['target_id'] == $receiver_id) { + $sender_listening = true; + } + } + if (! $sender_listening) { + $sender_port = new UserAudible(); + $sender_port->user_id = $user_id; + $sender_port->target_id = $receiver_id; + $sender_port->status = 0; + $sender_port->save(); + $sender_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$user_id])->get(); + $sender_dirty = 1; + } + $receiver_listening = false; + foreach ($receiver_audibles as $se => $receiver_echo) { + if ($receiver_echo['target_id'] == $user_id) { + $receiver_listening = true; + } + } + if (! $receiver_listening) { + $receiver_port = new UserAudible(); + $receiver_port->user_id = $receiver_id; + $receiver_port->target_id = $user_id; + $receiver_port->status = 0; + $receiver_port->save(); + $receiver_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$receiver_id])->get(); + $receiver_dirty = 1; + } + if ($sender_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-audibles'.$user_id, $sender_audibles, $expiresAt); + event(new Chatter('audible', $user_id, UserAudibleResource::collection($sender_audibles))); + } + if ($receiver_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-audibles'.$receiver_id, $receiver_audibles, $expiresAt); + event(new Chatter('audible', $receiver_id, UserAudibleResource::collection($receiver_audibles))); + } + + $ignore = false; + $room_id = 0; + if ($bot_id > 0) { + $ignore = true; + } + $message = $this->chat->privateMessage($user_id, $room_id, $message, $receiver_id, null, $ignore); + } else { + $receiver_id = null; + $bot_id = null; + $message = $this->chat->message($user_id, $room_id, $message, $receiver_id, $bot_id); + $this->chat->ping('room', $room_id); + } if (! $save) { $message->delete(); } - return $save ? new ChatMessageResource($message) : response('success', 200); + if ($save && $echo != false) { + return new ChatMessageResource($message); + } + + return response('success', 200); } public function deleteMessage($id) @@ -98,15 +357,119 @@ public function deleteMessage($id) return response('success', 200); } + public function deleteRoomEcho(Request $request, $user_id) + { + $echo = UserEcho::where('user_id', '=', $user_id)->where('room_id', '=', $request->input('room_id'))->firstOrFail(); + $echo->delete(); + + $user = User::with(['chatStatus', 'chatroom', 'group', 'echoes'])->findOrFail($user_id); + $room = $this->chat->roomFindOrFail(1); + + $user->chatroom()->dissociate(); + $user->chatroom()->associate($room); + + $user->save(); + + $sender_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$user_id])->get(); + + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-echoes'.$user_id, $sender_echoes, $expiresAt); + event(new Chatter('echo', $user_id, UserEchoResource::collection($sender_echoes))); + + return response($user, 200); + } + + public function deleteTargetEcho(Request $request, $user_id) + { + $echo = UserEcho::where('user_id', '=', $user_id)->where('target_id', '=', $request->input('target_id'))->firstOrFail(); + $echo->delete(); + + $user = User::with(['chatStatus', 'chatroom', 'group', 'echoes'])->findOrFail($user_id); + $sender_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$user_id])->get(); + + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-echoes'.$user_id, $sender_echoes, $expiresAt); + event(new Chatter('echo', $user_id, UserEchoResource::collection($sender_echoes))); + + return response($user, 200); + } + + public function deleteBotEcho(Request $request, $user_id) + { + $echo = UserEcho::where('user_id', '=', $user_id)->where('bot_id', '=', $request->input('bot_id'))->firstOrFail(); + $echo->delete(); + + $user = User::with(['chatStatus', 'chatroom', 'group', 'echoes'])->findOrFail($user_id); + $sender_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$user_id])->get(); + + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-echoes'.$user_id, $sender_echoes, $expiresAt); + event(new Chatter('echo', $user_id, UserEchoResource::collection($sender_echoes))); + + return response($user, 200); + } + + public function toggleRoomAudible(Request $request, $user_id) + { + $echo = UserAudible::where('user_id', '=', $user_id)->where('room_id', '=', $request->input('room_id'))->firstOrFail(); + $echo->status = ($echo->status == 1 ? 0 : 1); + $echo->save(); + + $user = User::with(['chatStatus', 'chatroom', 'group', 'audibles', 'audibles'])->findOrFail($user_id); + $sender_audibles = UserAudible::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$user_id])->get(); + + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-audibles'.$user_id, $sender_audibles, $expiresAt); + event(new Chatter('audible', $user_id, UserAudibleResource::collection($sender_audibles))); + + return response($user, 200); + } + + public function toggleTargetAudible(Request $request, $user_id) + { + $echo = UserAudible::where('user_id', '=', $user_id)->where('target_id', '=', $request->input('target_id'))->firstOrFail(); + $echo->status = ($echo->status == 1 ? 0 : 1); + $echo->save(); + + $user = User::with(['chatStatus', 'chatroom', 'group', 'audibles', 'audibles'])->findOrFail($user_id); + $sender_audibles = UserAudible::with(['target', 'room', 'bot'])->whereRaw('user_id = ?', [$user_id])->get(); + + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-audibles'.$user_id, $sender_audibles, $expiresAt); + event(new Chatter('audible', $user_id, UserAudibleResource::collection($sender_audibles))); + + return response($user, 200); + } + + public function toggleBotAudible(Request $request, $user_id) + { + $echo = UserAudible::where('user_id', '=', $user_id)->where('bot_id', '=', $request->input('bot_id'))->firstOrFail(); + $echo->status = ($echo->status == 1 ? 0 : 1); + $echo->save(); + + $user = User::with(['chatStatus', 'chatroom', 'group', 'audibles', 'audibles'])->findOrFail($user_id); + $sender_audibles = UserAudible::with(['bot', 'room', 'bot'])->whereRaw('user_id = ?', [$user_id])->get(); + + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-audibles'.$user_id, $sender_audibles, $expiresAt); + event(new Chatter('audible', $user_id, UserAudibleResource::collection($sender_audibles))); + + return response($user, 200); + } + /* USERS */ public function updateUserChatStatus(Request $request, $id) { - $user = User::with(['chatStatus', 'chatroom', 'group'])->findOrFail($id); - $status = $this->chat->statusFindOrFail($request->get('status_id')); + $user = User::with(['chatStatus', 'chatroom', 'group', 'echoes'])->findOrFail($id); + $status = $this->chat->statusFindOrFail($request->input('status_id')); + + $log = '[url=/'.$user->slug.'.'.$user->id.']'.$user->username.'[/url] has updated their status to [b]'.$status->name.'[/b]'; + + $message = $this->chat->message(1, $user->chatroom->id, $log, null); + $message->save(); $user->chatStatus()->dissociate(); $user->chatStatus()->associate($status); - $user->save(); return response($user, 200); @@ -114,14 +477,53 @@ public function updateUserChatStatus(Request $request, $id) public function updateUserRoom(Request $request, $id) { - $user = User::with(['chatStatus', 'chatroom', 'group'])->findOrFail($id); - $room = $this->chat->roomFindOrFail($request->get('room_id')); + $user = User::with(['chatStatus', 'chatroom', 'group', 'echoes'])->findOrFail($id); + $room = $this->chat->roomFindOrFail($request->input('room_id')); $user->chatroom()->dissociate(); $user->chatroom()->associate($room); $user->save(); + $sender_dirty = 0; + $sender_echoes = cache()->get('user-echoes'.$id); + if (! $sender_echoes || ! is_array($sender_echoes) || count($sender_echoes) < 1) { + $sender_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$id])->get(); + } + $sender_listening = false; + foreach ($sender_echoes as $se => $sender_echo) { + if ($sender_echo['room_id'] == $room->id) { + $sender_listening = true; + } + } + if (! $sender_listening) { + $sender_port = new UserEcho(); + $sender_port->user_id = $id; + $sender_port->room_id = $room->id; + $sender_port->save(); + $sender_echoes = UserEcho::with(['room', 'target', 'bot'])->whereRaw('user_id = ?', [$id])->get(); + $sender_dirty = 1; + } + if ($sender_dirty == 1) { + $expiresAt = Carbon::now()->addMinutes(60); + cache()->put('user-echoes'.$id, $sender_echoes, $expiresAt); + event(new Chatter('echo', $id, UserEchoResource::collection($sender_echoes))); + } + + return response($user, 200); + } + + public function updateUserTarget(Request $request, $id) + { + $user = User::with(['chatStatus', 'chatroom', 'group', 'echoes'])->findOrFail($id); + + return response($user, 200); + } + + public function updateBotTarget(Request $request, $id) + { + $user = User::with(['chatStatus', 'chatroom', 'group', 'echoes'])->findOrFail($id); + return response($user, 200); } } diff --git a/app/Http/Controllers/BonusController.php b/app/Http/Controllers/BonusController.php index 91276508a4..48a56c6a68 100755 --- a/app/Http/Controllers/BonusController.php +++ b/app/Http/Controllers/BonusController.php @@ -376,7 +376,7 @@ public function sendGift(Request $request) $recipient_url = hrefProfile($recipient); $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : [url={$profile_url}]{$user->username}[/url] has gifted {$value} BON to [url={$recipient_url}]{$recipient->username}[/url]" + "[url={$profile_url}]{$user->username}[/url] has gifted {$value} BON to [url={$recipient_url}]{$recipient->username}[/url]" ); if ($dest == 'profile') { diff --git a/app/Http/Controllers/CommentController.php b/app/Http/Controllers/CommentController.php index e9fab42ded..e83fd1be1a 100755 --- a/app/Http/Controllers/CommentController.php +++ b/app/Http/Controllers/CommentController.php @@ -109,7 +109,7 @@ public function article(Request $request, $slug, $id) $profile_url = hrefProfile($user); $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : [url={$profile_url}]{$user->username}[/url] has left a comment on article [url={$article_url}]{$article->title}[/url]" + "[url={$profile_url}]{$user->username}[/url] has left a comment on article [url={$article_url}]{$article->title}[/url]" ); if ($this->tag->hasTags($request->input('content'))) { @@ -210,11 +210,11 @@ public function torrent(Request $request, $slug, $id) // Auto Shout if ($comment->anon == 0) { $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : [url={$profile_url}]{$user->username}[/url] has left a comment on Torrent [url={$torrent_url}]{$torrent->name}[/url]" + "[url={$profile_url}]{$user->username}[/url] has left a comment on Torrent [url={$torrent_url}]{$torrent->name}[/url]" ); } else { $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : An anonymous user has left a comment on torrent [url={$torrent_url}]{$torrent->name}[/url]" + "An anonymous user has left a comment on torrent [url={$torrent_url}]{$torrent->name}[/url]" ); } @@ -311,11 +311,11 @@ public function request(Request $request, $id) // Auto Shout if ($comment->anon == 0) { $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : [url={$profile_url}]{$user->username}[/url] has left a comment on Request [url={$tr_url}]{$tr->name}[/url]" + "[url={$profile_url}]{$user->username}[/url] has left a comment on Request [url={$tr_url}]{$tr->name}[/url]" ); } else { $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : An anonymous user has left a comment on Request [url={$tr_url}]{$tr->name}[/url]" + "An anonymous user has left a comment on Request [url={$tr_url}]{$tr->name}[/url]" ); } @@ -436,7 +436,7 @@ public function quickthanks($id) $profile_url = hrefProfile($user); $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : [url={$profile_url}]{$user->username}[/url] has left a comment on Torrent [url={$torrent_url}]{$torrent->name}[/url]" + "[url={$profile_url}]{$user->username}[/url] has left a comment on Torrent [url={$torrent_url}]{$torrent->name}[/url]" ); return redirect()->route('torrent', ['slug' => $torrent->slug, 'id' => $torrent->id]) diff --git a/app/Http/Controllers/ForumController.php b/app/Http/Controllers/ForumController.php index cf1bbdb0d6..20fa777050 100755 --- a/app/Http/Controllers/ForumController.php +++ b/app/Http/Controllers/ForumController.php @@ -591,7 +591,7 @@ public function reply(Request $request, $slug, $id) $postUrl = "{$appurl}/forums/topic/{$topic->slug}.{$topic->id}?page={$post->getPageNumber()}#post-{$post->id}"; $realUrl = "/forums/topic/{$topic->slug}.{$topic->id}?page={$post->getPageNumber()}#post-{$post->id}"; $profileUrl = "{$appurl}/{$user->username}.{$user->id}"; - $this->chat->systemMessage(":robot: [b][color=#fb9776]System[/color][/b] : [url=$profileUrl]{$user->username}[/url] has left a reply on topic [url={$postUrl}]{$topic->name}[/url]"); + $this->chat->systemMessage("[url=$profileUrl]{$user->username}[/url] has left a reply on topic [url={$postUrl}]{$topic->name}[/url]"); // Notify All Subscribers Of New Reply if ($topic->first_user_poster_id != $user->id) { @@ -732,7 +732,7 @@ public function newTopic(Request $request, $slug, $id) $topicUrl = "{$appurl}/forums/topic/{$topic->slug}.{$topic->id}"; $profileUrl = "{$appurl}/{$user->username}.{$user->id}"; - $this->chat->systemMessage(":robot: [b][color=#fb9776]System[/color][/b] : [url={$profileUrl}]{$user->username}[/url] has created a new topic [url={$topicUrl}]{$topic->name}[/url]"); + $this->chat->systemMessage("[url={$profileUrl}]{$user->username}[/url] has created a new topic [url={$topicUrl}]{$topic->name}[/url]"); //Achievements $user->unlock(new UserMadeFirstPost(), 1); diff --git a/app/Http/Controllers/Staff/BotsController.php b/app/Http/Controllers/Staff/BotsController.php new file mode 100644 index 0000000000..70b7a7d073 --- /dev/null +++ b/app/Http/Controllers/Staff/BotsController.php @@ -0,0 +1,186 @@ +toastr = $toastr; + } + + /** + * Display a listing of the Bots resource. + * + * @param string $hash + * @return \Illuminate\Http\Response + */ + public function index($hash = null) + { + $bots = Bot::orderBy('position', 'ASC')->get(); + + return view('Staff.bots.index', [ + 'bots' => $bots, + ]); + } + + /** + * Show the form for editing the specified Bot resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function edit($id) + { + $user = auth()->user(); + $bot = Bot::findOrFail($id); + + return view('Staff.bots.edit', [ + 'user' => $user, + 'bot' => $bot, + ]); + } + + /** + * Update the specified Bot resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $id) + { + $user = auth()->user(); + $bot = Bot::findOrFail($id); + + if ($request->has('command') && $request->input('command') == $bot->command) { + $v = validator($request->all(), [ + 'name' => 'required|min:3|max:255', + 'command' => 'required|alpha_dash|min:3|max:255', + 'position' => 'required', + 'color' => 'required', + 'icon' => 'required', + 'emoji' => 'required', + 'help' => 'sometimes|max:9999', + 'info' => 'sometimes|max:9999', + 'about' => 'sometimes|max:9999', + ]); + } else { + $v = validator($request->all(), [ + 'name' => 'required|min:3|max:255', + 'command' => 'required|alpha_dash|min:3|max:255|unique:bots', + 'position' => 'required', + 'color' => 'required', + 'icon' => 'required', + 'emoji' => 'required', + 'help' => 'sometimes|max:9999', + 'info' => 'sometimes|max:9999', + 'about' => 'sometimes|max:9999', + ]); + } + + $error = null; + $success = null; + $redirect = null; + + if ($v->passes()) { + $bot->name = $request->input('name'); + $bot->slug = str_slug($request->input('name')); + $bot->position = $request->input('position'); + $bot->color = $request->input('color'); + $bot->icon = $request->input('icon'); + $bot->emoji = $request->input('emoji'); + $bot->about = $request->input('about'); + $bot->info = $request->input('info'); + $bot->help = $request->input('help'); + $bot->command = $request->input('command'); + $bot->save(); + $success = 'The Bot Has Been Updated'; + } + if (! $success) { + $error = 'Unable To Process Request'; + if ($v->errors()) { + $error = $v->errors(); + } + + return redirect()->route('Staff.bots.edit', ['id' => $id]) + ->with($this->toastr->error($error, 'Whoops!', ['options'])); + } + + return redirect()->route('Staff.bots.edit', ['id' => $id]) + ->with($this->toastr->success($success, 'Yay!', ['options'])); + } + + /** + * Remove the specified Bot resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy($id) + { + $bot = Bot::where('is_protected', '=', 0)->findOrFail($id); + $bot->delete(); + + return redirect()->route('Staff.bots.index') + ->with($this->toastr->success('The Humans Vs Machines War Has Begun! Humans: 1 and Bots: 0', 'Yay!', ['options'])); + } + + /** + * Disable the specified Bot resource in storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function disable($id) + { + $bot = Bot::findOrFail($id); + $bot->active = 0; + $bot->save(); + + return redirect()->route('Staff.bots.index') + ->with($this->toastr->success('The Bot Has Been Disabled', 'Yay!', ['options'])); + } + + /** + * Enable the specified Bot resource in storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function enable($id) + { + $bot = Bot::findOrFail($id); + $bot->active = 1; + $bot->save(); + + return redirect()->route('Staff.bots.index') + ->with($this->toastr->success('The Bot Has Been Enabled', 'Yay!', ['options'])); + } +} diff --git a/app/Http/Controllers/TorrentController.php b/app/Http/Controllers/TorrentController.php index da1fa07347..1a14e7371e 100755 --- a/app/Http/Controllers/TorrentController.php +++ b/app/Http/Controllers/TorrentController.php @@ -1285,11 +1285,11 @@ public function upload(Request $request) // Announce To Shoutbox if ($anon == 0) { $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : User [url={$appurl}/".$username.'.'.$user_id.']'.$username."[/url] has uploaded [url={$appurl}/torrents/".$torrent->slug.'.'.$torrent->id.']'.$torrent->name.'[/url] grab it now! :slight_smile:' + "User [url={$appurl}/".$username.'.'.$user_id.']'.$username."[/url] has uploaded [url={$appurl}/torrents/".$torrent->slug.'.'.$torrent->id.']'.$torrent->name.'[/url] grab it now! :slight_smile:' ); } else { $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : An anonymous user has uploaded [url={$appurl}/torrents/".$torrent->slug.'.'.$torrent->id.']'.$torrent->name.'[/url] grab it now! :slight_smile:' + "An anonymous user has uploaded [url={$appurl}/torrents/".$torrent->slug.'.'.$torrent->id.']'.$torrent->name.'[/url] grab it now! :slight_smile:' ); } @@ -1412,7 +1412,7 @@ public function bumpTorrent($slug, $id) $profile_url = hrefProfile($user); $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : Attention, [url={$torrent_url}]{$torrent->name}[/url] has been bumped to top by [url={$profile_url}]{$user->username}[/url]! It could use more seeds!" + "Attention, [url={$torrent_url}]{$torrent->name}[/url] has been bumped to top by [url={$profile_url}]{$user->username}[/url]! It could use more seeds!" ); // Announce To IRC @@ -1514,13 +1514,13 @@ public function grantFL($slug, $id) $torrent->free = '1'; $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : Ladies and Gents, [url={$torrent_url}]{$torrent->name}[/url] has been granted 100% FreeLeech! Grab It While You Can! :fire:" + "Ladies and Gents, [url={$torrent_url}]{$torrent->name}[/url] has been granted 100% FreeLeech! Grab It While You Can! :fire:" ); } else { $torrent->free = '0'; $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : Ladies and Gents, [url={$torrent_url}]{$torrent->name}[/url] has been revoked of its 100% FreeLeech! :poop:" + "Ladies and Gents, [url={$torrent_url}]{$torrent->name}[/url] has been revoked of its 100% FreeLeech! :poop:" ); } @@ -1562,7 +1562,7 @@ public function grantFeatured($slug, $id) $torrent_url = hrefTorrent($torrent); $profile_url = hrefProfile($user); $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : Ladies and Gents, [url={$torrent_url}]{$torrent->name}[/url] has been added to the Featured Torrents Slider by [url={$profile_url}]{$user->username}[/url]! Grab It While You Can! :fire:" + "Ladies and Gents, [url={$torrent_url}]{$torrent->name}[/url] has been added to the Featured Torrents Slider by [url={$profile_url}]{$user->username}[/url]! Grab It While You Can! :fire:" ); // Activity Log @@ -1596,12 +1596,12 @@ public function grantDoubleUp($slug, $id) $torrent->doubleup = '1'; $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : Ladies and Gents, [url={$torrent_url}]{$torrent->name}[/url] has been granted Double Upload! Grab It While You Can! :fire:" + "Ladies and Gents, [url={$torrent_url}]{$torrent->name}[/url] has been granted Double Upload! Grab It While You Can! :fire:" ); } else { $torrent->doubleup = '0'; $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : Ladies and Gents, [url={$torrent_url}]{$torrent->name}[/url] has been revoked of its Double Upload! :poop:" + "Ladies and Gents, [url={$torrent_url}]{$torrent->name}[/url] has been revoked of its Double Upload! :poop:" ); } $torrent->save(); @@ -1638,7 +1638,7 @@ public function reseedTorrent($slug, $id) $profile_url = hrefProfile($user); $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : Ladies and Gents, a reseed request was just placed on [url={$torrent_url}]{$torrent->name}[/url] can you help out :question:" + "Ladies and Gents, a reseed request was just placed on [url={$torrent_url}]{$torrent->name}[/url] can you help out :question:" ); // Activity Log diff --git a/app/Http/Resources/BotResource.php b/app/Http/Resources/BotResource.php new file mode 100644 index 0000000000..eb6460d7c7 --- /dev/null +++ b/app/Http/Resources/BotResource.php @@ -0,0 +1,31 @@ +make(LaravelEmojiOne::class); + $logger = null; + if ($this->user_id && $this->user_id == 1) { + $logger = Bbcode::parse('[div class="align-left"][div class="chatTriggers"]'.clean($this->message).'[/div][/div]'); + $logger = $emojiOne->toImage($logger); + $logger = str_replace('a href="/#', 'a trigger="bot" class="chatTrigger" href="/#', $logger); + } else { + $logger = Bbcode::parse('[div class="align-left"]'.clean($this->message).'[/div]'); + $logger = $emojiOne->toImage($logger); + } + return [ - 'id' => $this->id, - 'user' => new ChatUserResource($this->whenLoaded('user')), - 'chatroom' => new ChatRoomResource($this->whenLoaded('chatroom')), - 'message' => htmlspecialchars_decode($emojiOne->toImage(Bbcode::parse('[left]'.clean($this->message).'[/left]'))), + 'id' => $this->id, + 'bot' => new BotResource($this->whenLoaded('bot')), + 'user' => new UserResource($this->whenLoaded('user')), + 'receiver' => new UserResource($this->whenLoaded('receiver')), + 'chatroom' => new ChatRoomResource($this->whenLoaded('chatroom')), + 'message' => htmlspecialchars_decode($logger), 'created_at' => $this->created_at->toIso8601String(), 'updated_at' => $this->updated_at->toIso8601String(), ]; diff --git a/app/Http/Resources/ChatUserResource.php b/app/Http/Resources/ChatUserResource.php index 0bf2dcabc6..9430631d58 100644 --- a/app/Http/Resources/ChatUserResource.php +++ b/app/Http/Resources/ChatUserResource.php @@ -33,6 +33,7 @@ public function toArray($request) 'chat_status_id' => $this->chat_status_id, 'chatroom_id' => $this->chatroom_id, 'group' => $this->whenLoaded('group'), + 'echoes' => $this->whenLoaded('echoes'), 'group_id' => $this->group_id, 'title' => $this->title, 'image' => $this->image, diff --git a/app/Http/Resources/UserAudibleResource.php b/app/Http/Resources/UserAudibleResource.php new file mode 100644 index 0000000000..4ab719dca5 --- /dev/null +++ b/app/Http/Resources/UserAudibleResource.php @@ -0,0 +1,39 @@ + $this->id, + 'user_id' => $this->user_id, + 'user' => $this->user, + 'target' => $this->target, + 'room' => $this->room, + 'bot' => $this->bot, + 'status' => $this->status, + ]; + } +} diff --git a/app/Http/Resources/UserEchoResource.php b/app/Http/Resources/UserEchoResource.php new file mode 100644 index 0000000000..74f8b18325 --- /dev/null +++ b/app/Http/Resources/UserEchoResource.php @@ -0,0 +1,38 @@ + $this->id, + 'user_id' => $this->user_id, + 'user' => $this->user, + 'target' => $this->target, + 'room' => $this->room, + 'bot' => $this->bot, + ]; + } +} diff --git a/app/Listeners/AchievementUnlocked.php b/app/Listeners/AchievementUnlocked.php index 851f478287..38d76f0c61 100644 --- a/app/Listeners/AchievementUnlocked.php +++ b/app/Listeners/AchievementUnlocked.php @@ -43,7 +43,7 @@ public function handle(Unlocked $event) $profile_url = hrefProfile($user); $this->chat->systemMessage( - ":robot: [b][color=#fb9776]System[/color][/b] : User [url={$profile_url}]{$user->username}[/url] has unlocked the {$event->progress->details->name} achievement :medal:" + "User [url={$profile_url}]{$user->username}[/url] has unlocked the {$event->progress->details->name} achievement :medal:" ); } } diff --git a/app/Message.php b/app/Message.php index 525093d790..04a2e28c2a 100644 --- a/app/Message.php +++ b/app/Message.php @@ -27,8 +27,20 @@ class Message extends Model 'message', 'user_id', 'chatroom_id', + 'receiver_id', + 'bot_id', ]; + /** + * Belongs To A Bot. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function bot() + { + return $this->belongsTo(Bot::class); + } + /** * Belongs To A User. * @@ -39,6 +51,16 @@ public function user() return $this->belongsTo(User::class); } + /** + * A message belongs to a receiver. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function receiver() + { + return $this->belongsTo(User::class, 'receiver_id'); + } + /** * Belongs To A Chat Room. * diff --git a/app/Repositories/ChatRepository.php b/app/Repositories/ChatRepository.php index bb1b4b6809..cd167f8e05 100644 --- a/app/Repositories/ChatRepository.php +++ b/app/Repositories/ChatRepository.php @@ -13,12 +13,18 @@ namespace App\Repositories; +use App\Bot; use App\User; use App\Message; use App\Chatroom; +use App\UserEcho; use App\ChatStatus; +use App\Events\Ping; +use App\UserAudible; +use App\Events\Chatter; use App\Events\MessageSent; use App\Events\MessageDeleted; +use App\Http\Resources\ChatMessageResource; class ChatRepository { @@ -42,12 +48,30 @@ class ChatRepository */ private $user; - public function __construct(Message $message, Chatroom $room, ChatStatus $status, User $user) + /** + * @var Bot + */ + private $bot; + + /** + * @var Echo + */ + private $echo; + + /** + * @var Audible + */ + private $audible; + + public function __construct(Message $message, Chatroom $room, ChatStatus $status, User $user, Bot $bot, UserEcho $echo, UserAudible $audible) { $this->message = $message; $this->room = $room; + $this->echo = $echo; $this->status = $status; $this->user = $user; + $this->bot = $bot; + $this->audible = $audible; } public function config() @@ -55,6 +79,39 @@ public function config() return config('chat'); } + public function bots() + { + return $this->bot->all(); + } + + public function echoes($user_id) + { + return $this->echo->with([ + 'bot', + 'user', + 'target', + 'room', + ])->where(function ($query) use ($user_id) { + $query->where('user_id', '=', $user_id); + }) + ->latest() + ->get(); + } + + public function audibles($user_id) + { + return $this->audible->with([ + 'bot', + 'user', + 'target', + 'room', + ])->where(function ($query) use ($user_id) { + $query->where('user_id', '=', $user_id); + }) + ->latest() + ->get(); + } + public function rooms() { return $this->room->all(); @@ -65,16 +122,32 @@ public function roomFindOrFail($id) return $this->room->findOrFail($id); } - public function message($user_id, $room_id, $message) + public function ping($type, $id) + { + if ($type == 'room') { + $rooms = Chatroom::where('id', '>', 0)->get(); + foreach ($rooms as $room) { + broadcast(new Ping($room->id, $id)); + } + } + + return true; + } + + public function message($user_id, $room_id, $message, $receiver = null, $bot = null) { if ($this->user->find($user_id)->censor) { $message = $this->censorMessage($message); } + $message = $this->htmlifyMessage($message); + $message = $this->message->create([ 'user_id' => $user_id, 'chatroom_id' => $room_id, - 'message' => $message, + 'message' => $message, + 'receiver_id' => $receiver, + 'bot_id' => $bot, ]); $this->checkMessageLimits($room_id); @@ -84,6 +157,65 @@ public function message($user_id, $room_id, $message) return $message; } + public function botMessage($bot_id, $room_id, $message, $receiver = null) + { + $user = $this->user->find($receiver); + if ($user->censor) { + $message = $this->censorMessage($message); + } + $message = $this->htmlifyMessage($message); + $save = $this->message->create([ + 'bot_id' => $bot_id, + 'user_id' => 1, + 'chatroom_id' => 0, + 'message' => $message, + 'receiver_id' => $receiver, + ]); + + $message = Message::with([ + 'bot', + 'user.group', + 'user.chatStatus', + 'receiver.group', + 'receiver.chatStatus', + ])->find($save->id); + + event(new Chatter('new.bot', $receiver, new ChatMessageResource($message))); + event(new Chatter('new.ping', $receiver, ['type' => 'bot', 'id' => $bot_id])); + $message->delete(); + } + + public function privateMessage($user_id, $room_id, $message, $receiver = null, $bot = null, $ignore = false) + { + if ($this->user->find($user_id)->censor) { + $message = $this->censorMessage($message); + } + $message = $this->htmlifyMessage($message); + $save = $this->message->create([ + 'user_id' => $user_id, + 'chatroom_id' => 0, + 'message' => $message, + 'receiver_id' => $receiver, + 'bot_id' => $bot, + ]); + + $message = Message::with([ + 'bot', + 'user.group', + 'user.chatStatus', + 'receiver.group', + 'receiver.chatStatus', + ])->find($save->id); + + if ($ignore != true) { + event(new Chatter('new.message', $user_id, new ChatMessageResource($message))); + } + event(new Chatter('new.message', $receiver, new ChatMessageResource($message))); + event(new Chatter('new.ping', $receiver, ['type' => 'target', 'id' => $user_id])); + + return $message; + } + public function deleteMessage($id) { $message = $this->message->find($id); @@ -95,9 +227,51 @@ public function deleteMessage($id) public function messages($room_id) { - return $this->message->with(['user.group', 'user.chatStatus']) - ->where('chatroom_id', '=', $room_id) - ->latest() + return $this->message->with([ + 'bot', + 'user.group', + 'chatroom', + 'user.chatStatus', + 'receiver.group', + 'receiver.chatStatus', + ])->where(function ($query) use ($room_id) { + $query->where('chatroom_id', '=', $room_id); + }) + ->orderBy('id', 'desc') + ->limit(config('chat.message_limit')) + ->get(); + } + + public function botMessages($sender_id, $bot_id) + { + return $this->message->with([ + 'bot', + 'user.group', + 'chatroom', + 'user.chatStatus', + 'receiver.group', + 'receiver.chatStatus', + ])->where(function ($query) use ($sender_id,$bot_id) { + $query->whereRaw('(user_id = ? and bot_id = ?)', [$sender_id, $bot_id])->orWhereRaw('(receiver_id = ? and bot_id = ?)', [$sender_id, $bot_id]); + }) + ->orderBy('id', 'desc') + ->limit(config('chat.message_limit')) + ->get(); + } + + public function privateMessages($sender_id, $target_id) + { + return $this->message->with([ + 'bot', + 'user.group', + 'chatroom', + 'user.chatStatus', + 'receiver.group', + 'receiver.chatStatus', + ])->where(function ($query) use ($sender_id,$target_id) { + $query->whereRaw('(user_id = ? and receiver_id = ?)', [$sender_id, $target_id])->orWhereRaw('(user_id = ? and receiver_id = ?)', [$target_id, $sender_id]); + }) + ->orderBy('id', 'desc') ->limit(config('chat.message_limit')) ->get(); } @@ -114,14 +288,22 @@ public function checkMessageLimits($room_id) $message = array_pop($messages); echo $message['id']."\n"; - $this->message->find($message['id'])->delete(); + $message = $this->message->find($message['id']); + + if ($message->receiver_id === null) { + $message->delete(); + } } } } - public function systemMessage($message) + public function systemMessage($message, $bot = null) { - $this->message(1, $this->systemChatroom(), $message); + if ($bot) { + $this->message(1, $this->systemChatroom(), $message, null, $bot); + } else { + $this->message(1, $this->systemChatroom(), $message, null, 1); + } return $this; } @@ -193,4 +375,11 @@ protected function censorMessage($message) return $message; } + + protected function htmlifyMessage($message) + { + // Soon + + return $message; + } } diff --git a/app/User.php b/app/User.php index c19ef8a9b4..97e9845a5a 100755 --- a/app/User.php +++ b/app/User.php @@ -88,7 +88,7 @@ public function chatroom() */ public function chatStatus() { - return $this->belongsTo(ChatStatus::class); + return $this->belongsTo(ChatStatus::class, 'chat_status_id', 'id'); } /** @@ -126,6 +126,16 @@ public function privacy() return $this->hasOne(UserPrivacy::class); } + /** + * Has One Chat Object. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function chat() + { + return $this->hasOne(UserChat::class); + } + /** * Has One Notifications Object. * @@ -146,6 +156,26 @@ public function rss() return $this->hasMany(Rss::class); } + /** + * Has Many Echo Settings. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function echoes() + { + return $this->hasMany(UserEcho::class); + } + + /** + * Has Many Audible Settings. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function audibles() + { + return $this->hasMany(UserAudible::class); + } + /** * Has Many Thanks Given. * diff --git a/app/UserAudible.php b/app/UserAudible.php new file mode 100644 index 0000000000..035b28fe2e --- /dev/null +++ b/app/UserAudible.php @@ -0,0 +1,73 @@ +belongsTo(User::class); + } + + /** + * Belongs To A Chatroom. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function room() + { + return $this->belongsTo(Chatroom::class); + } + + /** + * Belongs To A Target. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function target() + { + return $this->belongsTo(User::class); + } + + /** + * Belongs To A Bot. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function bot() + { + return $this->belongsTo(Bot::class); + } +} diff --git a/app/UserEcho.php b/app/UserEcho.php new file mode 100644 index 0000000000..44dd73be33 --- /dev/null +++ b/app/UserEcho.php @@ -0,0 +1,73 @@ +belongsTo(User::class); + } + + /** + * Belongs To A Chatroom. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function room() + { + return $this->belongsTo(Chatroom::class); + } + + /** + * Belongs To A Target. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function target() + { + return $this->belongsTo(User::class); + } + + /** + * Belongs To A Bot. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function bot() + { + return $this->belongsTo(Bot::class); + } +} diff --git a/database/migrations/2018_05_15_223339_add_receiver_id_column_to_messages_table.php b/database/migrations/2018_05_15_223339_add_receiver_id_column_to_messages_table.php new file mode 100644 index 0000000000..9d55704e58 --- /dev/null +++ b/database/migrations/2018_05_15_223339_add_receiver_id_column_to_messages_table.php @@ -0,0 +1,32 @@ +integer('receiver_id')->after('chatroom_id')->unsigned()->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('messages', function (Blueprint $table) { + $table->dropColumn('receiver_id'); + }); + } +} diff --git a/database/migrations/2019_02_04_041644_create_user_echoes_table.php b/database/migrations/2019_02_04_041644_create_user_echoes_table.php new file mode 100644 index 0000000000..489db31df6 --- /dev/null +++ b/database/migrations/2019_02_04_041644_create_user_echoes_table.php @@ -0,0 +1,36 @@ +integer('id', true)->signed(); + $table->integer('user_id')->signed()->index(); + $table->boolean('room_id')->nullable()->index(); + $table->boolean('target_id')->nullable()->index(); + $table->boolean('bot_id')->nullable()->index(); + $table->timestamps(); + $table->foreign('user_id')->references('id')->on('users')->onUpdate('RESTRICT')->onDelete('CASCADE'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('user_echoes'); + } +} diff --git a/database/migrations/2019_02_05_220444_create_bots_table.php b/database/migrations/2019_02_05_220444_create_bots_table.php new file mode 100644 index 0000000000..9a5f945fe5 --- /dev/null +++ b/database/migrations/2019_02_05_220444_create_bots_table.php @@ -0,0 +1,53 @@ +integer('id', true); + $table->integer('position'); + $table->string('slug'); + $table->string('name'); + $table->string('command'); + $table->string('color')->nullable(); + $table->string('icon')->nullable(); + $table->string('emoji')->nullable(); + $table->string('info')->nullable(); + $table->string('about', 500)->nullable(); + $table->text('help')->nullable(); + $table->boolean('active')->default(1)->index(); + $table->boolean('is_protected')->default(0)->index(); + $table->boolean('is_triviabot')->default(0)->index(); + $table->boolean('is_nerdbot')->default(0)->index(); + $table->boolean('is_systembot')->default(0)->index(); + $table->boolean('is_casinobot')->default(0)->index(); + $table->boolean('is_betbot')->default(0)->index(); + $table->bigInteger('uploaded')->unsigned()->default(0); + $table->bigInteger('downloaded')->unsigned()->default(0); + $table->integer('fl_tokens')->unsigned()->default(0); + $table->float('seedbonus', 12)->unsigned()->default(0.00); + $table->integer('invites')->unsigned()->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('bots'); + } +} diff --git a/database/migrations/2019_02_06_005248_add_bot_id_to_messages_table.php b/database/migrations/2019_02_06_005248_add_bot_id_to_messages_table.php new file mode 100644 index 0000000000..80e764f3b5 --- /dev/null +++ b/database/migrations/2019_02_06_005248_add_bot_id_to_messages_table.php @@ -0,0 +1,32 @@ +integer('bot_id')->after('receiver_id')->unsigned()->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('messages', function (Blueprint $table) { + $table->dropColumn('bot_id'); + }); + } +} diff --git a/database/migrations/2019_02_06_075938_create_bot_transactions_table.php b/database/migrations/2019_02_06_075938_create_bot_transactions_table.php new file mode 100644 index 0000000000..761456939e --- /dev/null +++ b/database/migrations/2019_02_06_075938_create_bot_transactions_table.php @@ -0,0 +1,42 @@ +integer('id', true); + $table->string('type')->default('')->nullable()->index(); + $table->float('cost', 22)->default(0.00); + $table->integer('user_id')->default(0)->index(); + $table->integer('bot_id')->default(0)->index(); + $table->boolean('to_user')->default(0)->index(); + $table->boolean('to_bot')->default(0)->index(); + $table->text('comment', 65535); + $table->timestamps(); + $table->foreign('user_id')->references('id')->on('users')->onUpdate('RESTRICT')->onDelete('CASCADE'); + $table->foreign('bot_id')->references('id')->on('bots')->onUpdate('RESTRICT')->onDelete('CASCADE'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('bot_transactions', function (Blueprint $table) { + // + }); + } +} diff --git a/database/migrations/2019_02_07_022409_create_user_audibles_table.php b/database/migrations/2019_02_07_022409_create_user_audibles_table.php new file mode 100644 index 0000000000..c77f099ed5 --- /dev/null +++ b/database/migrations/2019_02_07_022409_create_user_audibles_table.php @@ -0,0 +1,37 @@ +integer('id', true)->signed(); + $table->integer('user_id')->signed()->index(); + $table->boolean('room_id')->nullable()->index(); + $table->boolean('target_id')->nullable()->index(); + $table->boolean('bot_id')->nullable()->index(); + $table->boolean('status')->default(0)->index(); + $table->timestamps(); + $table->foreign('user_id')->references('id')->on('users')->onUpdate('RESTRICT')->onDelete('CASCADE'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('user_audibles'); + } +} diff --git a/database/seeds/BotsTableSeeder.php b/database/seeds/BotsTableSeeder.php new file mode 100644 index 0000000000..ae3290c677 --- /dev/null +++ b/database/seeds/BotsTableSeeder.php @@ -0,0 +1,127 @@ + 'SystemBot', + 'slug' => 'systembot', + 'emoji' => '1f916', + 'command' => 'systembot', + 'position' => 1, + 'color' => '#f1c40f', + 'icon' => 'fab fa-android', + 'help' => '{me} v0.1 Help -- Notes about / ! and @{me} tab + +All [b]echo[/b] commands begin with / and echo output to current tab. +All [b]room[/b] commands begin with ! and echo output for all in current room. +All [b]private[/b] commands begin with @ or are sent via the @{me} tab. If sent via @{me} tab, no (! | / | @){command} prefix is needed. + +Echo & Private commands: +/msg [username] [message] - Send a quick private shoutbox message. +/gift [username] [amount] [message] - Send a quick gift of [amount] to [username] with attached [message]. + +Available Bots: +{bots}', + 'is_protected' => 1, + 'is_systembot' => 1, + ]); + + //2 + Bot::create([ + 'name' => 'NerdBot', + 'slug' => 'nerdbot', + 'emoji' => '1f913', + 'command' => 'nerdbot', + 'position' => 2, + 'color' => '#f1c40f', + 'icon' => 'fab fa-android', + 'help' => '{me} v0.1 Help -- Notes about / ! and @{me} tab + +All [b]echo[/b] commands begin with / and echo output to current tab. +All [b]room[/b] commands begin with ! and echo output for all in current room. +All [b]private[/b] commands begin with @ or are sent via the @{me} tab. If sent via @{me} tab, no (! | / | @){command} prefix is needed. + +Public, Echo & Private commands: + +(! | / | @)nerdbot help - Displays this help file. + +(! | / | @)nerdbot banker - Displays who is currently top BON holder. +(! | / | @)nerdbot bankers - Displays who are currently top 10 BON holders. +(! | / | @)nerdbot bans - Displays # of bans from site in past 24 hours. +(! | / | @)nerdbot donations - Displays the 10 most recent donations to all bots. +(! | / | @)nerdbot doubleupload - Displays # of double upload torrents available on the site. +(! | / | @)nerdbot freeleech - Displays # of freeleech torrents available on the site. +(! | / | @)nerdbot king - Displays who is the one and only king. +(! | / | @)nerdbot logins - Displays # of log ins to site in past 24 hours. +(! | / | @)nerdbot peers - Displays # of peers for torrents on the site. +(! | / | @)nerdbot registrations - Displays # of registrations to site in past 24 hours. +(! | / | @)nerdbot uploads - Displays # of uploads to site in past 24 hours. +(! | / | @)nerdbot warnings - Displays # of H&R warnings issued on site in past 24 hours. + +(! | / | @)nerdbot leeched - Displays the top leeched torrent on the site. +(! | / | @)nerdbot seeded - Displays the seeded torrent on the site. +(! | / | @)nerdbot snatched - Displays the top snatched torrent on the site. + +Echo & Private commands: + +None. + +(All NerdBot statistics are cached for 60 minutes)', + 'is_protected' => 1, + 'is_nerdbot' => 1, + ]); + + //3 + Bot::create([ + 'name' => 'CasinoBot', + 'slug' => 'casinobot', + 'command' => 'casinobot', + 'emoji' => '1f3b0', + 'position' => 3, + 'color' => '#f1c40f', + 'icon' => 'fab fa-android', + 'help' => 'Coming soon', + 'is_protected' => 1, + 'is_casinobot' => 1, + ]); + + //4 + Bot::create([ + 'name' => 'BetBot', + 'slug' => 'betbot', + 'command' => 'betbot', + 'emoji' => '1f3b2', + 'position' => 4, + 'color' => '#f1c40f', + 'icon' => 'fab fa-android', + 'help' => 'Coming soon', + 'is_protected' => 1, + 'is_betbot' => 1, + ]); + + //5 + Bot::create([ + 'name' => 'TriviaBot', + 'slug' => 'triviabot', + 'command' => 'triviabot', + 'emoji' => '2753', + 'position' => 5, + 'color' => '#f1c40f', + 'icon' => 'fab fa-android', + 'help' => 'Coming soon', + 'is_protected' => 1, + 'is_triviabot' => 1, + ]); + } +} diff --git a/public/sounds/alert.mp3 b/public/sounds/alert.mp3 new file mode 100644 index 0000000000..6066e62e7d Binary files /dev/null and b/public/sounds/alert.mp3 differ diff --git a/resources/js/components/chat/ChatForm.vue b/resources/js/components/chat/ChatForm.vue index becab4f97e..121178bbda 100644 --- a/resources/js/components/chat/ChatForm.vue +++ b/resources/js/components/chat/ChatForm.vue @@ -2,123 +2,170 @@
-
- SHIFT + ENTER to insert new line - Type : for emoji +
+
+ {{ $parent.botName }} can accept messages from any tab if you type: /{{ $parent.botCommand }} help +
+
+ {{ $parent.activePeer.username }} is typing ... +
- BBcode Allowed +
+ + SHIFT + ENTER to insert new line + + + Type : for emoji + + + + BBcode Allowed + +
-
+
+ +
+
+ + + + + +
+
- Status: -   + +
+
+ -
-
-
- +
+ } + } + \ No newline at end of file diff --git a/resources/js/components/chat/ChatMessages.vue b/resources/js/components/chat/ChatMessages.vue index 3640caf625..b60a8b2b51 100644 --- a/resources/js/components/chat/ChatMessages.vue +++ b/resources/js/components/chat/ChatMessages.vue @@ -2,114 +2,156 @@
+ filters: { + fromNow (dt) { + return moment(String(dt)).fromNow() + } + }, + created () { + this.interval = setInterval(() => this.$forceUpdate(), 30000) + }, + beforeDestroy () { + clearInterval(this.interval) + } + } + \ No newline at end of file diff --git a/resources/js/components/chat/ChatPms.vue b/resources/js/components/chat/ChatPms.vue new file mode 100644 index 0000000000..5384fdc853 --- /dev/null +++ b/resources/js/components/chat/ChatPms.vue @@ -0,0 +1,93 @@ + + \ No newline at end of file diff --git a/resources/js/components/chat/ChatUserList.vue b/resources/js/components/chat/ChatUserList.vue new file mode 100644 index 0000000000..e08923574c --- /dev/null +++ b/resources/js/components/chat/ChatUserList.vue @@ -0,0 +1,58 @@ + + \ No newline at end of file diff --git a/resources/js/components/chat/Chatbox.vue b/resources/js/components/chat/Chatbox.vue index b4bda53bdf..6992f8713b 100644 --- a/resources/js/components/chat/Chatbox.vue +++ b/resources/js/components/chat/Chatbox.vue @@ -1,292 +1,884 @@ diff --git a/resources/js/components/chat/ChatroomsDropdown.vue b/resources/js/components/chat/ChatroomsDropdown.vue index 4b0bf9aece..61bb07a0eb 100644 --- a/resources/js/components/chat/ChatroomsDropdown.vue +++ b/resources/js/components/chat/ChatroomsDropdown.vue @@ -1,6 +1,7 @@