Example #1
0
 /**
  * Makes authenticated requests to the DeviantArt API
  *
  * @param string      $endpoint
  * @param null|array  $postdata
  * @param null|string $token
  *
  * @return array
  */
 static function request($endpoint, $token = null, $postdata = null)
 {
     global $signedIn, $currentUser, $http_response_header;
     $requestHeaders = array("Accept-Encoding: gzip", "User-Agent: MLPVC-RR @ " . GITHUB_URL);
     if (!isset($token) && $signedIn) {
         $token = $currentUser->Session['access'];
     }
     if (!empty($token)) {
         $requestHeaders[] = "Authorization: Bearer {$token}";
     } else {
         if ($token !== false) {
             return null;
         }
     }
     $requestURI = preg_match(new RegExp('^https?://'), $endpoint) ? $endpoint : "https://www.deviantart.com/api/v1/oauth2/{$endpoint}";
     $r = curl_init($requestURI);
     $curl_opt = array(CURLOPT_RETURNTRANSFER => 1, CURLOPT_HTTPHEADER => $requestHeaders, CURLOPT_HEADER => 1, CURLOPT_BINARYTRANSFER => 1);
     if (!empty($postdata)) {
         $query = array();
         foreach ($postdata as $k => $v) {
             $query[] = urlencode($k) . '=' . urlencode($v);
         }
         $curl_opt[CURLOPT_POST] = count($postdata);
         $curl_opt[CURLOPT_POSTFIELDS] = implode('&', $query);
     }
     curl_setopt_array($r, $curl_opt);
     $response = curl_exec($r);
     $responseCode = curl_getinfo($r, CURLINFO_HTTP_CODE);
     $headerSize = curl_getinfo($r, CURLINFO_HEADER_SIZE);
     $responseHeaders = rtrim(CoreUtils::substring($response, 0, $headerSize));
     $response = CoreUtils::substring($response, $headerSize);
     $http_response_header = array_map("rtrim", explode("\n", $responseHeaders));
     $curlError = curl_error($r);
     curl_close($r);
     self::$requestCount++;
     if ($responseCode < 200 || $responseCode >= 300) {
         throw new CURLRequestException(rtrim("cURL fail for URL \"{$requestURI}\" (HTTP {$responseCode}); {$curlError}", ' ;'), $responseCode);
     }
     if (preg_match(new RegExp('Content-Encoding:\\s?gzip'), $responseHeaders)) {
         $response = gzdecode($response);
     }
     return JSON::decode($response);
 }
Example #2
0
 /**
  * Checks if a deviation is in the club
  *
  * @param int|string $DeviationID
  *
  * @return bool|int
  */
 static function isDeviationInClub($DeviationID)
 {
     if (!is_int($DeviationID)) {
         $DeviationID = intval(CoreUtils::substring($DeviationID, 1), 36);
     }
     try {
         $DiFiRequest = HTTP::legitimateRequest("http://deviantart.com/global/difi/?c[]=\"DeviationView\",\"getAllGroups\",[\"{$DeviationID}\"]&t=json");
     } catch (CURLRequestException $e) {
         return $e->getCode();
     }
     if (empty($DiFiRequest['response'])) {
         return 1;
     }
     $DiFiRequest = @JSON::decode($DiFiRequest['response'], JSON::AS_OBJECT);
     if (empty($DiFiRequest->DiFi->status)) {
         return 2;
     }
     if ($DiFiRequest->DiFi->status !== 'SUCCESS') {
         return 3;
     }
     if (empty($DiFiRequest->DiFi->response->calls)) {
         return 4;
     }
     if (empty($DiFiRequest->DiFi->response->calls[0])) {
         return 5;
     }
     if (empty($DiFiRequest->DiFi->response->calls[0]->response)) {
         return 6;
     }
     if (empty($DiFiRequest->DiFi->response->calls[0]->response->status)) {
         return 7;
     }
     if ($DiFiRequest->DiFi->response->calls[0]->response->status !== 'SUCCESS') {
         return 8;
     }
     if (empty($DiFiRequest->DiFi->response->calls[0]->response->content->html)) {
         return 9;
     }
     $html = $DiFiRequest->DiFi->response->calls[0]->response->content->html;
     return strpos($html, 'gmi-groupname="MLP-VectorClub">') !== false;
 }
Example #3
0
 /**
  * Format log entry details
  *
  * @param array $MainEntry Main log entry
  * @param array $data      Data to process (sub-log entry)
  *
  * @return array
  */
 static function formatEntryDetails($MainEntry, $data)
 {
     global $Database, $CGDb;
     $details = array();
     $reftype = $MainEntry['reftype'];
     switch ($reftype) {
         case "rolechange":
             /** @var $target User */
             $target = $Database->where('id', $data['target'])->getOne('users');
             $details = array(array('Target user', $target->getProfileLink()), array('Old group', Permission::ROLES_ASSOC[$data['oldrole']]), array('New group', Permission::ROLES_ASSOC[$data['newrole']]));
             break;
         case "episodes":
             $details[] = array('Action', self::$ACTIONS[$data['action']]);
             $details[] = array('Name', (new Episode($data))->formatTitle());
             if ($data['season'] === 0) {
                 $details[] = array('Overall', "#{$data['episode']}");
             }
             if (!empty($data['airs'])) {
                 $details[] = array('Air date', Time::tag($data['airs'], Time::TAG_EXTENDED, Time::TAG_STATIC_DYNTIME));
             }
             $details[] = array('Two parts', !empty($data['twoparter']));
             break;
         case "episode_modify":
             $link = $data['target'];
             $EpData = Episodes::parseID($data['target']);
             if (!empty($EpData)) {
                 $Episode = Episodes::getActual($EpData['season'], $EpData['episode'], Episodes::ALLOW_MOVIES);
                 if (!empty($Episode)) {
                     $link = "<a href='" . $Episode->formatURL() . "'>" . $Episode->formatTitle(AS_ARRAY, 'id') . "</a>";
                 }
             }
             $details[] = array('Episode', $link);
             if (empty($Episode)) {
                 $details[] = array('Still exists', false);
             }
             unset($data['entryid'], $data['target']);
             $newOld = self::_arrangeNewOld($data);
             if (!empty($newOld['airs'])) {
                 $newOld['airs']['old'] = Time::tag($newOld['airs']['old'], Time::TAG_EXTENDED, Time::TAG_STATIC_DYNTIME);
                 $newOld['airs']['new'] = Time::tag($newOld['airs']['new'], Time::TAG_EXTENDED, Time::TAG_STATIC_DYNTIME);
             }
             if (isset($newOld['title']['old']) && isset($newOld['title']['new'])) {
                 $details[] = array('Title', self::charDiff($newOld['title']['old'], $newOld['title']['new']));
                 unset($newOld['title']);
             }
             foreach ($newOld as $thing => $ver) {
                 $details[] = array("Old {$thing}", $ver['old']);
                 $details[] = array("New {$thing}", $ver['new']);
             }
             break;
         case "userfetch":
             $details[] = array('User', Users::get($data['userid'])->getProfileLink());
             break;
         case "banish":
         case "un-banish":
             $details[] = array('User', Users::get($data['target'])->getProfileLink());
             $details[] = array('Reason', CoreUtils::escapeHTML($data['reason']));
             break;
         case "post_lock":
             $Post = $Database->where('id', $data['id'])->getOne("{$data['type']}s");
             self::_genericPostInfo($Post, $data, $details);
             break;
         case "color_modify":
             $details[] = array('Appearance', self::_getAppearanceLink($data['ponyid']));
             $details[] = array('Reason', CoreUtils::escapeHTML($data['reason']));
             break;
         case "req_delete":
             $details[] = array('Request ID', $data['id']);
             $typeNames = array('chr' => 'Character', 'obj' => 'Object', 'bg' => 'Background');
             $details[] = array('Description', CoreUtils::escapeHTML($data['label']));
             $details[] = array('Type', $typeNames[$data['type']]);
             $IDstr = "S{$data['season']}E{$data['episode']}";
             $details[] = array('Episode', "<a href='/episode/{$IDstr}'>{$IDstr}</a>");
             $details[] = array('Posted', Time::tag($data['posted'], Time::TAG_EXTENDED, Time::TAG_STATIC_DYNTIME));
             if (!empty($data['requested_by'])) {
                 $details[] = array('Requested by', Users::get($data['requested_by'])->getProfileLink());
             }
             if (!empty($data['reserved_by'])) {
                 $details[] = array('Reserved by', Users::get($data['reserved_by'])->getProfileLink());
             }
             $details[] = array('Finished', !empty($data['deviation_id']));
             if (!empty($data['deviation_id'])) {
                 $details[] = array('Deviation', self::_link("http://fav.me/{$data['deviation_id']}"));
                 $details[] = array('Approved', $data['lock']);
             }
             break;
         case "img_update":
             $Post = $Database->where('id', $data['id'])->getOne("{$data['thing']}s");
             $data['type'] = $data['thing'];
             self::_genericPostInfo($Post, $data, $details);
             $details[] = array('Old image', "<a href='{$data['oldfullsize']}' target='_blank'>Full size</a><div><img src='{$data['oldpreview']}'></div>");
             $details[] = array('New image', "<a href='{$data['newfullsize']}' target='_blank'>Full size</a><div><img src='{$data['newpreview']}'></div>");
             break;
         case "res_overtake":
             $Post = $Database->where('id', $data['id'])->getOne("{$data['type']}s");
             self::_genericPostInfo($Post, $data, $details);
             $details[] = array('Previous reserver', Users::get($data['reserved_by'])->getProfileLink());
             $details[] = array('Previously reserved at', Time::tag($data['reserved_at'], Time::TAG_EXTENDED, Time::TAG_STATIC_DYNTIME));
             $diff_text = '';
             $diff = Time::difference(strtotime($MainEntry['timestamp']), strtotime($data['reserved_at']));
             foreach (array_keys(Time::$IN_SECONDS) as $unit) {
                 if (empty($diff[$unit])) {
                     continue;
                 }
                 $diff_text .= CoreUtils::makePlural($unit, $diff[$unit], PREPEND_NUMBER) . ' ';
             }
             $details[] = array('In progress for', rtrim($diff_text));
             break;
         case "appearances":
             $details[] = array('Action', self::$ACTIONS[$data['action']]);
             $PonyGuide = empty($data['ishuman']);
             $details[] = array('Guide', $PonyGuide ? 'Pony' : 'EQG');
             $details[] = array('ID', self::_getAppearanceLink($data['id']));
             $details[] = array('Label', $data['label']);
             if (!empty($data['order'])) {
                 $details[] = array('Ordering index', $data['order']);
             }
             if (!empty($data['notes'])) {
                 $details[] = array('Notes', '<div>' . nl2br($data['notes']) . '</div>');
             }
             if (!empty($data['cm_favme'])) {
                 $details[] = array('CM Submission', self::_link("http://fav.me/{$data['cm_favme']}"));
                 $details[] = array('CM Orientation', CGUtils::$CM_DIR[$data['cm_dir']]);
                 if (!empty($data['cm_preview'])) {
                     $details[] = array('Custom CM Preview', "<img src='" . CoreUtils::aposEncode($data['cm_preview']) . "'>");
                 }
             }
             if (!empty($data['usetemplate'])) {
                 $details[] = array('Template applied', true);
             }
             $details[] = array('Private', !empty($data['private']));
             if (!empty($data['added'])) {
                 $details[] = array('Added', Time::tag($data['added'], Time::TAG_EXTENDED, Time::TAG_STATIC_DYNTIME));
             }
             break;
         case "res_transfer":
             $Post = $Database->where('id', $data['id'])->getOne("{$data['type']}s");
             self::_genericPostInfo($Post, $data, $details);
             $details[] = array('New reserver', Users::get($data['to'])->getProfileLink());
             break;
         case "cg_modify":
             $details[] = array('Appearance', self::_getAppearanceLink($data['ponyid']));
             $CG = $CGDb->where('groupid', $data['groupid'])->getOne('colorgroups');
             if (empty($CG)) {
                 $details[] = array('Color group ID', '#' . $data['groupid']);
                 $details[] = array('Still exists', false);
             } else {
                 $details[] = array('Group', "{$CG['label']} (#{$data['groupid']})");
             }
             if (isset($data['newlabel'])) {
                 $details[] = array('Label', self::charDiff($data['oldlabel'] ?? '', $data['newlabel']));
             }
             if (isset($data['newcolors'])) {
                 $details[] = array('Colors', self::charDiff($data['oldcolors'] ?? '', $data['newcolors'], 'block'));
             }
             break;
         case "cgs":
             $details[] = array('Action', self::$ACTIONS[$data['action']]);
             $details[] = array('Color group ID', '#' . $data['groupid']);
             $details[] = array('Label', $data['label']);
             $details[] = array('Appearance', self::_getAppearanceLink($data['ponyid']));
             if (isset($data['order'])) {
                 $details[] = array('Ordering index', $data['order']);
             }
             break;
         case "cg_order":
             $details[] = array('Appearance', self::_getAppearanceLink($data['ponyid']));
             $details[] = array('Order', self::charDiff($data['oldgroups'], $data['newgroups'], 'block'));
             break;
         case "appearance_modify":
             $details[] = array('Appearance', self::_getAppearanceLink($data['ponyid']));
             $changes = JSON::decode($data['changes']);
             $newOld = self::_arrangeNewOld($changes);
             if (isset($newOld['label']['new'])) {
                 $details[] = array('Label', self::charDiff($newOld['label']['old'], $newOld['label']['new'], 'block'));
             }
             if (isset($newOld['notes']['new']) || isset($newOld['notes']['old'])) {
                 $details[] = array('Notes', self::charDiff($newOld['notes']['old'] ?? '', $newOld['notes']['new'] ?? '', 'block smaller'));
             }
             if (isset($newOld['cm_favme']['old'])) {
                 $details[] = array('Old CM Submission', self::_link('http://fav.me/' . $newOld['cm_favme']['old']));
             } else {
                 if (isset($newOld['cm_favme']['new'])) {
                     $details[] = array('Old CM Submission', null);
                 }
             }
             if (isset($newOld['cm_favme']['new'])) {
                 $details[] = array('New CM Submission', self::_link('http://fav.me/' . $newOld['cm_favme']['new']));
             } else {
                 if (isset($newOld['cm_favme']['old'])) {
                     $details[] = array('New CM Submission', null);
                 }
             }
             $olddir = isset($newOld['cm_dir']['old']) ? CGUtils::$CM_DIR[$newOld['cm_dir']['old']] : '';
             $newdir = isset($newOld['cm_dir']['new']) ? CGUtils::$CM_DIR[$newOld['cm_dir']['new']] : '';
             if ($olddir || $newdir) {
                 $details[] = array('CM Orientation', self::charDiff($olddir, $newdir, 'inline', new FineDiff\Granularity\Paragraph()));
             }
             if (isset($newOld['private']['new'])) {
                 $details[] = array('<span class="typcn typcn-lock-' . ($newOld['private']['new'] ? 'closed' : 'open') . '"></span> ' . ($newOld['private']['new'] ? 'Marked private' : 'No longer private'), self::SKIP_VALUE, self::KEYCOLOR_INFO);
             }
             if (isset($newOld['cm_preview']['new'])) {
                 $details[] = array('New Custom CM Preview', "<img src='" . CoreUtils::aposEncode($newOld['cm_preview']['new']) . "'>");
             } else {
                 if (isset($newOld['cm_preview']['old'])) {
                     $details[] = array('New Custom CM Preview', null);
                 }
             }
             break;
         case "da_namechange":
             $User = Users::get($data['id'], 'id', 'name');
             $newIsCurrent = $User->name === $data['new'];
             $details[] = array('User', $User->getProfileLink());
             if ($newIsCurrent) {
                 $details[] = array('Old name', $data['old']);
             } else {
                 $details[] = array('Name', Logs::charDiff($data['old'], $data['new']));
             }
             break;
         case "video_broken":
             $IDstr = "S{$data['season']}E{$data['episode']}";
             $details[] = array('Episode', "<a href='/episode/{$IDstr}'>{$IDstr}</a>");
             $url = VideoProvider::getEmbed(new EpisodeVideo(array('provider' => $data['provider'], 'id' => $data['id'])), VideoProvider::URL_ONLY);
             $details[] = array('Link', "<a href='{$url}'>{$url}</a>");
             break;
         default:
             $details[] = array('<span class="typcn typcn-warning"></span> Couldn\'t process details', 'No data processor defined for this entry type', self::KEYCOLOR_ERROR);
             $details[] = array('Raw details', '<pre>' . var_export($data, true) . '</pre>');
             break;
     }
     return array('details' => $details);
 }
Example #4
0
 /**
  * Redirection
  *
  * @param string $url  Redirection target URL
  * @param int    $http HTTP status code
  */
 public static function redirect($url = '/', $http = 301)
 {
     header("Location: {$url}", true, $http);
     $urlenc = CoreUtils::aposEncode($url);
     die("Click <a href='{$urlenc}'>here</a> if you aren't redirected.<script>location.replace(" . JSON::encode($url) . ")</script>");
 }
Example #5
0
         $response['notes'] = Appearances::getNotesHTML($EditedAppearance, NOWRAP);
     }
     Response::done($response);
     break;
 case "delete":
     if ($Appearance['id'] === 0) {
         Response::fail('This appearance cannot be deleted');
     }
     $Tagged = Tags::getFor($Appearance['id'], null, true, false);
     if (!$CGDb->where('id', $Appearance['id'])->delete('appearances')) {
         Response::dbError();
     }
     try {
         CoreUtils::elasticClient()->delete(Appearances::toElasticArray($Appearance, true));
     } catch (ElasticMissing404Exception $e) {
         $message = JSON::decode($e->getMessage());
         // Eat error if appearance was not indexed
         if ($message['found'] !== false) {
             throw $e;
         }
     } catch (ElasticNoNodesAvailableException $e) {
         error_log('ElasticSearch server was down when server attempted to remove appearance ' . $Appearance['id']);
     }
     if (!empty($Tagged)) {
         foreach ($Tagged as $tag) {
             Tags::updateUses($tag['tid']);
         }
     }
     $fpath = APPATH . "img/cg/{$Appearance['id']}.png";
     if (file_exists($fpath)) {
         unlink($fpath);
Example #6
0
	<link rel="icon" type="image/png" href="/img/favicons-v1/favicon-16x16.png" sizes="16x16">
	<link rel="manifest" href="/img/favicons-v1/manifest.json">
	<link rel="mask-icon" href="/img/favicons-v1/safari-pinned-tab.svg" color="#2c73b1">
	<meta name="apple-mobile-web-app-title" content="MLP-VectorClub">
	<meta name="application-name" content="MLP-VectorClub">
	<meta name="msapplication-TileColor" content="#2c73b1">
	<meta name="msapplication-TileImage" content="/img/favicons-v1/mstile-144x144.png">
	<meta name="msapplication-config" content="/img/favicons-v1/browserconfig.xml">

	<link rel="shortcut icon" href="/favicon.ico">
<?php 
if (isset($norobots)) {
    echo '<meta name="robots" content="noindex, nofollow">';
}
if (isset($redirectto)) {
    echo '<script>history.replaceState&&history.replaceState(history.state,"",' . JSON::encode($redirectto) . ')</script>' . "\n";
}
if (isset($customCSS)) {
    foreach ($customCSS as $css) {
        echo "<link rel='stylesheet' href='{$css}'>\n";
    }
}
if (!empty(GA_TRACKING_CODE) && Permission::insufficient('developer')) {
    ?>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create','<?php 
Example #7
0
 private function _getDirectUrl($id)
 {
     switch ($this->provider) {
         case 'imgur':
             $this->fullsize = "https://i.imgur.com/{$id}.png";
             $this->preview = "https://i.imgur.com/{$id}m.png";
             self::_checkImageAllowed($this->fullsize);
             break;
         case 'derpibooru':
             $Data = @file_get_contents("http://derpibooru.org/{$id}.json");
             if (empty($Data)) {
                 throw new \Exception('The requested image could not be found on Derpibooru');
             }
             $Data = JSON::decode($Data);
             if (isset($Data['duplicate_of'])) {
                 return $this->_getDirectUrl($Data['duplicate_of']);
             }
             if (!isset($Data['is_rendered'])) {
                 error_log("Invalid Derpibooru response for ID {$id}\n" . var_export($Data, true));
                 throw new \Exception('Derpibooru returned an invalid API response. This issue has been logged, please <a class="send-feedback">remind us</a> to take a look.');
             }
             if (!$Data['is_rendered']) {
                 throw new \Exception('The image was found but it hasn\'t been rendered yet. Please wait for it to render and try again shortly.');
             }
             $this->fullsize = $Data['representations']['full'];
             $this->preview = $Data['representations']['small'];
             self::_checkImageAllowed($this->fullsize, $Data['mime_type']);
             break;
         case 'puush':
             $path = "http://puu.sh/{$id}";
             $image = @file_get_contents($path);
             if (empty($image) || $image === 'That puush could not be found.') {
                 throw new \Exception('The requested image could not be found on Puu.sh');
             }
             if ($image === 'You do not have access to view that puush.') {
                 throw new \Exception('The requested image is a private Puu.sh and the token is missing from the URL');
             }
             self::_checkImageAllowed($path);
             $this->fullsize = $this->preview = $path;
             break;
         case 'dA':
         case 'fav.me':
         case 'sta.sh':
             if ($this->provider === 'dA') {
                 $id = 'd' . base_convert($id, 10, 36);
                 $this->provider = 'fav.me';
             }
             try {
                 $CachedDeviation = DeviantArt::getCachedSubmission($id, $this->provider);
                 if (!DeviantArt::isImageAvailable($CachedDeviation['preview'])) {
                     $preview = CoreUtils::aposEncode($CachedDeviation['preview']);
                     throw new \Exception("The preview image appears to be unavailable. Please make sure <a href='{$preview}'>this link</a> works and try again, or re-submit the deviation if this persists.");
                 }
                 if (!DeviantArt::isImageAvailable($CachedDeviation['fullsize'])) {
                     $fullsize = CoreUtils::aposEncode($CachedDeviation['fullsize']);
                     throw new \Exception("The submission appears to be unavailable. Please make sure <a href='{$fullsize}'>this link</a> works and try again, or re-submit the deviation if this persists.");
                 }
             } catch (CURLRequestException $e) {
                 if ($e->getCode() === 404) {
                     throw new \Exception('The requested image could not be found');
                 }
                 throw new \Exception($e->getMessage());
             }
             if (empty($CachedDeviation)) {
                 throw new \Exception("{$this->provider} submission information could not be fetched for {$id}");
             }
             $this->preview = $CachedDeviation['preview'];
             $this->fullsize = $CachedDeviation['fullsize'];
             $this->title = $CachedDeviation['title'];
             $this->author = $CachedDeviation['author'];
             self::_checkImageAllowed($this->preview);
             self::_checkImageAllowed($this->fullsize);
             break;
         case 'lightshot':
             $page = @file_get_contents("http://prntscr.com/{$id}");
             if (empty($page)) {
                 throw new \Exception('The requested page could not be found');
             }
             if (!preg_match(new RegExp('<img\\s+class="image__pic[^"]*"\\s+src="http://i\\.imgur\\.com/([A-Za-z\\d]+)\\.'), $page, $_match)) {
                 throw new \Exception('The requested image could not be found');
             }
             $this->provider = 'imgur';
             $this->_getDirectUrl($_match[1]);
             break;
         default:
             throw new \Exception("The image could not be retrieved due to a missing handler for the provider \"{$this->provider}\"");
     }
     $this->preview = URL::makeHttps($this->preview);
     $this->fullsize = URL::makeHttps($this->fullsize);
     $this->id = $id;
 }
Example #8
0
 static function send($to, $type, $data)
 {
     global $Database;
     if (empty(self::$_notifTypes[$type])) {
         throw new \Exception("Invalid notification type: {$type}");
     }
     switch ($type) {
         case 'post-finished':
         case 'post-approved':
             $Database->rawQuery("UPDATE notifications SET read_at = NOW() WHERE \"user\" = ? && type = ? && data->>'id' = ? && data->>'type' = ?", array($to, $type, $data['id'], $data['type']));
     }
     $Database->insert('notifications', array('user' => $to, 'type' => $type, 'data' => JSON::encode($data)));
     try {
         CoreUtils::socketEvent('notify-pls', array('user' => $to));
     } catch (ServerConnectionFailureException $e) {
         error_log("Error while notifying {$to} with type {$type} (data:" . JSON::encode($data) . ")\nError message: {$e->getMessage()}");
         return 'Notification server is down! Please <a class="send-feedback">let us know</a>.';
     }
     return 0;
 }
Example #9
0
 /**
  * @param Post        $Post
  * @param string      $type
  * @param string      $reason
  * @param string|null $sent_by
  * @param string|null $reserved_by
  */
 static function clearTransferAttempts(Post $Post, string $type, string $reason, string $sent_by = null, $reserved_by = null)
 {
     global $currentUser, $Database;
     if (empty(self::TRANSFER_ATTEMPT_CLEAR_REASONS[$reason])) {
         throw new \Exception("Invalid clear reason {$reason}");
     }
     $Database->where('read_at IS NULL');
     $TransferAttempts = Posts::getTransferAttempts($Post, $type, $sent_by, $reserved_by, 'id,data');
     if (!empty($TransferAttempts)) {
         $SentFor = array();
         foreach ($TransferAttempts as $n) {
             Notifications::safeMarkRead($n['id']);
             $data = JSON::decode($n['data']);
             if (!empty($SentFor[$data['user']][$reason]["{$data['type']}-{$data['id']}"])) {
                 continue;
             }
             Notifications::send($data['user'], "post-pass{$reason}", array('id' => $data['id'], 'type' => $data['type'], 'by' => $currentUser->id));
             $SentFor[$data['user']][$reason]["{$data['type']}-{$data['id']}"] = true;
         }
     }
 }
Example #10
0
 static function reindex()
 {
     global $CGDb;
     $elasticClient = CoreUtils::elasticClient();
     try {
         $elasticClient->indices()->delete(CGUtils::ELASTIC_BASE);
     } catch (ElasticMissing404Exception $e) {
         $message = JSON::decode($e->getMessage());
         // Eat exception if the index we're re-creating does not exist yet
         if ($message['error']['type'] !== 'index_not_found_exception' || $message['error']['index'] !== CGUtils::ELASTIC_BASE['index']) {
             throw $e;
         }
     } catch (ElasticNoNodesAvailableException $e) {
         Response::fail('Re-index failed, ElasticSearch server is down!');
     }
     $params = array_merge(CGUtils::ELASTIC_BASE, ["body" => ["mappings" => ["entry" => ["_all" => ["enabled" => false], "properties" => ["label" => ["type" => "text", "analyzer" => "overkill"], "order" => ["type" => "integer"], "ishuman" => ["type" => "boolean"], "private" => ["type" => "boolean"], "tags" => ["type" => "text", "analyzer" => "overkill"]]]], "settings" => ["analysis" => ["analyzer" => ["overkill" => ["type" => "custom", "tokenizer" => "overkill", "filter" => ["lowercase"]]], "tokenizer" => ["overkill" => ["type" => "edge_ngram", "min_gram" => 2, "max_gram" => 6, "token_chars" => ["letter", "digit"]]]]]]]);
     $elasticClient->indices()->create(array_merge($params));
     $Appearances = $CGDb->where('id != 0')->get('appearances', null, self::ELASTIC_COLUMNS);
     $params = array('body' => []);
     foreach ($Appearances as $i => $a) {
         $meta = self::getElasticMeta($a);
         $params['body'][] = ['index' => ['_index' => $meta['index'], '_type' => $meta['type'], '_id' => $meta['id']]];
         $params['body'][] = self::getElasticBody($a);
         if ($i % 100 == 0) {
             $elasticClient->bulk($params);
             $params = ['body' => []];
         }
     }
     if (!empty($params['body'])) {
         $elasticClient->bulk($params);
     }
     Response::success('Re-index completed');
 }
Example #11
0
         Response::fail('An error prevented the notifications from appearing. If this persists, <a class="send-feedback">let us know</a>.');
     }
     break;
 case 'mark-read':
     $nid = intval($data, 10);
     $Notif = $Database->where('id', $nid)->where('user', $currentUser->id)->getOne('notifications');
     if (empty($Notif)) {
         Response::fail("The notification (#{$nid}) does not exist");
     }
     $read_action = (new Input('read_action', 'string', array(Input::IS_OPTIONAL => true, Input::IN_RANGE => [null, 10], Input::CUSTOM_ERROR_MESSAGES => array(Input::ERROR_INVALID => 'Action (@value) is invalid', Input::ERROR_RANGE => 'Action cannot be longer than @max characters'))))->out();
     if (!empty($read_action)) {
         if (empty(Notifications::$ACTIONABLE_NOTIF_OPTIONS[$Notif['type']][$read_action])) {
             Response::fail("Invalid read action ({$action}) specified for notification type {$Notif['type']}");
         }
         /** @var $data array */
         $data = !empty($Notif['data']) ? JSON::decode($Notif['data']) : null;
         switch ($Notif['type']) {
             case "post-passon":
                 $Post = $Database->where('id', $data['id'])->getOne("{$data['type']}s");
                 if (empty($Post)) {
                     Posts::clearTransferAttempts($Post, $data['type'], 'del');
                     Response::fail("The {$data['type']} doesn't exist or has been deleted");
                 }
                 if ($read_action === 'true') {
                     if ($Post['reserved_by'] !== $currentUser->id) {
                         Posts::clearTransferAttempts($Post, $data['type'], 'perm', null, $currentUser->id);
                         Response::fail('You are not allowed to transfer this reservation');
                     }
                     Notifications::safeMarkRead($Notif['id'], $read_action);
                     Notifications::send($data['user'], "post-passallow", array('id' => $data['id'], 'type' => $data['type'], 'by' => $currentUser->id));
                     $Database->where('id', $data['id'])->update("{$data['type']}s", array('reserved_by' => $data['user'], 'reserved_at' => date('c')));
Example #12
0
                    Statistics::processUsageData($RequestData, $Dataset);
                    $Data['datasets'][] = $Dataset;
                }
                $ReservationData = $Database->rawQuery(str_replace('table_name', 'reservations', $query));
                if (!empty($ReservationData)) {
                    $Dataset = array('label' => 'Reservations', 'clrkey' => 1);
                    Statistics::processUsageData($ReservationData, $Dataset);
                    $Data['datasets'][] = $Dataset;
                }
                break;
            case 'approvals':
                $Labels = $Database->rawQuery("SELECT to_char(timestamp,'{$LabelFormat}') AS key\n\t\t\t\t\tFROM log\n\t\t\t\t\tWHERE timestamp > NOW() - INTERVAL '2 MONTHS' AND reftype = 'post_lock'\n\t\t\t\t\tGROUP BY key\n\t\t\t\t\tORDER BY MIN(timestamp)");
                Statistics::processLabels($Labels, $Data);
                $Approvals = $Database->rawQuery("SELECT\n\t\t\t\t\t\tto_char(MIN(timestamp),'{$LabelFormat}') AS key,\n\t\t\t\t\t\tCOUNT(*)::INT AS cnt\n\t\t\t\t\tFROM log\n\t\t\t\t\tWHERE timestamp > NOW() - INTERVAL '2 MONTHS' AND reftype = 'post_lock'\n\t\t\t\t\tGROUP BY to_char(timestamp,'{$LabelFormat}')\n\t\t\t\t\tORDER BY MIN(timestamp)");
                if (!empty($Approvals)) {
                    $Dataset = array('label' => 'Approved posts');
                    Statistics::processUsageData($Approvals, $Dataset);
                    $Data['datasets'][] = $Dataset;
                }
                break;
        }
        Statistics::postprocessTimedData($Data);
        CoreUtils::createUploadFolder($CachePath);
        file_put_contents($CachePath, JSON::encode($Data));
        Response::done(array('data' => $Data));
    }
    CoreUtils::notFound();
}
HTTP::pushResource('/about/stats-posts');
HTTP::pushResource('/about/stats-approvals');
CoreUtils::loadPage(array('title' => 'About', 'do-css', 'js' => array('Chart', $do)));