/** * Verify the changes before committing them * @since Version 3.2 * @return boolean */ public function validate() { if (empty($this->name)) { throw new Exception("Cannot validate Operator: the operator name cannot be empty"); } if (!filter_var($this->organisation_id, FILTER_VALIDATE_INT)) { $this->organisation_id = 0; } $this->name = ContentUtility::FormatTitle($this->name); return true; }
/** * Commit changes to this competition * @since Version 3.9.1 * @return \Railpage\Images\Competition */ public function commit() { $this->validate(); $data = array("title" => $this->title, "theme" => $this->theme, "description" => $this->description, "slug" => $this->slug, "status" => $this->status, "author" => $this->Author->id, "voting_date_open" => $this->VotingDateOpen instanceof DateTime ? $this->VotingDateOpen->format("Y-m-d H:i:s") : "0000-00-00 00:00:00", "voting_date_close" => $this->VotingDateClose instanceof DateTime ? $this->VotingDateClose->format("Y-m-d H:i:s") : "0000-00-00 00:00:00", "submissions_date_open" => $this->SubmissionsDateOpen instanceof DateTime ? $this->SubmissionsDateOpen->format("Y-m-d H:i:s") : "0000-00-00 00:00:00", "submissions_date_close" => $this->SubmissionsDateClose instanceof DateTime ? $this->SubmissionsDateClose->format("Y-m-d H:i:s") : "0000-00-00 00:00:00", "meta" => json_encode($this->meta)); if (filter_var($this->id, FILTER_VALIDATE_INT)) { $where = array("id = ?" => $this->id); $this->db->update("image_competition", $data, $where); } if (!filter_var($this->id, FILTER_VALIDATE_INT)) { $this->db->insert("image_competition", $data); $this->id = $this->db->lastInsertId(); } /** * Clear the cache */ $regkey = sprintf(self::CACHE_KEY, $this->id); $Redis = AppCore::GetRedis(); $Memcached = AppCore::GetMemcached(); $Redis->delete($regkey); $Memcached->delete($regkey); /** * Check our themes and see if we need to mark this theme as used */ $themes = (new Competitions())->getSuggestedThemes(); foreach ($themes as $key => $theme) { $theme['theme'] = ContentUtility::FormatTitle($theme['theme']); if ((!isset($theme['used']) || $theme['used'] === false) && $theme['theme'] === $this->theme) { $themes[$key]['used'] = true; } } $Config = new Config(); $Config->set("image.competition.suggestedthemes", json_encode($themes), "Photo competition themes"); $this->url = Utility\Url::makeCompetitionUrls($this); return $this; }
/** * Populate this object from an array * * @since Version 3.9.1 * @return void */ public function populateFromArray($row) { $this->provider = $row['provider']; $this->photo_id = $row['photo_id']; $this->Date = new DateTime($row['modified']); $this->DateCaptured = !isset($row['captured']) || is_null($row['captured']) ? null : new DateTime($row['captured']); $this->title = !empty($row['meta']['title']) ? ContentUtility::FormatTitle($row['meta']['title']) : "Untitled"; $this->description = $row['meta']['description']; $this->sizes = $row['meta']['sizes']; $this->links = $row['meta']['links']; $this->meta = $row['meta']['data']; $this->lat = $row['lat']; $this->lon = $row['lon']; #printArray($row['meta']);die; if (!$this->DateCaptured instanceof DateTime) { if (isset($row['meta']['data']['dates']['taken'])) { $this->DateCaptured = new DateTime($row['meta']['data']['dates']['taken']); } } /** * Normalize some sizes */ if (count($this->sizes)) { $this->sizes = Images::normaliseSizes($this->sizes); } $this->url = Utility\Url::CreateFromImageID($this->id); if (empty($this->mckey)) { $this->mckey = sprintf("railpage:image=%d", $this->id); } }
/** * Validate changes to this manufacturer * @return boolean * @throws \Exception if $this->name is empty */ public function validate() { if (empty($this->name)) { throw new Exception("Cannot validate changes to this locomotive manufacturer: manufacturer name cannot be empty"); } if (empty($this->slug)) { $proposal = ContentUtility::generateUrlSlug($this->name, 30); $query = "SELECT manufacturer_id FROM loco_manufacturer WHERE slug = ?"; $result = $this->db->fetchAll($query, $proposal); if (count($result)) { $proposal = $proposal . count($result); } $this->slug = $proposal; $this->url = new Url(sprintf("/locos/builder/%s", $this->slug)); } $this->name = ContentUtility::FormatTitle($this->name); return true; }
/** * Suggest a theme to add * @since Version 3.9.1 * @return \Railpage\Images\Competitions * @param string $theme The short descriptive text for the theme (eg "At night", "Close up", etc) * @param boolean $winner True/false flag indicating if this theme has been suggested by a competition winner */ public function suggestTheme($theme, $winner = null) { if (!$this->Author instanceof User) { throw new Exception("You have not set the author of this theme (hint: Competitions::setAuthor()"); } if (empty($theme)) { throw new Exception("You haven't entered any text..."); } $theme = ContentUtility::FormatTitle($theme); $themes = $this->getSuggestedThemes(); array_unshift($themes, ["user" => ["id" => $this->Author->id, "username" => $this->Author->username], "theme" => $theme, "winner" => $winner]); $Config = new Config(); $Config->set("image.competition.suggestedthemes", json_encode($themes), "Photo competition themes"); return $this; }
/** * Fetch stories from Sphinx * @since Version 3.9.1 * @return array * @param int $page * @param int $limit * @param boolean $total */ private function fetchStoriesFromSphinx($page = 0, $limit = 25, $total = true) { $Sphinx = $this->getSphinx(); $query = $Sphinx->select("*")->from("idx_news_article")->orderBy("story_time_unix", "DESC")->limit($page * $limit, $limit)->where("topic_id", "=", $this->id)->where("story_active", "=", 1)->option("max_matches", 10000); $matches = $query->execute(); $meta = $Sphinx->query("SHOW META"); $meta = $meta->execute(); if (is_array($matches) && count($matches)) { $return = array("total" => $meta[1]['Value'], "children" => array(), "page" => $page, "perpage" => $limit, "topic_id" => $this->id); foreach ($matches as $id => $row) { $row['time_relative'] = ContentUtility::relativeTime($row['story_time_unix']); $row['time'] = $row['story_time']; $row['title'] = ContentUtility::FormatTitle($row['story_title']); // Match the first sentence $line = explode("\n", !empty($row['story_lead']) ? $row['story_lead'] : $row['story_blurb']); $row['firstline'] = preg_replace('/([^?!.]*.).*/', '\\1', strip_tags($line[0])); if (empty($row['story_slug'])) { $row['slug'] = $this->createSlug($row['story_id']); } $row['url'] = $this->makePermaLink($row['story_slug']); $row['hometext'] = $row['story_blurb']; $row['bodytext'] = $row['story_body']; $row['featured_image'] = $row['story_image']; $row['informant'] = $row['username']; $return['children'][$id] = $row; } return $return; } return false; }
/** * 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; }
/** * Embed Flickr content from an OpenEmbed-friendly URL * @since Version 3.10.0 * @param \DOMElement $e * @param string $group * @return \DOMElement */ private static function drawFlickrFromOpenGraph(DOMElement $e, $group = null) { $og = ContentUtility::GetOpenGraphTags(pq($e)->attr("href")); $style = ["background-image: url(\"" . $og['image'] . "\")"]; $titlePrepend = ["flickr_photos:set" => "Photo album", "flickr_photos:photo" => "Photo"]; $titlePrepend = isset($titlePrepend[$og['type']]) ? $titlePrepend[$og['type']] . ": " : ""; if (empty($og['title'])) { $og['title'] = "Untitled"; } $og['title'] = ContentUtility::FormatTitle($og['title']); $mediaBlock = pq("<div />"); $mediaBlock->addClass("content-image")->addClass("content-flickr")->addClass("media"); $mediaBlock->attr("style", implode(";", $style)); $mediaBlock->html("<div class='media--content'><h1><a href='" . $og['url'] . "'>" . $titlePrepend . $og['title'] . "</a></h1><div class='media--lead'><a href='" . $og['url'] . "'>" . $og['description'] . "</a></div></div>"); $mediaBlockWrapper = pq("<div />"); $mediaBlockWrapper->addClass("content-image-wrapper"); //$mediaBlockWrapper->attr('style', "height: 0;padding-bottom: 56.25%;position: relative;margin-bottom:1.4em;"); $mediaBlockWrapper->html($mediaBlock); if (pq($e)->hasClass("embed-group")) { $mediaBlockWrapper->addClass("embed-group-member"); } pq($e)->replaceWith($mediaBlockWrapper); return $e; }
/** * Validate this event * @since Version 3.8.7 * @return boolean * @throws Exception if $this->title is empty * @throws Exception if $this->desc is empty * @throws Exception if $this->Category is not an instance of Railpage\Events\EventCategory */ private function validate() { if (empty($this->title)) { throw new Exception("Validation failed for event. Title cannot be empty"); } if (empty($this->desc)) { throw new Exception("Validation failed for event. Description cannot be empty"); } if (!$this->Category instanceof EventCategory) { throw new Exception("Validation failed for event. Event must have a category!"); } if (!isset($this->slug) || empty($this->slug)) { $this->createSlug(); } if (!filter_var($this->status)) { $this->status = Events::STATUS_UNAPPROVED; } if (!$this->Author instanceof User) { throw new Exception("A valid user object must be set (hint: Event::setAuthor()"); } $this->title = ContentUtility::FormatTitle($this->title); return true; }