/** * Send the notification */ public function send() { $Client = new Client(); $failures = array(); $result = array(); $data = ["registration_ids" => [], "data" => ["title" => $this->data['subject'], "message" => $this->data['body']]]; foreach ($this->data['recipients'] as $user_id => $userdata) { $ThisUser = UserFactory::CreateUser($user_id); $subscriptions = Notifications::getPushSubscriptions($ThisUser); foreach ($subscriptions as $sub) { $data['registration_ids'][] = $sub['registration_id']; } } if (empty($data['registration_ids'])) { return; } try { $response = $Client->post($sub['endpoint'], ["headers" => ["Content-Type" => "application/json", "Authorization" => "key=" . GOOGLE_SERVER_KEY], "json" => $data]); $body = $response->getBody(); $result = json_decode($body, true); $this->removeStaleSubscriptions($result, $data['registration_ids']); $return = array("stat" => true, "failures" => $result); } catch (RequestException $e) { $return = ["stat" => false, "failures" => ["message" => $e->getMessage(), "body" => $e->getRequest()->getBody()]]; } return $return; }
/** * Update the author for a specific image * @since Version 3.10.0 * @param \Railpage\Images\Image $imageObject * @return \Railpage\Images\Image */ public static function updateAuthor(Image $imageObject) { if ($id = UserUtility::findFromFlickrNSID($imageObject->author->id)) { $imageObject->author->railpage_id = $id; $imageObject->author->User = UserFactory::CreateUser($imageObject->author->railpage_id); $imageObject->commit(); } return $imageObject; }
/** * Populate this object * @since Version 3.9.1 * @return void */ private function populate() { $query = "SELECT * FROM location_corrections WHERE id = ?"; if (!($row = $this->db->fetchRow($query, $this->id))) { return; } $this->comments = $row['comments']; $this->DateAdded = new DateTime($row['date_added']); $this->Location = new Location($row['location_id']); $this->setAuthor(UserFactory::CreateUser($row['user_id'])); if (!is_null($row['date_closed'])) { $this->DateClosed = new DateTime($row['date_closed']); } return; }
/** * Get the next photo competition * @since Version 3.10.0 * @param \Railpage\Gallery\Competition $photoComp * @return \Railpage\Gallery\Competition */ public function getNextCompetition(Competition $photoComp) { $query = "SELECT id \r\n FROM image_competition\r\n WHERE submissions_date_close >= NOW()\r\n AND id != ?\r\n ORDER BY submissions_date_open ASC\r\n LIMIT 0, 1"; $params = [$photoComp->id]; $id = $this->db->fetchOne($query, $params); try { $photoComp = new Competition($id); } catch (Exception $e) { // throw it away } if ($photoComp instanceof Competition && filter_var($photoComp->id, FILTER_VALIDATE_INT)) { return $photoComp; } $NextComp = $this->autoPopulateNextComp(); $NextComp->setAuthor(UserFactory::CreateUser(User::SYSTEM_USER_ID))->commit(); return $NextComp; }
/** * Populate this image with fresh data * * @since Version 3.8.7 * @return $this * * @param boolean $force * @param int $option * * @throws \Exception if the photo cannot be found on the image provider * @todo Split this into utility functions */ public function populate($force = false, $option = null) { if ($force === false && !$this->isStale()) { return $this; } Debug::LogCLI("Fetching data from " . $this->provider . " for image ID " . $this->id . " (photo ID " . $this->photo_id . ")"); /** * Start the debug timer */ if (RP_DEBUG) { global $site_debug; $debug_timer_start = microtime(true); } /** * New and improved populator using image providers */ $Provider = $this->getProvider(); $data = false; try { $data = $Provider->getImage($this->photo_id, $force); } catch (Exception $e) { $expected = array(sprintf("Unable to fetch data from Flickr: Photo \"%s\" not found (invalid ID) (1)", $this->photo_id), "Unable to fetch data from Flickr: Photo not found (1)"); if (in_array($e->getMessage(), $expected)) { $where = ["image_id = ?" => $this->id]; $this->db->delete("image_link", $where); $where = ["id = ?" => $this->id]; $this->db->delete("image", $where); throw new Exception("Photo no longer available from " . $this->provider); } } if ($data) { $this->sizes = $data['sizes']; $this->title = empty($data['title']) ? "Untitled" : $data['title']; $this->description = $data['description']; $this->meta = array("dates" => array("posted" => $data['dates']['uploaded'] instanceof DateTime ? $data['dates']['uploaded']->format("Y-m-d H:i:s") : $data['dates']['uploaded']['date'], "taken" => $data['dates']['taken'] instanceof DateTime ? $data['dates']['taken']->format("Y-m-d H:i:s") : $data['dates']['taken']['date'])); $this->author = new stdClass(); $this->author->username = $data['author']['username']; $this->author->realname = !empty($data['author']['realname']) ? $data['author']['realname'] : $data['author']['username']; $this->author->id = $data['author']['id']; $this->author->url = "https://www.flickr.com/photos/" . $this->author->id; if ($user_id = UserUtility::findFromFlickrNSID($this->author->id)) { $data['author']['railpage_id'] = $user_id; } if (isset($data['author']['railpage_id']) && filter_var($data['author']['railpage_id'], FILTER_VALIDATE_INT)) { $this->author->User = UserFactory::CreateUser($data['author']['railpage_id']); } /** * Load the tags */ if (isset($data['tags']) && is_array($data['tags']) && count($data['tags'])) { foreach ($data['tags'] as $row) { $this->meta['tags'][] = $row['raw']; } } /** * Load the Place object */ if ($option != Images::OPT_NOPLACE && isset($data['location']) && !empty($data['location'])) { try { $this->Place = Place::Factory($data['location']['latitude'], $data['location']['longitude']); } catch (Exception $e) { // Throw it away. Don't care. } } $this->links = new stdClass(); $this->links->provider = isset($data['urls']['url'][0]['_content']) ? $data['urls']['url'][0]['_content'] : $data['urls'][key($data['urls'])]; $this->commit(); $this->cacheGeoData(); return true; } /** * Fetch data in various ways for different photo providers */ switch ($this->provider) { /** * Picasa */ case "picasaweb": if (empty($this->meta) && !is_null(filter_input(INPUT_SERVER, "HTTP_REFERER", FILTER_SANITIZE_URL)) && strpos(filter_input(INPUT_SERVER, "HTTP_REFERER", FILTER_SANITIZE_URL), "picasaweb.google.com")) { $album = preg_replace("@(http|https)://picasaweb.google.com/([a-zA-Z\\-\\.]+)/(.+)@", "\$2", filter_input(INPUT_SERVER, "HTTP_REFERER", FILTER_SANITIZE_URL)); if (is_string($album)) { $update_url = sprintf("https://picasaweb.google.com/data/feed/api/user/%s/photoid/%s?alt=json", $album, $this->photo_id); } } if (isset($update_url)) { $data = file_get_contents($update_url); $json = json_decode($data, true); $this->meta = array("title" => $json['feed']['subtitle']['$t'], "description" => $json['feed']['title']['$t'], "dates" => array("posted" => date("Y-m-d H:i:s", $json['feed']['gphoto$timestamp']['$t'])), "sizes" => array("original" => array("width" => $json['feed']['gphoto$width']['$t'], "height" => $json['feed']['gphoto$height']['$t'], "source" => str_replace(sprintf("/s%d/", $json['feed']['media$group']['media$thumbnail'][0]['width']), sprintf("/s%d/", $json['feed']['gphoto$width']['$t']), $json['feed']['media$group']['media$thumbnail'][0]['url'])), "largest" => array("width" => $json['feed']['gphoto$width']['$t'], "height" => $json['feed']['gphoto$height']['$t'], "source" => str_replace(sprintf("/s%d/", $json['feed']['media$group']['media$thumbnail'][0]['width']), sprintf("/s%d/", $json['feed']['gphoto$width']['$t']), $json['feed']['media$group']['media$thumbnail'][0]['url']))), "photo_id" => $json['feed']['gphoto$id']['$t'], "album_id" => $json['feed']['gphoto$albumid']['$t'], "updateurl" => sprintf("%s?alt=json", $json['feed']['id']['$t'])); foreach ($json['feed']['media$group']['media$thumbnail'] as $size) { if ($size['width'] <= 500 && $size['width'] > 200) { $this->meta['sizes']['small'] = array("width" => $size['width'], "height" => $size['height'], "source" => $size['url']); } if ($size['width'] <= 200) { $this->meta['sizes']['small'] = array("width" => $size['width'], "height" => $size['height'], "source" => $size['url']); } if ($size['width'] <= 1024 && $size['width'] > 500) { $this->meta['sizes']['large'] = array("width" => $size['width'], "height" => $size['height'], "source" => $size['url']); } } foreach ($json['feed']['link'] as $link) { if ($link['rel'] == "alternate" && $link['type'] == "text/html") { $this->meta['source'] = $link['href']; } } if ($option != Images::OPT_NOPLACE && isset($json['feed']['georss$where']['gml$Point']) && is_array($json['feed']['georss$where']['gml$Point'])) { $pos = explode(" ", $json['feed']['georss$where']['gml$Point']['gml$pos']['$t']); $this->Place = Place::Factory($pos[0], $pos[1]); } $this->title = $this->meta['title']; $this->description = $this->meta['description']; $this->author = new stdClass(); $this->author->username = $album; $this->author->id = $album; $this->author->url = sprintf("%s/%s", $json['feed']['generator']['uri'], $album); } $this->sizes = $this->meta['sizes']; $this->commit(); break; /** * Vicsig */ /** * Vicsig */ case "vicsig": if (strpos(filter_input(INPUT_SERVER, "HTTP_REFERER", FILTER_SANITIZE_URL), "vicsig.net/photo")) { $this->meta['source'] = filter_input(INPUT_SERVER, "HTTP_REFERER", FILTER_SANITIZE_STRING); $response = $this->GuzzleClient->get($this->meta['source']); if ($response->getStatusCode() != 200) { throw new Exception(sprintf("Failed to fetch image data from %s: HTTP error %s", $this->provider, $response->getStatusCode())); } /** * Start fetching it */ $data = $response->getBody(); $doc = new DomDocument(); $doc->loadHTML($data); $images = $doc->getElementsByTagName("img"); foreach ($images as $element) { if (!empty($element->getAttribute("src")) && !empty($element->getAttribute("alt"))) { #$image_title = $element->getAttribute("alt"); $this->sizes['original'] = array("source" => $element->getAttribute("src"), "width" => $element->getAttribute("width"), "height" => $element->getAttribute("height")); if (substr($this->sizes['original']['source'], 0, 1) == "/") { $this->sizes['original']['source'] = "http://www.vicsig.net" . $this->sizes['original']['source']; } break; } } $desc = $doc->getElementsByTagName("i"); foreach ($desc as $element) { if (!isset($image_desc)) { $text = trim($element->nodeValue); $text = str_replace("\r\n", "\n", $text); $text = explode("\n", $text); /** * Loop through the exploded text and remove the obvious date/author/etc */ foreach ($text as $k => $line) { // Get the author if (preg_match("@Photo: @i", $line)) { $this->author = new stdClass(); $this->author->realname = str_replace("Photo: ", "", $line); $this->author->url = filter_input(INPUT_SERVER, "HTTP_REFERER", FILTER_SANITIZE_STRING); unset($text[$k]); } // Get the date try { $this->meta['dates']['posted'] = (new DateTime($line))->format("Y-m-d H:i:s"); unset($text[$k]); } catch (Exception $e) { // Throw it away } } /** * Whatever's left must be the photo title and description */ foreach ($text as $k => $line) { if (empty($this->title)) { $this->title = $line; continue; } $this->description .= $line; } $this->links = new stdClass(); $this->links->provider = filter_input(INPUT_SERVER, "HTTP_REFERER", FILTER_SANITIZE_STRING); $this->commit(); } } } break; } /** * End the debug timer */ if (RP_DEBUG) { $site_debug[] = __CLASS__ . "::" . __FUNCTION__ . "() : completed in " . round(microtime(true) - $debug_timer_start, 5) . "s"; } return $this; }
/** * Fetch the message * @since Version 3.3 * @version 3.3 * @return boolean */ public function fetch() { if (!filter_var($this->id, FILTER_VALIDATE_INT)) { throw new Exception("Cannot fetch PM - no message ID provided"); } $this->mckey = "railpage:messsages.message_id=" . $this->id; if (!($row = $this->Memcached->fetch($this->mckey))) { $query = "SELECT pm.*, pmt.*, ufrom.user_id AS user_id_from, ufrom.username AS username_from, ufrom.user_avatar AS from_user_avatar, ufrom.user_allow_viewonline AS from_user_viewonline, uto.user_id AS user_id_to, uto.username AS username_to, uto.user_allow_viewonline AS to_user_viewonline\r\n FROM nuke_bbprivmsgs AS pm\r\n LEFT JOIN nuke_bbprivmsgs_text AS pmt ON pm.privmsgs_id = pmt.privmsgs_text_id\r\n LEFT JOIN nuke_users AS ufrom ON pm.privmsgs_from_userid = ufrom.user_id\r\n LEFT JOIN nuke_users AS uto ON pm.privmsgs_to_userid = uto.user_id\r\n WHERE pm.privmsgs_id = ?"; $row = $this->db->fetchRow($query, $this->id); $this->Memcached->save($this->mckey, $row); } if (!isset($row) || count($row) == 0) { return; } // Nasty way of doing it, but it should work for now. // Remember to extend BOTH open AND close when adding another bbcode to match //$bbcode_preg_open = "@\[(img|url|list|b|i|u)\:([a-zA-Z0-9]+)\]@"; //$bbcode_preg_close = "@\[/(img|url|list|b|i|u)\:([a-zA-Z0-9]+)\]@"; $this->id = $row['privmsgs_id']; $this->date = $row['privmsgs_date']; $this->subject = $row['privmsgs_subject']; $this->body = trim($row['privmsgs_text']); $this->bbcode_uid = $row['privmsgs_bbcode_uid']; $this->type = $row['privmsgs_type']; $this->enable_bbcode = $row['privmsgs_enable_bbcode']; $this->enable_html = $row['privmsgs_enable_html']; $this->enable_smilies = $row['privmsgs_enable_smilies']; $this->enable_signature = $row['privmsgs_attach_sig']; $this->object_id = $row['object_id']; $this->hide_from = $row['hide_from']; $this->hide_to = $row['hide_to']; $this->setRecipient(UserFactory::CreateUser($row['privmsgs_to_userid'])); $this->setAuthor(UserFactory::CreateUser($row['privmsgs_from_userid'])); }
/** * Constructor * @since Version 3.8.7 * @param int $id */ public function __construct($id = NULL) { parent::__construct(); $this->Module = new Module("events"); $this->namespace = $this->Module->namespace; if (!filter_var($id, FILTER_VALIDATE_INT)) { return; } if (!($row = $this->db->fetchRow("SELECT * FROM event_dates WHERE id = ?", $id))) { return; } $this->id = $id; $this->Event = Factory::CreateEvent($row['event_id']); $this->Date = new DateTime($row['date']); $this->meta = json_decode($row['meta'], true); $this->status = $row['status']; $this->url = new Url("/events?mode=event.date&event_id=" . $this->Event->id . "&date_id=" . $this->id); $this->url->approve = sprintf("/events?mode=event.date.setstatus&date_id=%d&status=%d", $this->id, self::STATUS_RUNNING); $this->url->reject = sprintf("/events?mode=event.date.setstatus&date_id=%d&status=%d", $this->id, self::STATUS_REJECTED); $this->url->cancel = sprintf("/events?mode=event.date.setstatus&date_id=%d&status=%d", $this->id, self::STATUS_CANCELLED); $this->url->export = sprintf("/events/export/date/%d.ics", $this->id); $this->setAuthor(UserFactory::CreateUser($row['user_id'])); if ($row['start'] != "00:00:00") { $this->Start = new DateTime($row['date'] . " " . $row['start']); } if ($row['end'] != "00:00:00") { $this->End = new DateTime($row['date'] . " " . $row['end']); } if (isset($this->meta['lat']) && empty($this->meta['lat'])) { unset($this->meta['lat']); } if (isset($this->meta['lon']) && empty($this->meta['lon'])) { unset($this->meta['lon']); } if (isset($this->meta['lat']) && isset($this->meta['lon'])) { $this->Place = Place::Factory($this->meta['lat'], $this->meta['lon']); } try { if ($this->Event->Place instanceof Place && !empty($this->Event->Place->Region->timezone)) { $this->Date->setTimezone(new DateTimeZone($this->Event->Place->Region->timezone)); if ($this->Start instanceof DateTime) { $this->Start->setTimezone(new DateTimeZone($this->Event->Place->Region->timezone)); } if ($this->End instanceof DateTime) { $this->End->setTimezone(new DateTimeZone($this->Event->Place->Region->timezone)); } } } catch (Exception $e) { printArray($e->getMessage()); printArray($this->Event->Place->Region->timezone); } }
/** * Load the download data from the database and populate this class * @since Version 3.2 * @return boolean */ public function fetch() { if (empty($this->id)) { throw new Exception("Cannot fetch download object - no download ID given"); } $query = "SELECT d.*, UNIX_TIMESTAMP(d.date) AS date_unix FROM download_items AS d WHERE d.id = ?"; $row = $this->db->fetchRow($query, $this->id); if (!is_array($row) || count($row) === 0) { throw new Exception("Requested download not found"); } // Populate the vars $this->name = $row['title']; $this->desc = $row['description']; $this->url_file = $row['url']; $this->filename = empty($row['filename']) ? basename($row['url']) : $row['filename']; $this->Date = new DateTime($row['date'], new DateTimeZone("Australia/Melbourne")); $this->hits = $row['hits']; $this->filesize = isset($row['filesize']) && $row['filesize'] > 0 ? formatBytes($row['filesize']) : "Unknown"; $this->user_id = $row['user_id']; $this->filepath = $row['filepath']; $this->object_id = $row['object_id']; $this->approved = $row['approved']; $this->active = $row['active']; $this->extra_data = $row['extra_data']; $this->mime = $row['mime']; if (empty($this->filepath) && !empty($this->url_file)) { $pathinfo = parse_url($this->url_file); $this->filepath = str_replace("/uploads/", "", $pathinfo['path']); try { $this->commit(); } catch (Exception $e) { // Do nothing } } if (!preg_match("@^(http|https)://@", $this->url_file)) { $this->url_file = parent::DOWNLOAD_HOST . parent::DOWNLOAD_DIR . $this->url_file; } if ($row['date'] == "0000-00-00 00:00:00") { $this->Date = new DateTime("now", new DateTimeZone("Australia/Melbourne")); $this->commit(); } if (empty($this->user_id) && !empty($row['submitter'])) { $this->submitter = $row['submitter']; } /** * Load the category this download belongs to */ $this->Category = new Category($row['category_id']); /** * Load the author */ $this->Author = UserFactory::CreateUser($this->user_id); if (empty($this->mime) && file_exists(RP_DOWNLOAD_DIR . $this->filepath)) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $this->mime = finfo_file($finfo, RP_DOWNLOAD_DIR . $this->filepath); $this->commit(); } $this->url = Utility\DownloadUtility::buildUrls($this); }
/** * Populate this object * @since Version 3.9.1 * @return void */ private function populate() { if (!($row = $this->Memcached->fetch($this->mckey))) { $query = "SELECT * FROM glossary WHERE id = ?"; $row = $this->db->fetchRow($query, $this->id); $this->Memcached->save($this->mckey, $row); } if (!isset($row) || !is_array($row)) { return; } $this->name = $row['short']; $this->text = $row['full']; $this->example = $row['example']; $this->Type = new Type($row['type']); $this->status = isset($row['status']) ? $row['status'] : self::STATUS_APPROVED; $this->slug = $row['slug']; $this->setAuthor(UserFactory::CreateUser($row['author'])); if ($row['date'] == "0000-00-00 00:00:00") { $this->Date = new DateTime(); $this->commit(); } if (!$this->Date instanceof DateTime) { $this->Date = new DateTime($row['date']); } $this->makeURLs(); $this->makeSlug(); }
/** * Populate this object * @since Version 3.9.1 * @return void * @param int|string $id */ private function populate($id) { $row = $this->load($id); if (!isset($row) || !is_array($row)) { return; } $this->title = $row['title']; $this->desc = $row['description']; $this->meta = json_decode($row['meta'], true); $this->slug = $row['slug']; $this->status = isset($row['status']) ? $row['status'] : Events::STATUS_APPROVED; if (!isset($row['user_id'])) { $row['user_id'] = 45; } $this->setAuthor(UserFactory::CreateUser($row['user_id'])); $this->flickr_tag = "railpage:event=" . $this->id; if (filter_var($row['category_id'], FILTER_VALIDATE_INT)) { $this->Category = Factory::CreateEventCategory($row['category_id']); } if (filter_var($row['organisation_id'], FILTER_VALIDATE_INT)) { $this->Organisation = OrganisationsFactory::CreateOrganisation($row['organisation_id']); } if (!empty($row['lat']) && round($row['lat'], 3) != "0.000" && !empty($row['lon']) && round($row['lon'], 3) != "0.000") { $this->Place = Place::Factory($row['lat'], $row['lon']); } $this->createUrls(); $this->Templates = new stdClass(); $this->Templates->view = sprintf("%s/event.tpl", $this->Module->Paths->html); }
/** * Send out a notification to site admins to cast a deciding vote in the event of a tied competition * @since Version 3.10.0 * @param \Railpage\Images\Competition $photoComp * @return void */ public static function NotifyTied(Competition $photoComp) { if (isset($photoComp->meta['notifytied']) && $photoComp->meta['notifytied'] >= strtotime("-1 day")) { return; } $photoComp->meta['notifytied'] = time(); $photoComp->commit(); $Smarty = AppCore::GetSmarty(); // User who will cast the deciding vote $Decider = UserFactory::CreateUser(45); // Create the push notification $Push = new Notification(); $Push->transport = Notifications::TRANSPORT_PUSH; $Push->subject = "Tied photo competition"; $Push->body = sprintf("The %s photo competition is tied. Cast a deciding vote ASAP.", $photoComp->title); $Push->setActionUrl($photoComp->url->tied)->addRecipient($Decider->id, $Decider->username, $Decider->username); $Push->commit()->dispatch(); // Create an email notification as a backup $Email = new Notification(); $Email->subject = "Tied competition: " . $photoComp->title; $Email->addRecipient($Decider->id, $Decider->username, $Decider->username); $tpl = $Smarty->ResolveTemplate("template.generic"); $email = array("subject" => $Email->subject, "subtitle" => "Photo competitions", "body" => sprintf("<p>The <a href='%s'>%s</a>photo competition is tied and requires a deciding vote. <a href='%s'>Cast it ASAP</a>.</p>", $photoComp->url->canonical, $photoComp->title, $photoComp->url->tied)); $Smarty->Assign("email", $email); $Email->body = $Smarty->fetch($tpl); $Email->commit(); return; }
/** * Populate this object * @since Version 3.9.1 * @return void */ private function populate($id) { $query = "SELECT * FROM loco_unit_corrections WHERE correction_id = ?"; $row = $this->db->fetchRow($query, $id); if (count($row)) { $this->id = $id; $this->text = $row['text']; $this->User = UserFactory::CreateUser($row['user_id']); $this->Date = new DateTime($row['date']); $this->status = $row['status']; $this->Resolution = new stdClass(); if (filter_var($row['resolved_by'], FILTER_VALIDATE_INT)) { $this->Resolution->User = UserFactory::CreateUser($row['resolved_by']); $this->Resolution->Date = new DateTime($row['resolved_date']); } if ($loco_id = filter_var($row['loco_id'], FILTER_VALIDATE_INT)) { $this->Object = new Locomotive($loco_id); return; } if ($class_id = filter_var($row['class_id'], FILTER_VALIDATE_INT)) { $this->Object = new LocoClass($class_id); return; } } throw new Exception("Unable to determine if this correction belongs to a locomotive or a locomotive class"); }
/** * Unban user * @since Version 3.2 * @version 3.2 * @param int $banId * @param int|bool $userId * @return boolean */ public function unBanUser($banId, $userId = null) { $success = false; /** * Empty the cache */ try { $this->Memcached->delete("railpage:bancontrol.users"); $this->Memcached->delete(self::CACHE_KEY_ALL); } catch (Exception $e) { // throw it away } try { $this->Redis->delete("railpage:bancontrol"); } catch (Exception $e) { // throw it away } if ($banId instanceof User) { $userId = $banId->id; } if ($userId == null) { $query = "SELECT user_id FROM bancontrol WHERE id = ?"; $userId = $this->db->fetchOne($query, $banId); } if ($userId > 0) { $data = array("ban_active" => 0); $where = array("user_id = " . $userId); $this->db->update("bancontrol", $data, $where); $success = true; $cachekey_user = sprintf(self::CACHE_KEY_USER, $userId); $this->Memcached->save($cachekey_user, false, strtotime("+5 weeks")); } if ($success) { // Tell the world that they've been unbanned $ThisUser = UserFactory::CreateUser($userId); $ThisUser->active = 1; $ThisUser->location = ""; $ThisUser->signature = ""; $ThisUser->avatar = ""; $ThisUser->interests = ""; $ThisUser->occupation = ""; try { $ThisUser->commit(); $Smarty = AppCore::getSmarty(); // Send the ban email $Smarty->Assign("userdata_username", $ThisUser->username); // Send the confirmation email $Notification = new Notification(); $Notification->addRecipient($ThisUser->id, $ThisUser->username, $ThisUser->contact_email); $Notification->body = $Smarty->Fetch($Smarty->ResolveTemplate("email_unban")); $Notification->subject = "Railpage account re-activation"; $Notification->transport = Notifications::TRANSPORT_EMAIL; $Notification->commit()->dispatch(); return true; } catch (Exception $e) { global $Error; if (isset($Error)) { $Error->save($e, $_SESSION['user_id']); } Debug::logException($e); } } return false; }
/** * Find user from email address * @since Version 3.8.7 * @param string $email * @param string $provider * @author Michael Greenhill */ public function getUserFromEmail($email = null, $provider = "railpage") { if ($email == null) { throw new Exception("Can't find user - no email address provided"); } $query = "SELECT user_id FROM nuke_users WHERE user_email = ?"; $params = array($email); if (!is_null($provider)) { $params[] = $provider; $query .= " AND provider = ?"; } $user_id = $this->db->fetchOne($query, $params); if (filter_var($user_id, FILTER_VALIDATE_INT)) { return Factory::CreateUser($user_id); } throw new Exception(sprintf("No user found with an email address of %s and logging in via %s", $email, $provider)); }
/** * Populate this object * @since Version 3.9.1 * @param string $column * @param string|int $value * @return void */ private function populate($column, $value) { $query = sprintf("SELECT * FROM idea_ideas WHERE %s = ?", $column); if (!($row = $this->db->fetchRow($query, $value))) { return; } $this->title = $row['title']; $this->id = $row['id']; $this->slug = $row['slug']; $this->description = $row['description']; $this->Date = new DateTime($row['date']); $this->Category = new Category($row['category_id']); $this->status = $row['status']; $this->forum_thread_id = $row['forum_thread_id']; $this->redmine_id = $row['redmine_id']; $this->meta = json_decode($row['meta'], true); if (!is_array($this->meta)) { $this->meta = []; } $this->setAuthor(UserFactory::CreateUser($row['author'])); $this->fetchVotes(); $this->makeURLs(); }
/** * Approve user membership * @since Version 3.9.1 * @param \Railpage\Users\User|int $userObject * @return \Railpage\Users\Group */ public function approveUser($userObject) { if (!$userObject instanceof User) { $userObject = Factory::CreateUser($userObject); } $data = ["user_pending" => 0]; $where = ["user_id = ?" => $userObject->id, "group_id = ?" => $this->id]; $mckey = sprintf("railpage:group=%d", intval($this->id)); $this->Redis->delete($mckey); $this->db->update("nuke_bbuser_group", $data, $where); return $this; }
/** * Validate a password for this account * * Updated to use PHP 5.5's password_hash(), password_verify() and password_needs_rehash() functions * @since Version 3.8.7 * * @param string $password * * @return boolean */ public function validatePassword($password = false, $username = false) { Utility\PasswordUtility::validateParameters($password, $username, $this); /** * Create a temporary instance of the requested user for logging purposes */ try { $TmpUser = Factory::CreateUserFromUsername($username); } catch (Exception $e) { if ($e->getMessage() == "Could not find user ID from given username") { $TmpUser = new User($this->id); } } /** * Get the stored password for this username */ if ($username && !empty($username) && empty($this->username)) { $query = "SELECT user_id, user_password, user_password_bcrypt FROM nuke_users WHERE username = ?"; $row = $this->db->fetchRow($query, $username); $stored_user_id = $row['user_id']; $stored_pass = $row['user_password']; $stored_pass_bcrypt = $row['user_password_bcrypt']; } elseif (!empty($this->password)) { $stored_user_id = $this->id; $stored_pass = $this->password; $stored_pass_bcrypt = $this->password_bcrypt; } /** * Check if the invalid auth timeout is in effect */ if (isset($TmpUser->meta['InvalidAuthTimeout'])) { if ($TmpUser->meta['InvalidAuthTimeout'] <= time()) { unset($TmpUser->meta['InvalidAuthTimeout']); unset($TmpUser->meta['InvalidAuthCounter']); $TmpUser->commit(); $this->refresh(); } else { $TmpUser->addNote("Login attempt while InvalidAuthTimeout is in effect"); throw new Exception("You've attempted to log in with the wrong password too many times. We've temporarily disabled your account to protect it against hackers. Please try again soon. <a href='/account/resetpassword'>Can't remember your password?</a>"); } } /** * Verify the password */ if (Utility\PasswordUtility::validatePassword($password, $stored_pass, $stored_pass_bcrypt)) { $this->load($stored_user_id); /** * Check if the password needs rehashing */ if (password_needs_rehash($stored_pass, PASSWORD_DEFAULT) || password_needs_rehash($stored_pass_bcrypt, PASSWORD_DEFAULT)) { $this->setPassword($password); } /** * Reset the InvalidAuthCounter */ if (isset($this->meta['InvalidAuthCounter'])) { unset($this->meta['InvalidAuthCounter']); } if (isset($this->meta['InvalidAuthTimeout'])) { unset($this->meta['InvalidAuthTimeout']); } $this->commit(); return true; } /** * Unsuccessful login attempt - bump up the invalid auth counter */ $TmpUser->meta['InvalidAuthCounter'] = !isset($TmpUser->meta['InvalidAuthCounter']) ? 1 : $TmpUser->meta['InvalidAuthCounter']++; $TmpUser->addNote(sprintf("Invalid login attempt %d", $TmpUser->meta['InvalidAuthCounter'])); $TmpUser->commit(); $this->refresh(); if ($TmpUser->meta['InvalidAuthCounter'] === 3) { $TmpUser->meta['InvalidAuthTimeout'] = strtotime("+10 minutes"); $TmpUser->addNote("Too many invalid login attempts - account disabled for ten minutes"); $TmpUser->commit(); $this->refresh(); throw new Exception("You've attempted to log in with the wrong password too many times. As a result, we're disabling this account for the next ten minutes. <a href='/account/resetpassword'>Can't remember your password?</a>"); } $this->reset(); return false; }
/** * Get all open corrections * @since Version 3.9.1 * @return array */ public function getOpenCorrections() { $query = "SELECT l.name AS location_name, u.username, c.* \n FROM location_corrections AS c \n LEFT JOIN location AS l ON c.location_id = l.id \n LEFT JOIN nuke_users AS u ON u.user_id = c.user_id \n WHERE c.status = ? \n ORDER BY c.date_added DESC"; $return = array(); foreach ($this->db->fetchAll($query, Correction::STATUS_NEW) as $row) { $return[] = array("location" => (new Location($row['location_id']))->getArray(), "author" => UsersFactory::CreateUser($row['user_id'])->getArray(), "correction" => array("comments" => $row['comments'], "date" => array("added" => $row['date_added'], "closed" => $row['date_closed']))); } return $return; }
/** * Save a correction for this loco * @since Version 3.2 * @param string $text * @param int $userId */ public function newCorrection($text = false, $userId = false) { $Correction = new Correction(); $Correction->text = $text; $Correction->setUser(UserFactory::CreateUser($userId)); $Correction->setObject($this); $Correction->commit(); return true; }
/** * Get and personalise the content for this newsletter * @since Version 3.10.0 * @return \Railpage\Newsletters\Weekly */ private function personaliseContent() { $replacements = array(); Debug::LogCLI("Looping through " . count($this->recipients) . " users and preparing email decoration"); $this->user_ids = array(); $counter = 0; /** * Loop through our list of users and start to curate the contents */ foreach ($this->recipients as $row) { // Flag this user ID so that we can update the "last sent" timestamp later $user_ids[] = $row['user_id']; // Sanity check : validate the email address first if (!filter_var($row['user_email'], FILTER_VALIDATE_EMAIL)) { Debug::LogCLI("Skipping user ID " . $row['user_id'] . " - \"" . $row['user_email'] . "\" is not a valid email address"); continue; } // Add the recipient $this->Notification->addRecipient($row['user_id'], $row['username'], $row['user_email']); // Assign some decoration $replacements[$row['user_email']] = array("##username##" => $row['username'], "##email##" => $row['user_email'], "##email_encoded##" => urlencode($row['user_email']), "##unsubscribe##" => sprintf("http://railpage.com.au/unsubscribe?email=%s&newsletter=weekly", urlencode($row['user_email']))); /** * Get the custom news feed articles */ Debug::LogCLI("Preparing personalised news for user ID " . $row['user_id']); // Try and create the user object. If it bombs out, we need to know about it but let the newsletter continue try { $User = UserFactory::CreateUser($row['user_id']); } catch (Exception $e) { Debug::LogCLI("Skipped user due to exception: " . $e->getMessage()); continue; } // Create the custom news feed object $Feed = new Feed(); $Feed->setUser($User); $articles = $Feed->addFilter(Feed::FILTER_UNREAD)->addFilter(Feed::FILTER_LAST_30_DAYS)->findArticles(0, 10, "story_hits"); // If the number of personalised articles is less than ten, drop the filter and simply find ten recent and unread articles if (count($articles) < 10) { Debug::LogCLI("Found " . count($articles) . " articles for user ID " . $User->id . " - dropping keyword and topic filter from feed"); $Feed->filter_words = null; $Feed->filter_topics = null; $articles = $Feed->findArticles(0, 10, "story_hits"); } // If we have less than six articles skip this user altogether. if (count($articles) < 6) { Debug::LogCLI("Found " . count($articles) . " articles for user ID " . $User->id . " - skipping"); continue; } Debug::LogCLI("Proceeding with newsletter for user ID " . $User->id); // Loop through each article and normalise the content foreach ($articles as $id => $article) { $article['sid'] = $article['story_id']; $article['catid'] = $article['topic_id']; $article['hometext'] = preg_replace("@(\\[b\\]|\\[\\/b\\])@", "", $article['story_blurb']); $article['informant'] = $article['username']; $article['informant_id'] = $article['user_id']; $article['ForumThreadId'] = $article['forum_topic_id']; $article['topictext'] = ContentUtility::FormatTitle($article['topic_title']); $article['topic'] = $article['topic_id']; $article['featured_image'] = ImageCache::cache($article['story_image']); $article['title'] = $article['story_title']; $article['url'] = NewsletterUtility::CreateUTMParametersForLink($this->Newsletter, $article['url']); $articles[$id] = $article; } $articles = array_values($articles); if (!isset($start)) { $start = 0; } // Loop through the prepended content and assign it to the blocks foreach ($this->prependedContent as $i => $block) { $tmp = ["##block" . $i . ".subtitle##" => $block['title'], "##block" . $i . ".featuredimage##" => $block['featuredimage'], "##block" . $i . ".text##" => strip_tags(wpautop(process_bbcode($block['text'])), "<br><br /><p>"), "##block" . $i . ".link##" => strpos($block['url'], "http") === false ? "http://www.railpage.com.au" . $block['url'] : $block['url'], "##block" . $i . ".alt_title##" => $block['subtitle'], "##block" . $i . ".link_text##" => isset($block['link_text']) && !empty($block['link_text']) ? $block['link_text'] : "Continue reading"]; $replacements[$row['user_email']] = array_merge($replacements[$row['user_email']], $tmp); } // Loop through our content and assign to content blocks for ($i = count($this->prependedContent) + $start; $i < $start + $this->num_items; $i++) { $Date = new DateTime($articles[$i]['story_time']); $tmp = ["##block" . $i . ".subtitle##" => $articles[$i]['story_title'], "##block" . $i . ".featuredimage##" => $articles[$i]['story_image'], "##block" . $i . ".text##" => strip_tags(wpautop(process_bbcode($articles[$i]['story_lead'])), "<br><br /><p>"), "##block" . $i . ".link##" => strpos($articles[$i]['url'], "http") === false ? "http://www.railpage.com.au" . $articles[$i]['url'] : $articles[$i]['url'], "##block" . $i . ".alt_title##" => sprintf("Published %s", $Date->format("F j, Y, g:i a")), "##block" . $i . ".link_text##" => "Continue reading"]; $replacements[$row['user_email']] = array_merge($replacements[$row['user_email']], $tmp); } Debug::LogCLI("Completed personalisation of newsletter for user ID " . $User->id); // Increment our personalised newsletter counter $counter++; /** * Break after 150 recipients. Don't want to be flagged as a spammer, or overload the MTA */ if ($counter == 150) { break; } } $this->replacements = $replacements; return $this; }
/** * Get author of a submitted photo * @since Version 3.9.1 * @return \Railpage\Users\User * @param \Railpage\Images\Image $imageObject */ public function getPhotoAuthor(Image $imageObject) { $query = "SELECT user_id FROM image_competition_submissions WHERE competition_id = ? AND image_id = ?"; $params = array($this->id, $imageObject->id); #printArray($params);die; $user_id = $this->db->fetchOne($query, $params); return UserFactory::CreateUser($user_id); }
/** * Populate this object * * @since Version 3.9.1 * @return void */ private function load() { if (!($row = $this->db->fetchRow("SELECT * FROM asset WHERE id = ?", $this->id))) { return; } $this->hash = $row['hash']; $this->type_id = $row['type_id']; $this->meta = json_decode($row['meta'], true); if (function_exists("get_domain")) { $this->meta['domain'] = get_domain($this->meta['url']); } $this->url = new Url("/assets?id=" . $this->id); foreach ($this->meta as $key => $val) { if (is_string($val)) { $this->meta[$key] = trim($val); } if (is_array($val)) { foreach ($val as $k => $v) { if (is_string($v)) { $this->meta[$key][$k] = trim($v); } } } } /** * Update the unique hash if we need to */ if (empty($this->hash)) { $data = array("hash" => md5($this->meta['url'])); $where = array("id = ?" => $this->id); $this->db->update("asset", $data, $where); } /** * Get uses/instances from the database */ foreach ($this->db->fetchAll("SELECT * FROM asset_link WHERE asset_id = ? ORDER BY date DESC", $this->id) as $row) { $this->instances[$row['asset_link_id']] = $row; $this->Date = new DateTime($row['date']); $this->User = UserFactory::CreateUser($row['user_id']); } }
/** * Load the owner of this album * @since Version 3.8.7 * @return \Railpage\Users\User */ public function getOwner() { if ($this->Owner instanceof User) { return $this->Owner; } if (filter_var($this->owner, FILTER_VALIDATE_INT)) { try { return UserFactory::CreateUser($this->owner); } catch (Exception $e) { // Don't care } } }
/** * Load the author * @since Version 3.8.7 * @return $this */ public function loadAuthor() { $this->Author = UserFactory::CreateUser($this->uid); return $this; }
/** * Get watchers of this thread * @since Version 3.9 * @return array */ public function getWatchers() { $query = "SELECT w.user_id FROM nuke_bbtopics_watch AS w LEFT JOIN nuke_users AS u ON u.user_id = w.user_id WHERE w.topic_id = ? ORDER BY u.username"; $return = array(); foreach ($this->db->fetchAll($query, $this->id) as $row) { $ThisUser = UserFactory::CreateUser($row['user_id']); $row = array("id" => $ThisUser->id, "username" => $ThisUser->username, "url" => $ThisUser->url->getUrls()); $return[] = $row; } return $return; }
/** * Validate changes to an article before committing changes * @since Version 3.4 * @return boolean * @throws \Exception if the article title is empty * @throws \Exception if the article blurb and lead are empty * @throws \Exception if the body and paragraphs AND source are empty * @throws \Exception if the article title is too long */ public function validate() { if (empty($this->title)) { throw new Exception("Validation failed: title is empty"); } if (empty($this->blurb) && empty($this->lead)) { throw new Exception("Validation failed: blurb is empty"); } if (empty($this->body) && empty($this->source) && empty($this->paragraphs)) { throw new Exception("Validation failed: body is empty"); } if (is_null($this->blurb) || !empty($this->lead)) { $this->blurb = ""; } if (is_null($this->body) || !empty($this->paragraphs)) { $this->body = ""; } if (is_null($this->paragraphs)) { $this->paragraphs = ""; } if (is_null($this->lead)) { $this->lead = ""; } if (!isset($this->Author) || !$this->Author instanceof User) { $this->Author = UserFactory::CreateUser($this->user_id); } if (!$this->date instanceof DateTime) { $this->date = new DateTime(); } if (!filter_var($this->approved)) { $this->approved = self::STATUS_UNAPPROVED; } if (is_null($this->source)) { $this->source = ""; } if (empty($this->unique_id)) { $this->unique_id = md5($this->title); } if (!is_bool($this->queued)) { $this->queued = false; } /** * Try to get the featured image from OpenGraph tags */ if ($this->source && !$this->featured_image) { require_once "vendor" . DS . "scottmac" . DS . "opengraph" . DS . "OpenGraph.php"; $graph = \OpenGraph::fetch($this->source); #printArray($graph->keys()); #printArray($graph->schema); foreach ($graph as $key => $value) { if ($key == "image" && strlen($value) > 0) { $this->featured_image = $value; } } } return true; }
/** * Constructor * * @since Version 3.8.7 * * @param int|bool $id * * @returns \Railpage\Warnings\Warning */ public function __construct($id = null) { parent::__construct(); if (!($id = filter_var($id, FILTER_VALIDATE_INT))) { return $this; } $this->id = $id; $query = "SELECT * FROM phpbb_warnings WHERE warn_id = ?"; if ($row = $this->db->fetchRow($query, $this->id)) { $this->level = $row['new_warning_level']; $this->adjustment = $row['new_warning_level'] - $row['old_warning_level']; $this->reason = $row['warn_reason']; $this->action = $row['actiontaken']; $this->comments = $row['mod_comments']; $this->Date = new DateTime("@" . $row['warn_date']); $this->Recipient = UserFactory::CreateUser($row['user_id']); $this->Issuer = UserFactory::CreateUser($row['warned_by']); } return $this; }
/** * Populate this object * @since Version 3.9.1 * @return void */ private function load() { $query = "SELECT * FROM image_collection WHERE id = ?"; $row = $this->db->fetchRow($query, $this->id); $this->slug = $row['slug']; $this->name = $row['title']; $this->description = $row['description']; $this->DateCreated = new DateTime($row['created'], new DateTimeZone("Australia/Melbourne")); $this->DateModified = new DateTime($row['modified'], new DateTimeZone("Australia/Melbourne")); $this->setAuthor(UsersFactory::CreateUser($row['user_id'])); /* if (empty($this->slug) || $this->slug == 1) { $this->validate(); $this->commit(); } */ $this->makeURLs(); return; }