/** * 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); }
/** * 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; }
/** * 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); }
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; }
$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);
static function getHTML($Notifications, $wrap = true) { global $Database; $HTML = $wrap ? '<ul class="notif-list">' : ''; foreach ($Notifications as $n) { $data = !empty($n['data']) ? JSON::decode($n['data']) : null; if (preg_match(new RegExp('^post-'), $n['type'])) { /** @var $Post Post */ $Post = $Database->where('id', $data['id'])->getOne("{$data['type']}s"); $Episode = Episodes::getActual($Post->season, $Post->episode, Episodes::ALLOW_MOVIES); $EpID = $Episode->formatTitle(AS_ARRAY, 'id'); $url = $Post->toLink($Episode); } switch ($n['type']) { case "post-finished": $HTML .= self::_getNotifElem("Your <a href='{$url}'>request</a> under {$EpID} has been fulfilled", $n); break; case "post-approved": $HTML .= self::_getNotifElem("A <a href='{$url}'>post</a> you reserved under {$EpID} has been added to the club gallery", $n); break; case "post-passon": $userlink = Users::get($data['user'])->getProfileLink(); $HTML .= self::_getNotifElem("{$userlink} is interested in finishing a <a href='{$url}'>post</a> you reserved under {$EpID}. Would you like to pass the reservation to them?", $n); break; case "post-passdeny": case "post-passallow": case "post-passfree": case "post-passdel": case "post-passsnatch": case "post-passperm": $userlink = Users::get($data['by'])->getProfileLink(); $passaction = str_replace('post-pass', '', $n['type']); switch ($passaction) { case "allow": $HTML .= self::_getNotifElem("Reservation transfer status: {$userlink} <strong class='color-lightgreen'>transferred</strong> the reservation of <a href='{$url}'>this post</a> under {$EpID} to you!", $n); break; case "deny": $HTML .= self::_getNotifElem("Reservation transfer status: {$userlink} <strong class='color-lightred'>denied</strong> transferring the reservation of <a href='{$url}'>this post</a> under {$EpID} to you.", $n); break; case 'free': case 'del': case 'snatch': case 'perm': $message = Posts::TRANSFER_ATTEMPT_CLEAR_REASONS[$passaction]; $message = str_replace('post', "<a href='{$url}'>post</a>", $message); switch ($passaction) { case 'del': $message .= " by {$userlink}"; break; case "perm": $message = str_replace('the previous reserver', $userlink, $message); break; } $HTML .= self::_getNotifElem("Reservation transfer status: {$message}", $n); break; } break; default: $HTML .= "<li><code>Notification({$n['type']})#{$n['id']}</code> <span class='nobr'>– Missing handler</span></li>"; } } return $HTML . ($wrap ? '</ul>' : ''); }
/** * @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; } } }
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'); }
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')));
use App\Time; use App\RegExp; use App\Response; use App\JSON; use App\Statistics; use App\CoreUtils; /** @var $do string */ if (POST_REQUEST) { CSRFProtection::protect(); $StatCacheDuration = 5 * Time::$IN_SECONDS['hour']; $_match = array(); if (!empty($data) && preg_match(new RegExp('^stats-(posts|approvals)$'), $data, $_match)) { $stat = $_match[1]; $CachePath = APPATH . "../fs/stats/{$stat}.json"; if (file_exists($CachePath) && filemtime($CachePath) > time() - $StatCacheDuration) { Response::done(array('data' => JSON::decode(file_get_contents($CachePath)))); } $Data = array('datasets' => array(), 'timestamp' => date('c')); $LabelFormat = 'YYYY-MM-DD'; switch ($stat) { case 'posts': $Labels = $Database->rawQuery("SELECT key FROM\n\t\t\t\t\t(\n\t\t\t\t\t\tSELECT posted, to_char(posted,'{$LabelFormat}') AS key FROM requests\n\t\t\t\t\t\tWHERE posted > NOW() - INTERVAL '2 MONTHS'\n\t\t\t\t\t\tUNION ALL\n\t\t\t\t\t\tSELECT posted, to_char(posted,'{$LabelFormat}') AS key FROM reservations\n\t\t\t\t\t\tWHERE posted > NOW() - INTERVAL '2 MONTHS'\n\t\t\t\t\t) t\n\t\t\t\t\tGROUP BY key\n\t\t\t\t\tORDER BY MIN(t.posted)"); Statistics::processLabels($Labels, $Data); $query = "SELECT\n\t\t\t\t\t\tto_char(MIN(posted),'{$LabelFormat}') AS key,\n\t\t\t\t\t\tCOUNT(*)::INT AS cnt\n\t\t\t\t\tFROM table_name t\n\t\t\t\t\tWHERE posted > NOW() - INTERVAL '2 MONTHS'\n\t\t\t\t\tGROUP BY to_char(posted,'{$LabelFormat}')\n\t\t\t\t\tORDER BY MIN(posted)"; $RequestData = $Database->rawQuery(str_replace('table_name', 'requests', $query)); if (!empty($RequestData)) { $Dataset = array('label' => 'Requests', 'clrkey' => 0); Statistics::processUsageData($RequestData, $Dataset); $Data['datasets'][] = $Dataset; } $ReservationData = $Database->rawQuery(str_replace('table_name', 'reservations', $query));