/**
  * Assign UTM parameters to an individual URL
  * @since Version 3.10.0
  * @param \Railpage\Newsletters\Newsletter $Newsletter
  * @param string $url
  * @return string
  */
 public static function CreateUTMParametersForLink(Newsletter $Newsletter, $url)
 {
     if (is_array($url)) {
         $url = $url['url'];
     }
     $utm = ["utm_source=newsletter", "utm_medium=email", sprintf("utm_campaign=%s", ContentUtility::generateUrlSlug($Newsletter->subject))];
     $parts = parse_url($url);
     if (!isset($parts['query'])) {
         $url .= "?" . implode("&", $utm);
         return $url;
     }
     $parts['query'] = array_merge(explode("&", $parts['query']), $utm);
     return ContentUtility::unparse_url($parts);
 }
 public function test_relativeTime()
 {
     $this->assertEquals("4 seconds ago", ContentUtility::relativeTime(new DateTime("4 seconds ago"), new DateTime()));
     $this->assertEquals("one minute ago", ContentUtility::relativeTime(strtotime("1 minutes ago")));
     $this->assertEquals("4 minutes ago", ContentUtility::relativeTime(strtotime("4 minutes ago")));
     $this->assertEquals("4 hours ago", ContentUtility::relativeTime(strtotime("4 hours ago")));
     $this->assertEquals("yesterday", ContentUtility::relativeTime(strtotime("24 hours ago")));
     $this->assertEquals("2 days ago", ContentUtility::relativeTime(strtotime("2 days ago")));
     $this->assertEquals("one week ago", ContentUtility::relativeTime(strtotime("7 days ago")));
     $this->assertEquals("2 weeks ago", ContentUtility::relativeTime(strtotime("14 days ago")));
     $this->assertEquals("4 weeks ago", ContentUtility::relativeTime(strtotime("1 month ago")));
     $this->assertEquals("2 months ago", ContentUtility::relativeTime(strtotime("2 months ago")));
     $this->assertEquals("last year", ContentUtility::relativeTime(strtotime("12 months ago")));
     $this->assertEquals("10 years ago", ContentUtility::relativeTime(strtotime("10 years ago")));
     $this->assertEquals("3 years ago", ContentUtility::relativeTime(strtotime("5 years ago"), new DateTime("2 years ago")));
 }
示例#3
0
 /**
  * Add an asset
  * @since Version 3.9.1
  * @param string $namespace
  * @param int $id
  * @param array $data
  * @return void
  */
 public static function addAsset($namespace, $id, $data)
 {
     if (!is_array($data)) {
         throw new Exception("Cannot add asset - \$data must be an array");
         return false;
     }
     $Database = (new AppCore())->getDatabaseConnection();
     $data = array_merge($data, array("date" => new Zend_Db_Expr("NOW()"), "namespace" => $namespace, "namespace_key" => $id));
     $meta = json_encode($data['meta']);
     /**
      * Handle UTF8 errors
      */
     if (!$meta && json_last_error() === JSON_ERROR_UTF8) {
         $data['meta'] = ContentUtility::FixJSONEncode_UTF8($data['meta']);
     } else {
         $data['meta'] = $meta;
     }
     $Database->insert("asset", $data);
     return true;
 }
示例#4
0
 /**
  * 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;
 }
示例#5
0
 /**
  * Make a URL slug
  * @since Version 3.9.1
  * @package Railpage
  * @author Michael Greenhill
  * @return void
  */
 private function makeSlug()
 {
     if (!empty($this->slug)) {
         return;
     }
     $proposal = ContentUtility::generateUrlSlug($this->name, 20);
     $query = "SELECT COUNT(id) FROM glossary WHERE slug = ?";
     $num = $this->db->fetchOne($query, $proposal);
     if ($num) {
         $proposal .= $num;
     }
     $this->slug = $proposal;
     if (filter_var($this->id, FILTER_VALIDATE_INT)) {
         $this->commit();
     }
     return;
 }
示例#6
0
 /**
  * Validate changes
  * @since Version 3.10.0
  * @return boolean
  */
 private function validate()
 {
     if (empty($this->title)) {
         throw new Exception("Title cannot be empty");
     }
     if (!$this->date instanceof DateTime) {
         $this->date = new DateTime();
     }
     if (empty($this->hits)) {
         $this->hits = 0;
     }
     if (empty($this->language)) {
         $this->language = "english";
     }
     if (empty($this->permalink)) {
         $prop = ContentUtility::generateUrlSlug($this->title);
         if ($rs = $this->db->fetchAll("SELECT pid FROM nuke_pages WHERE shortname = ?", $prop)) {
             $prop .= count($rs);
         }
         $this->permalink = $prop;
     }
     return true;
 }
示例#7
0
 /**
  * Format an avatar
  * @since Version 3.9.1
  * @return string
  * @param string $userAvatar
  * @param int $width
  * @param width $height
  */
 public static function format($userAvatar = null, $width = 100, $height = 100)
 {
     if (is_null($userAvatar)) {
         return false;
     }
     $cacheHandler = AppCore::getMemcached();
     $timer = Debug::getTimer();
     if ($userAvatar == "http://www.railpage.com.au/modules/Forums/images/avatars/https://static.railpage.com.au/image_resize") {
         $userAvatar = self::DEFAULT_AVATAR;
     }
     if (empty($userAvatar) || stristr($userAvatar, "blank.gif") || stristr($userAvatar, "blank.png")) {
         $userAvatar = self::DEFAULT_AVATAR;
         return $userAvatar;
     }
     $parts = parse_url($userAvatar);
     if (isset($parts['host']) && $parts['host'] == "static.railpage.com.au" && isset($parts['query'])) {
         parse_str($parts['query'], $query);
         if (isset($query['w']) && isset($query['h']) && isset($query['image'])) {
             if ($query['w'] == $width && $query['h'] == $height) {
                 return $userAvatar;
             }
             return sprintf("http://static.railpage.com.au/image_resize.php?w=%d&h=%d&image=%s", $width, $height, $query['image']);
         }
     }
     if (isset($parts['host']) && $parts['host'] == "www.gravatar.com" && isset($parts['query'])) {
         parse_str($parts['query'], $query);
         $query['s'] = $width;
         $bits = array();
         foreach ($query as $key => $val) {
             $bits[] = sprintf("%s=%s", $key, $val);
         }
         $userAvatar = sprintf("%s://%s%s?%s", $parts['scheme'], $parts['host'], $parts['path'], implode("&", $bits));
         return self::GravatarHTTPS($userAvatar);
     }
     $mckey = sprintf("railpage.user:avatar=%s;width=%s;height=%s", $userAvatar, $width, $height);
     /**
      * Check if this shit is in Memcache first
      */
     if ($result = $cacheHandler->fetch($mckey)) {
         return self::GravatarHTTPS($result);
     }
     /**
      * It's not in Memcached, so let's process and cache it
      */
     parse_str(parse_url($userAvatar, PHP_URL_QUERY), $args);
     if (isset($args['base64_args'])) {
         if (!@unserialize(base64_decode($args['base64_args']))) {
             // Malformed string!
             $userAvatar = self::DEFAULT_AVATAR;
         } else {
             // Do other stuff...
             $base64 = unserialize(base64_decode($args['base64_args']));
         }
     }
     if (preg_match("@modules/Forums/images/avatars/(http\\:\\/\\/|https\\:\\/\\/)@", $userAvatar)) {
         $userAvatar = self::DEFAULT_AVATAR;
     }
     if (!preg_match("@(http\\:\\/\\/|https\\:\\/\\/)@", $userAvatar)) {
         $userAvatar = "http://static.railpage.com.au/modules/Forums/images/avatars/" . $userAvatar;
     }
     if (!ContentUtility::url_exists($userAvatar)) {
         $userAvatar = self::DEFAULT_AVATAR;
     }
     if ($width && !$height) {
         $height = $width;
     }
     // Is this an anigif?
     if (substr($userAvatar, -4, 4) == ".gif") {
         // Fetch the dimensions
         $mckey = "railpage:avatar.size=" . md5($userAvatar);
         if ($dimensions = $cacheHandler->fetch($mckey)) {
             // Do nothing
         } else {
             $dimensions = @getimagesize($userAvatar);
             $cacheHandler->save($mckey, $dimensions);
         }
         if (isset($dimensions['mime']) && $dimensions['mime'] == "image/gif") {
             // Great, it's a gif
             if ($width && $height) {
                 if ($dimensions[0] <= $width && $dimensions[1] <= $height) {
                     // It fits within the width and height - return it as-is
                     return self::GravatarHTTPS($userAvatar);
                 }
             }
         }
     }
     // Assume that all avatars created on dev.railpage.com.au are shit and should be re-directed to static.railpage.com.au
     $userAvatar = str_replace("dev.railpage.com.au", "static.railpage.com.au", $userAvatar);
     if ($width && $height) {
         $args['width'] = $width;
         $args['height'] = $height;
         $args['url'] = $userAvatar;
         if (empty($userAvatar)) {
             $args['url'] = self::DEFAULT_AVATAR;
         }
         #$userAvatar = "https://static.railpage.com.au/image_resize.php?base64_args=".base64_encode(serialize($args));
         $userAvatar = sprintf("https://static.railpage.com.au/image_resize.php?w=%d&h=%d&image=%s", $args['width'], $args['height'], $args['url']);
         if ($width == $height) {
             $userAvatar .= "&square=true";
         }
     }
     $cacheHandler->save($mckey, $userAvatar, 0);
     Debug::logEvent(__METHOD__, $timer);
     return self::GravatarHTTPS($userAvatar);
 }
示例#8
0
 /**
  * Create a URL slug
  * @since Version 3.9.1
  */
 private function createSlug()
 {
     $proposal = ContentUtility::generateUrlSlug($this->name);
     $result = $this->db->fetchAll("SELECT id_cat FROM nuke_faqCategories WHERE url_slug = ?", $proposal);
     if (count($result)) {
         $proposal .= count($result);
     }
     $this->url_slug = $proposal;
 }
示例#9
0
 /**
  * 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;
 }
示例#10
0
 /**
  * Generate the URL slug for this help item
  * @since Version 3.8.6
  * @return string
  */
 private function createSlug()
 {
     $proposal = ContentUtility::generateUrlSlug($this->title);
     /**
      * Check that we haven't used this slug already
      */
     $result = $this->db->fetchAll("SELECT id FROM nuke_faqAnswer WHERE url_slug = ?", $proposal);
     if (count($result)) {
         $proposal .= count($result);
     }
     /**
      * Return it
      */
     return $proposal;
 }
示例#11
0
 /**
  * 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;
 }
示例#12
0
 /**
  * Validate changes to this camera
  * @since Version 3.10.0
  * @throws \Exception if $this->name is empty
  * @throws \Exception if $this->manufacturer is empty
  * @return boolean
  */
 private function validate()
 {
     if (empty($this->name)) {
         throw new Exception("Camera name is empty");
     }
     if (empty($this->manufacturer)) {
         throw new Exception("Manufacturer name is empty");
     }
     if (empty($this->slug)) {
         $this->slug = ContentUtility::generateUrlSlug(sprintf("%s %s", $this->manufacturer, $this->name));
         try {
             $count = $this->db->fetchAll("SELECT id FROM image_camera WHERE url_slug = ?", $this->slug);
             if (count($count)) {
                 $this->slug .= count($count);
             }
         } catch (Exception $e) {
             // Don't care
         }
     }
     return true;
 }
示例#13
0
 /**
  * Render the page 
  * @since Version 3.10.0
  * @return string
  */
 public function render()
 {
     if (!$this->userObject instanceof User) {
         throw new InvalidArgumentException("No valid user object has been provided");
     }
     #$this->smarty->clearCache($this->template, $this->unique);
     if ($this->smarty->isCached($this->template, $this->unique)) {
         Debug::LogCLI("!! Template file " . $this->template . " is already cached for unique ID " . $this->unique);
         return $this->smarty->fetch($this->template, $this->unique);
     }
     Debug::LogCLI("Template file " . $this->template . " is NOT cached for unique ID \"" . $this->unique . "\"");
     /**
      * Get user alerts
      */
     if (!$this->userObject->guest) {
         global $acl;
         $alerts = $this->userObject->getAlerts($acl);
         $this->smarty->Assign("alerts", $alerts, true);
     }
     /**
      * Get the latest jobs
      */
     $newjobs = array();
     foreach ((new Jobs())->yieldNewJobs(5) as $Job) {
         $newjobs[] = $Job->getArray();
     }
     $this->smarty->Assign("jobs", $newjobs, true);
     /**
      * Upcoming events
      */
     $Memcached = AppCore::GetMemcached();
     $cachekey = "railpage.home.upcomingevents";
     $upcoming = [];
     if (!($upcoming = $Memcached->fetch($cachekey))) {
         $Events = new Events();
         $upcoming = [];
         foreach ($Events->getUpcomingEvents(5) as $row) {
             //$Event = EventsFactory::CreateEvent($row['event_id']);
             $EventDate = new EventDate($row['id']);
             $data = $EventDate->getArray();
             $upcoming[] = $data;
         }
         $Memcached->save("railpage.home.upcomingevents", $upcoming, strtotime("+5 minutes"));
     }
     $this->smarty->Assign("upcomingevents", $upcoming);
     /**
      * New photos
      */
     $this->smarty->Assign("newphotos", RecentImages::getNewest(5));
     /**
      * Chronicle
      */
     $Chronicle = new Chronicle();
     $this->smarty->Assign("chronicle", $Chronicle->getEntriesForToday(10));
     /**
      * Get the latest railcam photo
      */
     $Camera = new Camera(1);
     $Photo = $Camera->getLatest(false);
     $railcam = $Photo->getArray();
     $railcam['sizes']['small']['source'] = ImageCache::cache($railcam['sizes']['small']['source']);
     $this->smarty->Assign("railcam", $railcam);
     $this->smarty->Assign("railcam_updated", ContentUtility::relativeTime($railcam['dates']['taken']));
     /**
      * First check if this user has a personalised news feed
      */
     if (filter_var($this->userObject->id, FILTER_VALIDATE_INT) && $this->userObject->id > 0) {
         $Feed = new Feed();
         $Feed->setUser($this->userObject)->getFilters();
         if (count($Feed->filter_words) || count($Feed->filter_topics)) {
             $latest = $Feed->findArticles(0, 20);
             foreach ($latest 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'] = $article['topic_title'];
                 $article['topic'] = $article['topic_id'];
                 $article['featured_image'] = $article['story_image'];
                 $article['title'] = $article['story_title'];
                 $article['time_relative'] = time2str($article['story_time_unix']);
                 $latest[$id] = $article;
             }
         }
     }
     $this->smarty->Assign("personalfeed", isset($latest));
     /**
      * No personal news feed - go ahead as normal
      */
     if (!isset($latest)) {
         /**
          * Instantiate the base News module
          */
         $News = new Base();
         /**
          * Get the latest 15 news articles
          */
         $latest = $News->latest(20);
     }
     /**
      * Format titles and tags for the latest news articles
      */
     foreach ($latest as $id => $data) {
         /**
          * Load the JSON for this article
          */
         if (!isset($data['sid'])) {
             $data['sid'] = $data['story_id'];
         }
         $json = json_decode(News::getArticleJSON($data['sid']), true);
         $latest[$id]['hometext'] = isset($json['article']['blub']) ? wpautop(process_bbcode($json['article']['blub'])) : wpautop(process_bbcode($json['article']['blurb']));
         $latest[$id]['hometext'] = strip_tags($latest[$id]['hometext'], "<a><p><img><br><br /><strong><em>");
         $latest[$id]['title'] = format_topictitle($data['title']);
         $latest[$id]['topic'] = $json['article']['topic'];
         $latest[$id]['topic_highlight'] = ColourUtility::String2Hex($latest[$id]['topic_title']);
         $latest[$id]['url'] = $json['article']['url'];
         $latest[$id]['author'] = $json['article']['author'];
         $latest[$id]['staff'] = $json['article']['staff'];
         if (!empty($latest[$id]['featured_image'])) {
             $latest[$id]['featured_image'] = ImageCache::cache($latest[$id]['featured_image']);
         }
         // Get the first paragraph from the home text
         preg_match("/<p>(.*)<\\/p>/", $latest[$id]['hometext'], $matches);
         $latest[$id]['hometext'] = strip_tags($matches[1]);
         if (empty($json['article']['body']) && !empty($json['article']['source'])) {
             $latest[$id]['url'] = $json['article']['source'];
         }
         /**
          * Pre-rendering
          */
         $this->smarty->addHeadTag(sprintf("<link rel='prerender' href='%s'>", $json['article']['url']['url']));
     }
     /**
      * Slice the first news article off
      */
     $newsLatest = array_shift($latest);
     /**
      * Send them to Smarty
      */
     $this->smarty->assign("newsLatest", $newsLatest);
     $this->smarty->assign("news", $latest);
     $this->smarty->assign("pagecontrols", '<p style="background: #333; background: rgba(0, 0, 0, 0.6);margin: -20px;padding: 10px;margin-top: 20px; text-align: center;">Wasting time and bandwidth since 1992</p>');
     if ($this->params['handheld']) {
         $this->smarty->assign("pagecontrols", '<p style="background: #333; background: rgba(0, 0, 0, 0.6);margin: 0px -20px;padding: 0px;margin-top: 40px; text-align: center;font-size:1em;">Wasting time and bandwidth since 1992</p>');
     }
     return $this->smarty->fetch($this->template, $this->unique);
 }
示例#14
0
 /**
  * Generate the URL slug
  * @since Version 3.7.5
  * @param int $id
  * @param string $name
  * @return string
  */
 public function createSlug($id = false, $name = false)
 {
     $timer = Debug::GetTimer();
     if (filter_var($id, FILTER_VALIDATE_INT) && !$name) {
         $name = $this->db->fetchOne("SELECT organisation_name FROM organisation WHERE organisation_id = ?", $id);
     } elseif (filter_var($id, FILTER_VALIDATE_INT) && is_string($name)) {
         // Do nothing
     } elseif (isset($this->name) && !empty($this->name)) {
         $name = $this->name;
         $id = $this->id;
     } else {
         return false;
     }
     $proposal = ContentUtility::generateUrlSlug($name, 200);
     /**
      * Check that we haven't used this slug already
      */
     $result = $this->db->fetchAll("SELECT organisation_id FROM organisation WHERE organisation_slug = ? AND organisation_id != ?", array($proposal, $id));
     if (count($result)) {
         $proposal .= count($result);
     }
     if (isset($this->slug) || empty($this->slug)) {
         $this->slug = $proposal;
     }
     /**
      * Add this slug to the database
      */
     $data = array("organisation_slug" => $proposal);
     $where = array("organisation_id = ?" => $id);
     $rs = $this->db->update("organisation", $data, $where);
     Debug::LogEvent(__METHOD__, $timer);
     /**
      * Return it
      */
     return $proposal;
 }
示例#15
0
 /**
  * Make a URL slug for a camera from brand and model
  * @since Version 3.10.0
  * @param string $make
  * @param string $model
  * @return string
  */
 public static function makeCameraUrlSlug($make, $model)
 {
     $prop = ContentUtility::generateUrlSlug(sprintf("%s %s", $make, $model), 30);
     return $prop;
 }
示例#16
0
 /**
  * Validate changes to this album
  * @since Version 3.10.0
  * @return boolean
  * @throws \Exception if $this->name is empty
  * @throws \Exception if $this->Author is empty
  */
 private function validate()
 {
     if (empty($this->name)) {
         throw new Exception("Album name is empty");
     }
     if (empty($this->slug)) {
         $this->slug = ContentUtility::generateUrlSlug($this->name, 30);
         $query = "SELECT id FROM gallery_mig_album WHERE name = ?";
         $rs = $this->db->fetchAll($query, $this->slug);
         if (count($rs)) {
             $this->slug .= count($rs);
         }
     }
     if (!$this->Owner instanceof User) {
         $this->Owner = $this->getOwner();
     }
     if (!$this->Owner instanceof User) {
         throw new Exception("No valid album owner has been set");
     }
     return true;
 }
示例#17
0
 /**
  * Create a URL slug
  * @since Version 3.7.5
  * @return void
  */
 private function createSlug()
 {
     $proposal = ContentUtility::generateUrlSlug($this->name);
     $result = $this->db->fetchAll("SELECT id FROM location WHERE slug = ?", $proposal);
     if (count($result)) {
         $proposal .= count($result);
     }
     $this->slug = $proposal;
 }
示例#18
0
 /**
  * Create a URL slug
  * @since Version 3.9.1
  */
 private function createSlug()
 {
     $proposal = ContentUtility::generateUrlSlug($this->width_metric);
     $result = $this->db->fetchAll("SELECT gauge_id FROM loco_gauge WHERE slug = ?", $proposal);
     if (count($result)) {
         $proposal .= count($result);
     }
     $this->slug = $proposal;
     return $this->slug;
 }
示例#19
0
 /**
  * Validate changes to this locotype 
  * @since Version 3.8.7
  * @return true
  * @throws \Exception if $this->arrangement is empty
  */
 public function validate()
 {
     if (empty($this->name)) {
         throw new Exception("Cannot validate changes to this loco type: name cannot be empty");
         return false;
     }
     if (empty($this->slug)) {
         $proposal = ContentUtility::generateUrlSlug($this->name, 30);
         $query = "SELECT id FROM loco_type WHERE slug = ?";
         $result = $this->db->fetchAll($query, $proposal);
         if (count($result)) {
             $proposal = $proposal . count($result);
         }
         $this->slug = $proposal;
         $this->url = new Url(sprintf("%s/type/%s", $this->Module->url, $this->slug));
     }
     return true;
 }
示例#20
0
 /**
  * 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;
 }
示例#21
0
 /**
  * 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;
 }
示例#22
0
 /**
  * Create a URL slug
  * @since Version 3.8.7
  */
 private function createSlug()
 {
     if (!empty($this->slug)) {
         return;
     }
     $proposal = ContentUtility::generateUrlSlug($this->name, 14);
     $result = $this->db->fetchAll("SELECT id FROM event_categories WHERE slug = ?", $proposal);
     if (count($result)) {
         $proposal .= count($result);
     }
     $this->slug = $proposal;
 }
示例#23
0
 /**
  * Get this sighting as an associative array
  * @since Version 3.10.0
  * @return array
  */
 public function getArray()
 {
     $array = array("id" => $this->id, "lat" => $this->lat, "lon" => $this->lon, "text" => $this->text, "author" => array("id" => $this->user_id, "username" => $this->username), "timezone" => $this->timezone, "date" => array("added" => array("absolute" => $this->date_added->format("Y-m-d H:i:s"), "relative" => ContentUtility::relativeTime($this->date_added)), "seen" => array("absolute" => $this->date->format("Y-m-d H:i:s"), "relative" => ContentUtility::relativeTime($this->date))), "loco_ids" => $this->loco_ids, "meta" => $this->meta, "url" => $this->url->getURLs(), "place" => $this->Place->getArray());
     return $array;
 }
示例#24
0
 /**
  * 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;
 }
示例#25
0
 /**
  * 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;
 }
示例#26
0
 /**
  * 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;
 }
示例#27
0
 /**
  * Commit changes to this locomotive
  * @since Version 3.9.1
  * @return \Railpage\Locos\Date
  */
 public function commit()
 {
     $this->validate();
     $data = array("loco_unit_id" => $this->Loco->id, "loco_date_id" => $this->action_id, "date" => $this->Date->getTimestamp(), "date_end" => $this->DateEnd instanceof DateTime ? $this->DateEnd->format("Y-m-d") : NULL, "timestamp" => $this->Date->format("Y-m-d"), "text" => $this->text, "meta" => json_encode($this->meta));
     if (filter_var($this->id)) {
         $this->Redis->delete($this->mckey);
         $where = array("date_id = ?" => $this->id);
         $this->db->update("loco_unit_date", $data, $where);
     } else {
         $this->db->insert("loco_unit_date", $data);
         $this->id = $this->db->lastInsertId();
     }
     if (isset($this->Loco->meta['construction_cost'])) {
         $this->Loco->meta['construction_cost_inflated'] = ContentUtility::convertCurrency($this->Loco->meta['construction_cost'], Utility\LocomotiveUtility::getConstructionDate($this->Loco));
         $this->Loco->commit();
     }
     return $this;
 }
示例#28
0
 /**
  * Generate the JSON data string
  *
  * @return $this
  */
 public function getJSON()
 {
     if (isset($this->author)) {
         $author = clone $this->author;
         if (isset($author->User) && $author->User instanceof User) {
             $author->User = $author->User->getArray();
         }
     }
     $data = array("id" => $this->id, "title" => $this->title, "description" => $this->description, "score" => $this->getScore(), "provider" => array("name" => $this->provider, "photo_id" => $this->photo_id), "sizes" => Images::NormaliseSizes($this->sizes), "srcset" => implode(", ", Utility\ImageUtility::generateSrcSet($this)), "author" => isset($author) ? $author : false, "url" => $this->url instanceof Url ? $this->url->getURLs() : array(), "dates" => array());
     $times = ["posted", "taken"];
     #printArray($this->meta['dates']);die;
     foreach ($times as $time) {
         if (isset($this->meta['dates'][$time])) {
             $Date = filter_var($this->meta['dates'][$time], FILTER_VALIDATE_INT) ? new DateTime("@" . $this->meta['dates'][$time]) : new DateTime($this->meta['dates'][$time]);
             $data['dates'][$time] = array("absolute" => $Date->format("Y-m-d H:i:s"), "nice" => $Date->Format("d H:i:s") == "01 00:00:00" ? $Date->Format("F Y") : $Date->format("F j, Y, g:i a"), "relative" => ContentUtility::RelativeTime($Date));
         }
     }
     if ($this->Place instanceof Place) {
         $data['place'] = array("url" => $this->Place->url, "lat" => $this->Place->lat, "lon" => $this->Place->lon, "name" => $this->Place->name, "country" => array("code" => $this->Place->Country->code, "name" => $this->Place->Country->name, "url" => $this->Place->Country->url));
     }
     $this->json = json_encode($data);
     return $this;
 }
示例#29
0
 /**
  * Return additional head tags in a concatenated string
  * @since Version 3.8 
  * @return string
  */
 public function getHeadTags()
 {
     $tags = array();
     if (count($this->rp_meta_tags)) {
         foreach ($this->rp_meta_tags as $property => $content) {
             $tag = '<meta property="' . $property . '" content="' . htmlentities(ContentUtility::formatText($content, ["strip_formatting" => true])) . '">';
             if ($property == "og:image" || $property == "twitter:image") {
                 $tag = str_replace("&amp;", "&", $tag);
             }
             $tags[] = $tag;
         }
     }
     if (count($this->head_links)) {
         foreach ($this->head_links as $rel => $href) {
             $tag = '<link rel="' . $rel . '" href="' . htmlentities($href) . '">';
             $tags[] = $tag;
         }
     }
     if (count($this->preload['prefetch'])) {
         foreach ($this->preload['prefetch'] as $href) {
             $tag = '<link rel="prefetch" href="' . htmlentities($href) . '">';
             $tags[] = $tag;
         }
     }
     if (count($this->preload['prerender'])) {
         foreach ($this->preload['prerender'] as $href) {
             $tag = '<link rel="prerender" href="' . htmlentities($href) . '">';
             $tags[] = $tag;
         }
     }
     return implode("\n\t", array_merge($tags, $this->head_tags));
 }
示例#30
0
 /**
  * Extract a user's timeline 
  * @since Version 3.9.1
  * @param \DateTime|int $dateFrom
  * @param \DateTime|int $dateTo
  * @return array
  */
 public function GenerateTimeline($dateFrom, $dateTo)
 {
     $page = false;
     $items_per_page = false;
     if (!$this->User instanceof User) {
         throw new InvalidArgumentException("No user object has been provided (hint: " . __CLASS__ . "::setUser(\$User))");
     }
     if (filter_var($dateFrom, FILTER_VALIDATE_INT)) {
         $page = $dateFrom;
     }
     if (filter_var($dateTo, FILTER_VALIDATE_INT)) {
         $items_per_page = $dateTo;
     }
     /**
      * Filter out forums this user doesn't have access to
      */
     $forum_post_filter = $this->getFilteredForums();
     if ($page && $items_per_page) {
         $query = "SELECT SQL_CALC_FOUND_ROWS * FROM log_general WHERE user_id = ? " . $forum_post_filter . " ORDER BY timestamp DESC LIMIT ?, ?";
         $offset = ($page - 1) * $items_per_page;
         $params = array($this->User->id, $offset, $items_per_page);
     }
     if (!$page || !$items_per_page) {
         $query = "SELECT SQL_CALC_FOUND_ROWS * FROM log_general WHERE user_id = ? " . $forum_post_filter . " AND timestamp >= ? AND timestamp <= ? ORDER BY timestamp DESC";
         $params = array($this->User->id, $dateFrom->format("Y-m-d H:i:s"), $dateTo->format("Y-m-d H:i:s"));
     }
     $timeline = array("total" => 0);
     if ($result = $this->db->fetchAll($query, $params)) {
         if ($page && $items_per_page) {
             $timeline['page'] = $page;
             $timeline['perpage'] = $items_per_page;
         }
         if (!$page || !$items_per_page) {
             $timeline['start'] = $dateFrom->format("Y-m-d H:i:s");
             $timeline['end'] = $dateTo->format("Y-m-d H:i:s");
         }
         $timeline['total'] = $this->db->fetchOne("SELECT FOUND_ROWS() AS total");
         foreach ($result as $row) {
             $row['args'] = json_decode($row['args'], true);
             $row['timestamp'] = new DateTime($row['timestamp']);
             $timeline['timeline'][$row['id']] = $row;
         }
     }
     /**
      * Process the timeline data
      */
     if (!isset($timeline['timeline'])) {
         return $timeline;
     }
     foreach ($timeline['timeline'] as $key => $row) {
         // Set their timezone
         $row['timestamp']->setTimezone(new DateTimeZone($this->User->timezone));
         if (stristr($row['title'], "loco") && empty($row['module'])) {
             $row['module'] = "locos";
         }
         /**
          * Check if the meta data array exists
          */
         if (!isset($row['meta'])) {
             $row['meta'] = array("id" => NULL, "namespace" => NULL);
         }
         /**
          * Format our data for grammatical and sentence structural purposes
          */
         $row = $this->processGrammar($row);
         /**
          * Alter the object if needed
          */
         $row = Timeline\Utility\General::formatObject($row);
         /**
          * Set the module namespace
          */
         $row['meta']['namespace'] = Timeline\Utility\General::getModuleNamespace($row);
         /**
          * Attempt to create a link to this object or action if none exists
          */
         $row['meta']['url'] = Timeline\Utility\Url::createUrl($row);
         /**
          * Attempt to create a meta object title for this object or action if none exists
          */
         $row = Timeline\Utility\ObjectTitle::generateTitle($row);
         /**
          * Compact it all together and create a succinct message
          */
         $row['action'] = Timeline\Utility\General::compactEvents($row);
         /**
          * Create the timestamp
          */
         $row['timestamp_nice'] = ContentUtility::relativeTime($row['timestamp']);
         /**
          * Determine the icon
          */
         $row['glyphicon'] = Timeline\Utility\General::getIcon($row);
         $timeline['timeline'][$key] = $row;
     }
     return $timeline;
 }