api->get('lookup', [ 'action' => $action, $action === 'port' ? 'port' : 'domain' => $value, ], (int) $serverId); return ($answer['site'] ?? null) ? (object) $answer['site'] : null; } /** The TV system, where refused links from it are sent back to. */ private const TV_URL = 'https://live.brascast.com'; /** Panel page each TV menu entry opens; anything else lands on the dashboard. */ private const TV_TARGETS = ['site' => 'site.home.r', 'emails' => 'emails.r']; public function index() { if(Auth::check() === false){ Auth::logout(); return redirect()->route('login'); } /* Check Suspensed */ $isSuspensed = (string) (SiteContext::current()->status ?? '') === '2'; if($isSuspensed){ Auth::logout(); session()->forget('serverID'); session()->forget('siteID'); return redirect()->to('https://account.brascast.com'); } /* Check Suspensed */ $userLogged = User::where('id', '=', Auth::id())->get()->first(); $allNotifications = DB::table('notifications')->orderBy('id','desc')->limit('3')->get(); $siteData = SiteContext::current(); $serverData = DB::table('sites_servers')->where('id','=',session('serverID'))->get()->first(); $logsData = DB::table('user_sites')->where('site_id','=',session('siteID'))->where('server_id','=',session('serverID'))->where('user_id','!=',Auth::id())->get(); $profile = $this->api->get('profile', ['action' => 'get']); $socialData = ($profile['social'] ?? null) ? (object) $profile['social'] : null; $contactData = ($profile['contact'] ?? null) ? (object) $profile['contact'] : null; /* uma ida so traz as tres pendencias e a grade do momento */ $panel = $this->api->get('dashboard', ['action' => 'get', 'day' => date('w'), 'time' => date('H:i')]); $pendReq = (int) ($panel['pending']['requests'] ?? 0); $pendMes = (int) ($panel['pending']['messages'] ?? 0); $pendCom = (int) ($panel['pending']['comments'] ?? 0); /* Scheduling Grid */ $onAir = ($panel['on_air'] ?? null) ? [(object) $panel['on_air']] : []; $nextAir = ($panel['next_air'] ?? null) ? [(object) $panel['next_air']] : []; $siteId = session('siteID'); $surveyCategories = null; if (!session()->has('admID') && isset($siteData->stream_port)) { //se for rádio, faz a pesquisa de categoria //$hasAnswer = DB::connection('mysql_central')->table('survey_radio_cat_answers')->where('site_id', $siteId)->exists(); //$hasAnswer = DB::connection('mysql_central')->table('survey_radio_cat_answers')->where('site_id', $siteId)->where('server_id', session('serverID'))->exists(); $hasAnswer = 1; if (!$hasAnswer) { $surveyCategories = DB::connection('mysql_central')->table('survey_radio_cat')->orderBy('id', 'asc')->get(); } } /* the last lines of the trail, for the card that opens the full screen */ $lastActivities = site_role() === 'owner' ? DB::table('user_logs')->where('site_id', '=', session('siteID')) ->where('server_id', '=', session('serverID')) ->orderByDesc('id')->limit(5)->get() : collect(); return view('dashboard', ['userLogged' => $userLogged , 'allNotifications' => $allNotifications, 'topHref' => 'general', 'lastActivities' => $lastActivities, 'siteData' => $siteData, 'serverData' => $serverData, 'socialData' => $socialData, 'contactData' => $contactData, 'logsData' => ($userLogged->type == '1' ? $logsData : null), 'pendReq' => $pendReq, 'pendMes' => $pendMes, 'pendCom' => $pendCom, 'onAir' => $onAir, 'nextAir' => $nextAir, 'onAirProgram' => ($panel['on_air_program'] ?? null) ? (object) $panel['on_air_program'] : null, 'nextProgram' => ($panel['next_air_program'] ?? null) ? (object) $panel['next_air_program'] : null, 'surveyCategories' => $surveyCategories]); } public function danEnter($port = null) { if(!$port){ return 'Tu ta doido é?'; } $dataCentral = DB::connection('mysql_central')->table('services')->where('port','like','%:'.$port)->get(); if(!$dataCentral->count()){return 'deu n';} $dataCentral = $dataCentral->first(); $siteServer = DB::table('site_server')->where('domain','=',$dataCentral->domain)->get(); if(!$siteServer->count()){ return 'aaaaaa'; } $serverData = DB::table('sites_servers')->where('id','=',$siteServer[0]->server_id)->get()->first(); $siteData = $this->siteBy('port', $port, $serverData->id); if(!$siteData){ return 'Não encontrei'; } Auth::guard('web')->logout(); Auth::guard('web')->loginUsingId($siteData->user_id); Session::put('siteID', $siteData->id); Session::put('serverID', $serverData->id); return redirect()->route('radio.home.r'); } public function radioRed(Request $request,$crypt = null) { $headers = getallheaders(); $hash = str_replace('|brasbar','/',$crypt); $dataD = EncryptBras($hash,'d'); $data = explode('|',$dataD); if(!$crypt || $headers['Origin'] != 'https://app.kshost.com.br'){ return redirect()->to('https://app.kshost.com.br/inicio'); } $serverData = DB::table('sites_servers')->where('name','=',$data[2])->get(); if($serverData->count()){ $serverData = $serverData->first(); $siteData = $this->siteBy('domain', $data[1], $serverData->id); if(!$siteData){ return redirect()->to('https://app.kshost.com.br/inicio'); } /*echo 'Vai logar no site: '.$siteData->domain.' - User:'.$siteData->user_id.' - Servidor:'.$serverData->name; exit();*/ Auth::guard('web')->logout(); Auth::guard('web')->loginUsingId($siteData->user_id); Session::put('siteID', $siteData->id); Session::put('serverID', $serverData->id); return redirect()->route('radio.home.r'); } } public function tvRed(Request $request,$crypt = null) { $headers = getallheaders(); $hash = str_replace('|brasbar','/',$crypt); $dataD = EncryptBras($hash,'d'); $data = explode('|',$dataD); if(!$crypt || $headers['Origin'] != 'https://tv.brascast.com'){ return redirect()->to('https://tv.brascast.com/dashboard?r=1'); } $serverData = DB::table('sites_servers')->where('name','=',$data[2])->get(); if($serverData->count()){ $serverData = $serverData->first(); $siteData = $this->siteBy('domain', $data[1], $serverData->id); if(!$siteData){ return redirect()->to('https://tv.brascast.com/dashboard?r=2'); } /*echo 'Vai logar no site: '.$siteData->domain.' - User:'.$siteData->user_id.' - Servidor:'.$serverData->name; exit();*/ $userData = DB::table('users')->where('email','=',(isset($data[3]) ? $data[3] : $siteData->user_id))->first(); if(!$userData){ return redirect()->to('https://tv.brascast.com/dashboard?r=3'); } Auth::guard('web')->logout(); Auth::guard('web')->loginUsingId($userData->id); Session::put('siteID', $siteData->id); Session::put('serverID', $serverData->id); return redirect()->route('site.home.r'); } } /** * Entry from the TV system (live.brascast.com) back into the panel. * * The encrypted link carries "tv name|tv site|target|email". The person is * signed in as themselves: the site owner, or an active administrator the * owner allowed into the TV. Every refusal returns to the TV dashboard with * the code the TV already understands. */ public function manageSiteTv(Request $request, $hash = null) { if (! $hash) { return redirect()->away(self::TV_URL); } if ($request->headers->get('referer') !== self::TV_URL . '/') { return $this->backToTv(0); } [$tvName, , $target, $email] = array_pad(explode('|', $this->openTvLink($hash)), 4, null); $link = $tvName ? DB::table('site_server')->where('stream_tv', '=', $tvName)->first() : null; $server = $link ? DB::table('sites_servers')->where('id', '=', $link->server_id)->first() : null; if (! $server) { return $this->backToTv(1); } $answer = $this->api->get('current', ['action' => 'get', 'app' => $tvName, 'id' => null], (int) $server->id); $site = ($answer['site'] ?? null) && (int) $answer['site']['id'] === (int) $link->site_id ? (object) $answer['site'] : null; if (! $site) { return $this->backToTv(2); } $user = $email ? User::where('email', '=', $email)->first() : null; if (! $user) { return $this->backToTv(3); } if (! can_open_tv($site, $user->id, $server->id)) { return $this->backToTv(4); } $isOwner = (int) $user->id === (int) $site->user_id; Auth::guard('web')->logout(); Auth::guard('web')->loginUsingId($user->id); Session::put('siteID', $site->id); Session::put('serverID', $server->id); Session::put('siteRole', $isOwner ? 'owner' : 'admin'); return redirect()->route(self::TV_TARGETS[$target] ?? 'dashboard.r'); } /** Plain text of the link, or empty when it does not decrypt: EncryptBras warns on garbage. */ private function openTvLink(string $hash): string { try { return (string) EncryptBras(str_replace('|brasbar', '/', $hash), 'd'); } catch (Throwable $e) { return ''; } } private function backToTv(int $code) { return redirect()->away(self::TV_URL . '/dashboard?e=' . $code); } public function plRed(Request $request) { if(isset($request->pl_id)){ DB::table('playlists')->where('id','=',$request->pl_id)->update([ 'redo' => '0' ]); } } public function managerLogin(Request $request, $hash = null) { if(!$hash){ return redirect()->to('https://account.brascast.com/manager/'); } $hash = str_replace('|brasbar','/',$hash); $referer = $request->headers->get('referer'); if($referer == env('CENTRAL_URL', 'https://account.brascast.com/')){ return 'OOps'; } $dataHash = explode('|',EncryptBras($hash,'d')); $serverSite = $serverData = DB::table('site_server')->where('domain','=',$dataHash[0])->get(); if(!$serverSite){ return 'Não consegui acessar o server do site: '.$dataHash[0].'!'; } $serverData = $serverData->first(); $siteData = $this->siteBy('domain', $dataHash[0], $serverData->server_id); if(!$siteData){ return 'Não consegui acessar este site: '.$dataHash[0].', fala com Edinaldo ai!'; } Auth::guard('web')->logout(); Auth::guard('web')->loginUsingId($siteData->user_id); Session::put('siteID', $siteData->id); Session::put('serverID', $serverData->server_id); Session::put('admID', $dataHash[1]); return redirect()->route('site.home.r'); } public function login() { return view('login'); /* $post = New User(); $post->name = "Edinaldo Filho"; $post->email = "naldowd@gmail.com"; $post->password = bcrypt('edinaldo1'); $post->save();*/ } public function doLogin(Request $request) { if($request->email == '' && $request->password == ''){ $json = array( 'message_email' => __('general.login_msg_error_empty_email'), 'message_password' => __('general.login_msg_error_empty_password'), "error" => '1'); return response()->json($json); } if(!filter_var($request->email, FILTER_VALIDATE_EMAIL)){ $json = array('message_email' => __('general.login_msg_error_email'), "error" => '2'); return response()->json($json); } $credentials = [ 'email' => $request->email, 'password' => $request->password ]; /* remember me was on the screen but never reached here */ if(!Auth::attempt($credentials, (bool) $request->boolean('remember'))){ $json = array('message' => __('general.login_msg_error_password'), "error" => '3'); return response()->json($json); } /** * Blocked only when there is nothing to open: no site of their own and * no accepted invite. The old test read users.type, a stamp written * once at sign up, so an invited admin who later bought a radio was * refused entry to a site that is genuinely theirs. */ if(!user_site_links(Auth::id())){ Auth::logout(); $json = array('message' => __('general.login_msg_error_adm_verify'), "error" => '4'); return response()->json($json); } DB::table('users')->where('id','=',Auth::id())->update(['last_login' => NOW()]); $json = array('redirect' => route('selectSite'), "error" => false); return response()->json($json); } public function logout() { Auth::logout(); session()->forget('serverID'); session()->forget('siteID'); return redirect()->route('login'); } public function logAs($id) { if(!$id){ return redirect()->route('login'); } $verifyUser = DB::table('users')->where('id','=',$id)->get(); if(!$verifyUser->count()){ return redirect()->route('login'); } Auth::guard('web')->logout(); Auth::guard('web')->loginUsingId($id); return redirect()->route('selectSite'); } public function homeAjax(Request $request) { if(Auth::check() === false){ Auth::logout(); return redirect()->route('login'); } $array = array('tiktok','instagram','xtwitter','facebook','outra'); if(!in_array($request->sea_opt, $array)){ return response()->json(array('status' => false), 200); } DB::table('search')->where('slug','=',$request->sea_opt)->increment('votes'); $this->api->post('profile', ['action' => 'flag', 'flag' => 'first_vote', 'value' => '1']); return response()->json(array('status' => true), 200); } public function homeCatAjax(Request $request) { $validator = Validator::make($request->all(), [ 'sea_opt' => 'required', 'sea_text' => 'required_if:sea_opt,1|max:255', ]); if ($validator->fails()) { return response()->json(['success' => false, 'message' => $validator->errors()->first()], 422); } try { $siteId = session('siteID'); $serverId = session('serverID'); if (!$siteId || !$serverId) { return response()->json(['success' => false, 'message' => 'Sessão inválida.'], 401); } $siteData = SiteContext::current((int) $siteId, (int) $serverId); if (!$siteData || empty($siteData->stream_port)) { return response()->json(['success' => false, 'message' => 'Entre em contato com o Suporte, por gentileza.'], 400); } $port = $siteData->stream_port; $service = DB::connection('mysql_central')->table('services')->where('port', 'REGEXP', ':'.$port.'$')->first(); if (!$service) { return response()->json(['success' => false, 'message' => 'Serviço central não localizado.'], 404); } $exists = DB::connection('mysql_central')->table('survey_radio_cat_answers')->where('site_id', $siteId)->where('server_id', $serverId)->exists(); if (!$exists) { DB::connection('mysql_central') ->table('survey_radio_cat_answers') ->insert([ 'site_id' => $siteId, 'service_id' => $service->id, 'server_id' => $serverId, 'answer_option_id' => (int) $request->sea_opt, 'other' => ($request->sea_opt == "1") ? $request->sea_text : null, 'created_at' => now(), ]); } return response()->json(['success' => true]); } catch (\Exception $e) { return response()->json(['success' => false, 'message' => 'Erro interno: ' . $e->getMessage()], 500); } } public function select() { if(Auth::check() === false){ Auth::logout(); return redirect()->route('login'); } $userLogged = User::where('id', '=', Auth::id())->get()->first(); // an invite still waiting for the e-mail confirmation must not be listed $allSites = collect(user_site_links($userLogged->id))->map(fn ($l) => (object) $l); session()->forget('serverID'); session()->forget('siteID'); return view('selectSite', [ 'userLogged' => $userLogged, 'topHref' => null, 'allSites' => $allSites, 'stations' => $this->stationsOf($allSites), ]); } /** * Name and domain of each station the user can manage. * * The pair in site_server is what selectAs accepts, but its domain column * is a stale copy: what the screen shows comes from the site itself, one * query per server instead of one per link. */ private function stationsOf($links) { $out = []; foreach ($links->groupBy('server_id') as $serverId => $group) { $ids = $group->pluck('site_id')->all(); $linked = DB::table('site_server')->where('server_id', '=', $serverId) ->whereIn('site_id', $ids)->pluck('site_id', 'site_id'); $answer = $this->api->get('lookup', ['action' => 'many', 'ids' => implode(',', $ids)], (int) $serverId); $sites = collect($answer['sites'] ?? [])->map(fn ($row) => (object) $row); foreach ($group as $link) { if (! isset($linked[$link->site_id])) { continue; } $site = $sites[$link->site_id] ?? null; $name = trim((string) ($site->name ?? '')); $domain = trim((string) ($site->domain ?? '')); $out[] = [ 'site_id' => $link->site_id, 'server_id' => $link->server_id, 'name' => $name !== '' ? $name : ($domain !== '' ? $domain : __('general.selectsite_unnamed', ['id' => $link->site_id])), 'domain' => $name !== '' ? $domain : '', ]; } } usort($out, fn ($a, $b) => strcasecmp($a['name'], $b['name'])); return $out; } public function selectAs($id = null,$server = null) { if(Auth::check() === false){ Auth::logout(); return redirect()->route('login'); } $userLogged = User::where('id', '=', Auth::id())->get()->first(); if(!$id){ return redirect()->route('selectSite'); } $getServerID = DB::table('site_server')->where('site_id','=',$id)->where('server_id','=',$server)->get()->first(); if(!$getServerID){ return redirect()->route('selectSite'); } /** * The pair decides, never the id alone: the same site_id exists on more * than one server. An unconfirmed invite is filtered out here too, so * the gate lives with the relationship instead of with users.type. */ $allowed = collect(user_site_links($userLogged->id)) ->firstWhere(fn ($l) => $l['site_id'] == $id && $l['server_id'] == $getServerID->server_id); if($allowed){ Session::put('siteID', $id); Session::put('serverID', $getServerID->server_id); Session::put('siteRole', $allowed['role']); if($allowed['role'] === 'admin'){ DB::table('site_administrators') ->where('server_id','=',$getServerID->server_id) ->where('user_id','=',$userLogged->id)->where('site_id','=',$id) ->update(['last_login' => NOW()]); } return redirect()->route('dashboard.r'); } return redirect()->route('selectSite'); } public function firstAccess() { if(Auth::check() === false){ Auth::logout(); return redirect()->route('login'); } return redirect()->route('dashboard.r'); $verifyFirst = (string) ($this->api->get('profile', ['action' => 'flag', 'flag' => 'first_access'])['value'] ?? '0') === '1'; if($verifyFirst){ return redirect()->route('dashboard.r'); } $this->api->post('profile', ['action' => 'flag', 'flag' => 'first_access', 'value' => '1']); $this->api->post('profile', ['action' => 'flag', 'flag' => 'first_access', 'value' => '1']); $userLogged = User::where('id', '=', Auth::id())->get()->first(); return view('firstAccess', ['userLogged' => $userLogged]); } public function redirect(Request $request,$crypt = null,$trial = false) { $dataHash = explode('|',EncryptBras($request->hash,'d')); $centralOrigin = env('CENTRAL_URL', 'https://account.brascast.com'); $origin = $_SERVER['HTTP_ORIGIN'] ?? null; if(!$crypt || $origin !== $centralOrigin){ return redirect()->route('login'); } $getServerID = DB::table('site_server')->where('domain','=',$dataHash[0])->get()->first(); if(!$getServerID){ return redirect()->route('login'); } $siteRow = $this->siteBy('domain', $dataHash[0], $getServerID->server_id); if(!$siteRow){ return redirect()->route('login'); } /** * The domain is the reliable key here, not the e-mail. Central owns the * e-mail and the panel only mirrors it, so a change that failed to sync * left the legitimate owner unable to enter. The site row already names * its owner, so we resolve by owner and heal the stale mirror. */ $verifyUser = DB::table('users')->where('email','=',$dataHash[1])->get(); if($verifyUser->count() == 0){ $owner = DB::table('users')->where('id','=',$siteRow->user_id)->first(); $taken = $owner ? DB::table('users')->where('email','=',$dataHash[1])->where('id','!=',$owner->id)->exists() : true; if(!$owner || $taken){ return redirect()->route('login'); } DB::table('users')->where('id','=',$owner->id)->update(['email' => $dataHash[1]]); Log::info('e-mail do painel ressincronizado com a central', [ 'user_id' => $owner->id, 'de' => $owner->email, 'para' => $dataHash[1], ]); $verifyUser = DB::table('users')->where('id','=',$owner->id)->get(); } $domainSite = $this->siteBy('domain', $dataHash[0], $getServerID->server_id); $verifySite = collect($domainSite && (int) $domainSite->user_id === (int) $verifyUser[0]->id ? [$domainSite] : []); if($verifyUser->count() && $verifySite->count()){ Auth::guard('web')->logout(); Auth::guard('web')->loginUsingId($verifyUser[0]->id); Session::put('siteID', $verifySite[0]->id); Session::put('serverID', $getServerID->server_id); if(isset($dataHash[2])){Session::put('admID', $dataHash[2]);} /* FIRST ACCESS */ $verifyFirst = (string) ($this->api->get('profile', ['action' => 'flag', 'flag' => 'first_access'])['value'] ?? '0') === '1'; if(!$verifyFirst && !$trial) { return redirect()->route('firstAccess'); } /* FIRST ACCESS */ DB::table('users')->where('id','=',Auth::id())->update(['last_login' => NOW()]); return view('redirect'); } } public function profile() { if(Auth::check() === false){ Auth::logout(); return redirect()->route('login'); } $userLogged = User::where('id', '=', Auth::id())->get()->first(); $allNotifications = DB::table('notifications')->orderBy('id','desc')->limit('3')->get(); $siteData = SiteContext::current(); return view('profile', ['userLogged' => $userLogged , 'allNotifications' => $allNotifications, 'topHref' => 'general', 'siteData' => $siteData]); } public function doProfile(Request $request) { if(Auth::check() === false){ Auth::logout(); return redirect()->route('login'); } $data = []; // FILTER_SANITIZE_STRING saiu de linha no PHP 8.1 e so emitia deprecated $name = trim(strip_tags((string) $request->input('name'))); if ($name !== '') { $data['name'] = mb_substr($name, 0, 255); } $lang = (string) $request->input('lang'); if (in_array($lang, config('app.available_locales', []), true)) { $data['lang'] = $lang; } $theme = (string) $request->input('theme'); /** * A coluna e conferida antes de gravar: assim o painel continua de pe * entre o deploy e o ALTER que a cria, em vez de derrubar o perfil de * todo mundo com erro de coluna inexistente. */ if (in_array($theme, user_themes(), true) && Schema::hasColumn('users', 'theme')) { $data['theme'] = $theme; } if ($data) { DB::table('users')->where('id', '=', Auth::id())->update($data); } return redirect()->route('profile')->with('success', __('general.profile_saved')); } public function stations() { if(Auth::check() === false){ Auth::logout(); return redirect()->route('login'); } $userLogged = User::where('id', '=', Auth::id())->get()->first(); // owning a site is what opens this screen, not the users.type stamp if(!user_owns_any_site($userLogged->id)){ return redirect()->route('selectSite'); } $allNotifications = DB::table('notifications')->orderBy('id','desc')->limit('3')->get(); $siteData = SiteContext::current(); /** * Rows are resolved here, grouped per server, because the view used to * run two queries per line. Excluded by the pair: the same site_id also * exists on other servers. */ $links = collect(user_site_links($userLogged->id)) ->reject(fn ($l) => $l['site_id'] == session('siteID') && $l['server_id'] == session('serverID')); $allAdmSites = collect(); foreach ($links->groupBy('server_id') as $serverId => $group) { $ids = collect($group)->pluck('site_id')->all(); $answer = $this->api->get('lookup', ['action' => 'many', 'ids' => implode(',', $ids), 'fields' => 'full'], (int) $serverId); $rows = collect($answer['sites'] ?? [])->map(fn ($row) => (object) $row); foreach ($group as $link) { $row = $rows[$link['site_id']] ?? null; if (! $row) { continue; } $allAdmSites->push((object) [ 'site_id' => $link['site_id'], 'server_id' => $link['server_id'], 'role' => $link['role'], 'name' => $row->name, 'domain' => $row->domain, 'status' => $row->status, 'avatar' => $row->avatar, ]); } } $allAdmSites = $allAdmSites->sortBy('name')->values(); $allServersSite = DB::table('sites_servers')->get(); return view('stations', ['userLogged' => $userLogged , 'allNotifications' => $allNotifications, 'topHref' => 'general', 'siteData' => $siteData, 'allAdmSites' => $allAdmSites, 'allServersSite' => $allServersSite]); } public function selectStation($id = null, $server = null) { if(Auth::check() === false){ Auth::logout(); return redirect()->route('login'); } if(!$id){return redirect()->route('stations.r');} $userLogged = User::where('id', '=', Auth::id())->get()->first(); /** * The server has to come with the id. Looking site_server up by site_id * alone returned whichever row came first, so a site with the same id * on another server could be opened by mistake. */ $link = collect(user_site_links($userLogged->id)) ->firstWhere(fn ($l) => $l['site_id'] == $id && (!$server || $l['server_id'] == $server)); if(!$link){ return redirect()->route('stations.r'); } Session::put('siteID', $link['site_id']); Session::put('serverID', $link['server_id']); Session::put('siteRole', $link['role']); return redirect()->route('dashboard.r'); } public function noPermission() { if(Auth::check() === false){ Auth::logout(); return redirect()->route('login'); } $userLogged = User::where('id', '=', Auth::id())->get()->first(); $allNotifications = DB::table('notifications')->orderBy('id','desc')->limit('3')->get(); return view('noPermission', ['userLogged' => $userLogged , 'allNotifications' => $allNotifications, 'topHref' => null]); } }