Adding lazy-load version of feed component to load data using AJAX after page content has been rendered.
This commit is contained in:
39
www/plugins/jasonwilliams/feed/Plugin.php
Normal file
39
www/plugins/jasonwilliams/feed/Plugin.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php namespace jasonwilliams\feed;
|
||||
|
||||
use System\Classes\PluginBase;
|
||||
use JasonWilliams\Feed\Classes\SocialApis;
|
||||
|
||||
class Plugin extends PluginBase
|
||||
{
|
||||
public function registerSettings()
|
||||
{
|
||||
return [
|
||||
'settings' => [
|
||||
'label' => 'Feed',
|
||||
'description' => 'Manage API keys and settings related to the feed plugin',
|
||||
'icon' => 'icon-newspaper-o',
|
||||
'class' => 'JasonWilliams\Feed\Models\Settings',
|
||||
'order' => 500,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function registerComponents()
|
||||
{
|
||||
return [
|
||||
'\JasonWilliams\Feed\Components\ShortFeed' => 'ShortFeed',
|
||||
'\JasonWilliams\Feed\Components\LazyLoadShortFeed' => 'LazyLoadShortFeed',
|
||||
'\JasonWilliams\Feed\Components\ChannelList' => 'ChannelList',
|
||||
'\JasonWilliams\Feed\Components\TagList' => 'TagList'
|
||||
];
|
||||
}
|
||||
|
||||
public function registerSchedule($schedule)
|
||||
{
|
||||
$schedule->call(function() {
|
||||
SocialApis::updateTwitter();
|
||||
SocialApis::updateInstagram();
|
||||
SocialApis::updateFoursquare();
|
||||
})->everyThirtyMinutes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
$(() => {
|
||||
var obj = {};
|
||||
if (typeof renderPartial !== 'string') obj = { '@feed': '#feedarea' }
|
||||
else obj[renderPartial] = '#feedarea'
|
||||
|
||||
$.request('LazyLoadShortFeed::onUpdateRequested', {
|
||||
update: obj,
|
||||
complete: () => { $(window).trigger('feedLoaded') }
|
||||
})
|
||||
})
|
||||
287
www/plugins/jasonwilliams/feed/classes/SocialApis.php
Normal file
287
www/plugins/jasonwilliams/feed/classes/SocialApis.php
Normal file
@@ -0,0 +1,287 @@
|
||||
<?php namespace JasonWilliams\Feed\Classes;
|
||||
|
||||
use JasonWilliams\Feed\Models\Settings;
|
||||
use JasonWilliams\Feed\Models\FeedItem;
|
||||
use October\Rain\Network\Http;
|
||||
|
||||
class SocialApis
|
||||
{
|
||||
// Update the database with the latest tweets
|
||||
public static function updateTwitter()
|
||||
{
|
||||
$tweets = self::fetchTwitter();
|
||||
|
||||
if (sizeof($tweets) > 0)
|
||||
{
|
||||
foreach ($tweets as $tweet)
|
||||
{
|
||||
// Skip tweets created by IFTTT if they have an image attached (because they came from Instagram)
|
||||
if (!isset($tweet['retweet_status']) && strpos($tweet['source'], "IFTTT") && isset($tweet['entities']['media'])) continue;
|
||||
|
||||
// Skip any tweets created by Foursquare
|
||||
if (!isset($tweet['retweet_status']) && strpos($tweet['source'], "Foursquare")) continue;
|
||||
|
||||
$extradata = array();
|
||||
|
||||
// Get the timestamp before we go down a layer to retweets
|
||||
$timestamp = strtotime($tweet['created_at']);
|
||||
|
||||
// Set extra data if this is a retweet
|
||||
if (isset($tweet['retweeted_status']))
|
||||
{
|
||||
$tweet = $tweet['retweeted_status'];
|
||||
$extradata['opuser'] = $tweet['user']['screen_name'];
|
||||
$extradata['opname'] = $tweet['user']['name'];
|
||||
$extradata['opimg'] = $tweet['user']['profile_image_url_https'];
|
||||
}
|
||||
|
||||
// Set extra data if there's an attached image
|
||||
if (isset($tweet['entities']['media'])) $extradata['img'] = $tweet['entities']['media'][0]['media_url_https'];
|
||||
|
||||
// Convert any extra data into a JSON object
|
||||
$extradata = (sizeof($extradata) > 0) ? json_encode($extradata) : "";
|
||||
|
||||
// Create a new FeedItem
|
||||
$feeditem = new FeedItem;
|
||||
$feeditem->timestamp = $timestamp;
|
||||
$feeditem->channel_id = 2;
|
||||
$feeditem->title = $tweet['full_text'];
|
||||
$feeditem->link = "https://twitter.com/i/web/status/".$tweet['id_str'];
|
||||
$feeditem->extra = $extradata;
|
||||
$feeditem->save();
|
||||
|
||||
// Are there links to include?
|
||||
if (sizeof($tweet['entities']['urls']) > 0)
|
||||
{
|
||||
foreach ($tweet['entities']['urls'] as $url)
|
||||
{
|
||||
$feeditem->links()->create([
|
||||
'addr' => $url['url'],
|
||||
'display' =>$url['display_url']
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Are there tags to include?
|
||||
if (sizeof($tweet['entities']['hashtags']))
|
||||
{
|
||||
foreach ($tweet['entities']['hashtags'] as $tag)
|
||||
{
|
||||
$feeditem->tags()->create([
|
||||
'tag' => $tag['text']
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the latest item ID
|
||||
Settings::set('twitter_latest_tweet', $tweets[sizeof($tweets) - 1]['id_str']);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the database with the latest instagram posts
|
||||
public static function updateInstagram()
|
||||
{
|
||||
$posts = self::fetchInstagram();
|
||||
|
||||
if (sizeof($posts) > 0)
|
||||
{
|
||||
foreach ($posts as $post)
|
||||
{
|
||||
// Skip videos and albums
|
||||
if ($post['media_type'] != "IMAGE") continue;
|
||||
|
||||
// Create a new FeedItem
|
||||
$feeditem = new FeedItem;
|
||||
$feeditem->timestamp = strtotime($post['timestamp']);
|
||||
$feeditem->channel_id = 3;
|
||||
$feeditem->title = (isset($post['caption'])) ? $post['caption'] : "";
|
||||
$feeditem->link = $post['permalink'];
|
||||
$feeditem->extra = json_encode(['img' => $post['media_url']]);
|
||||
$feeditem->save();
|
||||
|
||||
// Are there tags to include?
|
||||
if (isset($post['caption']) && strpos($post['caption'], '#'))
|
||||
{
|
||||
preg_match_all('%\B#\w*[a-zA-Z]+\w*%', $post['caption'], $hashtags);
|
||||
foreach ($hashtags[0] as $tag)
|
||||
{
|
||||
$feeditem->tags()->create([
|
||||
'tag' => substr($tag, 1)
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the latest item ID
|
||||
Settings::set('instagram_latest_post', strtotime(end($posts)['timestamp']));
|
||||
}
|
||||
}
|
||||
|
||||
// Update the database with the latest foursquare posts
|
||||
public static function updateFoursquare()
|
||||
{
|
||||
$posts = self::fetchFoursquare();
|
||||
|
||||
if (sizeof($posts) > 0)
|
||||
{
|
||||
foreach ($posts as $post)
|
||||
{
|
||||
$extradata = [
|
||||
'lat' => $post['venue']['location']['lat'],
|
||||
'lng' => $post['venue']['location']['lng'],
|
||||
'address' => []
|
||||
];
|
||||
|
||||
// Build the address
|
||||
if (isset($post['venue']['location']['address'])) $extradata['address'][] = $post['venue']['location']['address'];
|
||||
if (isset($post['venue']['location']['city'])) $extradata['address'][] = $post['venue']['location']['city'];
|
||||
if (isset($post['venue']['location']['country'])) $extradata['address'][] = $post['venue']['location']['country'];
|
||||
$extradata['address'] = implode(', ', $extradata['address']);
|
||||
|
||||
// Create a new FeedItem
|
||||
$feeditem = new FeedItem;
|
||||
$feeditem->timestamp = $post['createdAt'];
|
||||
$feeditem->channel_id = 6;
|
||||
$feeditem->title = $post['venue']['name'];
|
||||
$feeditem->body = (isset($post['shout'])) ? $post['shout'] : "";
|
||||
$feeditem->extra = json_encode($extradata);
|
||||
$feeditem->save();
|
||||
|
||||
// Are there tags to include?
|
||||
if (isset($post['shout']) && strpos($post['shout'], '#'))
|
||||
{
|
||||
preg_match_all('%\B#\w*[a-zA-Z]+\w*%', $post['shout'], $hashtags);
|
||||
foreach ($hashtags[0] as $tag)
|
||||
{
|
||||
$feeditem->tags()->create([
|
||||
'tag' => substr($tag, 1)
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the latest item ID
|
||||
Settings::set('foursquare_latest_post', end($posts)['createdAt']);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch and return the latest tweets
|
||||
private static function fetchTwitter()
|
||||
{
|
||||
// Set the API endpoint
|
||||
$endpoint = "https://api.twitter.com/1.1/statuses/user_timeline.json";
|
||||
|
||||
// Set request parameteres
|
||||
$req_params = array(
|
||||
'screen_name' => Settings::get('twitter_username'),
|
||||
'count' => 200,
|
||||
'since_id' => Settings::get('twitter_latest_tweet'),
|
||||
'tweet_mode' => 'extended',
|
||||
'exclude_replies' => true,
|
||||
'include_rts' => true
|
||||
);
|
||||
|
||||
// Set oauth parameters
|
||||
self::$authobject = array(
|
||||
'oauth_token' => Settings::get('twitter_access_token'),
|
||||
'oauth_consumer_key' => Settings::get('twitter_consumer_key'),
|
||||
'oauth_nonce' => time(),
|
||||
'oauth_signature_method' => 'HMAC-SHA1',
|
||||
'oauth_timestamp' => time(),
|
||||
'oauth_version' => '1.0'
|
||||
);
|
||||
|
||||
// Add parameters to oauth array
|
||||
self::$authobject = array_merge(self::$authobject, $req_params);
|
||||
|
||||
// Generate the oauth signautre
|
||||
$base_string = self::buildBaseString($endpoint, "GET", self::$authobject);
|
||||
$composite_key = rawurlencode(Settings::get('twitter_consumer_secret'))."&".rawurlencode(Settings::get('twitter_access_token_secret'));
|
||||
self::$authobject['oauth_signature'] = base64_encode(hash_hmac('sha1', $base_string, $composite_key, true));
|
||||
|
||||
// Create the URL by adding the parameters to the endpoint
|
||||
$endpoint = $endpoint."?".http_build_query($req_params);
|
||||
|
||||
$tweets = array_reverse(json_decode(Http::get($endpoint, function($http)
|
||||
{
|
||||
$http->header(self::buildAuthorizationHeader(self::$authobject));
|
||||
}), true));
|
||||
|
||||
return $tweets;
|
||||
}
|
||||
|
||||
// Fetch and return the latest instagram posts
|
||||
private static function fetchInstagram()
|
||||
{
|
||||
$endpoint = "https://graph.instagram.com/me/media";
|
||||
|
||||
// Set the fields we want back
|
||||
$fields = [
|
||||
'id',
|
||||
'ig-id',
|
||||
'caption',
|
||||
'media_type',
|
||||
'media_url',
|
||||
'permalink',
|
||||
'timestamp'
|
||||
];
|
||||
|
||||
// Create the URL by adding the parameters to the endpoint
|
||||
$endpoint = $endpoint."?".http_build_query([
|
||||
'access_token' => Settings::get('instagram_access_token'),
|
||||
'fields' => implode(',', $fields),
|
||||
'limit' => 100
|
||||
]);
|
||||
|
||||
$posts = json_decode(Http::get($endpoint), true);
|
||||
$posts = array_reverse($posts['data']);
|
||||
|
||||
foreach($posts as $postkey => $post)
|
||||
{
|
||||
if (strtotime($post['timestamp']) <= Settings::get('instagram_latest_post')) unset($posts[$postkey]);
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
|
||||
// Fetch and return the latest foursquare checkins
|
||||
private static function fetchFoursquare()
|
||||
{
|
||||
$endpoint = "https://api.foursquare.com/v2/users/self/checkins";
|
||||
|
||||
// Create the URL by adding the parameters to the endpoint
|
||||
$endpoint = $endpoint."?".http_build_query([
|
||||
'oauth_token' => Settings::get('foursquare_access_token'),
|
||||
'v' => date('Ymd'),
|
||||
'limit' => 250,
|
||||
'sort' => 'oldestfirst',
|
||||
'afterTimestamp' => Settings::get('foursquare_latest_post') + 1
|
||||
]);
|
||||
|
||||
$posts = json_decode(Http::get($endpoint), true);
|
||||
return $posts['response']['checkins']['items'];
|
||||
}
|
||||
|
||||
// Function to build a base string for the twitter API
|
||||
private static function buildBaseString($baseURI, $method, $params) {
|
||||
$r = array();
|
||||
ksort($params);
|
||||
foreach ($params as $key => $value) {
|
||||
$r[] = $key.'='.rawurlencode($value);
|
||||
}
|
||||
return $method.'&'.rawurlencode($baseURI).'&'.rawurlencode(implode('&', $r));
|
||||
}
|
||||
|
||||
// Function to build the OAuth authorization header for twitter
|
||||
private static function buildAuthorizationHeader($oauth) {
|
||||
$r = 'Authorization: OAuth ';
|
||||
$values = array();
|
||||
foreach($oauth as $key=>$value)
|
||||
$values[] = $key.'="'.rawurlencode($value).'"';
|
||||
$r .= implode(', ', $values);
|
||||
return $r;
|
||||
}
|
||||
|
||||
private static $authobject;
|
||||
}
|
||||
41
www/plugins/jasonwilliams/feed/components/ChannelList.php
Normal file
41
www/plugins/jasonwilliams/feed/components/ChannelList.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php namespace JasonWilliams\Feed\Components;
|
||||
|
||||
use Cms\Classes\ComponentBase;
|
||||
use JasonWilliams\Feed\Models\Channels;
|
||||
|
||||
class ChannelList extends ComponentBase
|
||||
{
|
||||
public function componentDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Channel List',
|
||||
'description' => 'Displays a list of feed channels.'
|
||||
];
|
||||
}
|
||||
|
||||
public function defineProperties()
|
||||
{
|
||||
return [
|
||||
'includeEmpty' => [
|
||||
'title' => 'Include Empty?',
|
||||
'description' => 'Include channels with no posts?',
|
||||
'type' => 'checkbox',
|
||||
'default' => true
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function onRun()
|
||||
{
|
||||
$this->page['channels'] = Channels::orderBy('id')->withCount('feeditems')->get();
|
||||
|
||||
// If applicable, remove empty channels
|
||||
if (!$this->property('includeEmpty'))
|
||||
{
|
||||
foreach($this->page['channels'] as $key => $value)
|
||||
{
|
||||
if (!$value->feeditems_count) unset($this->page['channels'][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php namespace JasonWilliams\Feed\Components;
|
||||
|
||||
use Cms\Classes\ComponentBase;
|
||||
use JasonWilliams\Feed\Models\FeedItem;
|
||||
|
||||
class LazyLoadShortFeed extends ComponentBase
|
||||
{
|
||||
public function componentDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Short Feed (Lazy Load)',
|
||||
'description' => 'Displays a mini-feed of the most recent feed items, retrieved after other page content has been loaded'
|
||||
];
|
||||
}
|
||||
|
||||
public function defineProperties()
|
||||
{
|
||||
return [
|
||||
'maxItems' => [
|
||||
'title' => 'Max items',
|
||||
'description' => 'How many feed items should be displayed?',
|
||||
'default' => 10,
|
||||
'type' => 'string',
|
||||
'validationPattern' => '^[0-9]+$',
|
||||
'validationMessage' => 'The Max items property must be numeric'
|
||||
],
|
||||
'renderPartial' => [
|
||||
'title' => 'Render partial',
|
||||
'description' => 'The path to the partial that will be used as a template to render feed items. @feed is provided by the plugin itself.',
|
||||
'default' => '@feed',
|
||||
'type' => 'string'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function onRun()
|
||||
{
|
||||
$this->page['renderPartial'] = $this->property('renderPartial');
|
||||
$this->addJs('/plugins/jasonwilliams/feed/assets/javascript/lazyloadshortfeed.js');
|
||||
}
|
||||
|
||||
public function onUpdateRequested()
|
||||
{
|
||||
date_default_timezone_set('America/Edmonton');
|
||||
$this->page['posts'] = FeedItem::orderBy('timestamp', 'desc')->take($this->property('maxItems'))->get();
|
||||
}
|
||||
}
|
||||
79
www/plugins/jasonwilliams/feed/components/ShortFeed.php
Normal file
79
www/plugins/jasonwilliams/feed/components/ShortFeed.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php namespace JasonWilliams\Feed\Components;
|
||||
|
||||
use Cms\Classes\ComponentBase;
|
||||
use JasonWilliams\Feed\Models\FeedItem;
|
||||
use JasonWilliams\Feed\Models\Tags;
|
||||
|
||||
class ShortFeed extends ComponentBase
|
||||
{
|
||||
private $channelfilter;
|
||||
|
||||
public function componentDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Short Feed',
|
||||
'description' => 'Displays a mini-feed of the most recent feed items, loaded with other page content'
|
||||
];
|
||||
}
|
||||
|
||||
public function defineProperties()
|
||||
{
|
||||
return [
|
||||
'channelFilter' => [
|
||||
'title' => 'Channels',
|
||||
'description' => 'A comma-separated list of channels to include in feed.',
|
||||
'type' => 'string',
|
||||
'default' => ''
|
||||
],
|
||||
'tagFilter' => [
|
||||
'title' => 'Tag',
|
||||
'description' => 'The tag to display in the feed.',
|
||||
'type' => 'string',
|
||||
'default' => ''
|
||||
],
|
||||
'maxItems' => [
|
||||
'title' => 'Max items',
|
||||
'description' => 'How many feed items should be displayed?',
|
||||
'default' => 10,
|
||||
'type' => 'string',
|
||||
'validationPattern' => '^[0-9]+$',
|
||||
'validationMessage' => 'The Max items property must be numeric'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function onRun()
|
||||
{
|
||||
date_default_timezone_set('America/Edmonton');
|
||||
|
||||
// Set up the results query
|
||||
$results = FeedItem::orderBy('timestamp', 'desc')->take($this->property('maxItems'));
|
||||
|
||||
// Do we need to filter based on a tag?
|
||||
if ($this->property('tagFilter') != null)
|
||||
{
|
||||
$results->join('jasonwilliams_feed_tags', 'jasonwilliams_feed_.id', '=', 'jasonwilliams_feed_tags.feed_item_id');
|
||||
$results->where('tag', $this->property('tagFilter'));
|
||||
}
|
||||
|
||||
// Do we need to filter based on the channel?
|
||||
if ($this->property('channelFilter') != null && $this->property('channelFilter') != 'all')
|
||||
{
|
||||
$this->channelfilter = explode(',', $this->property('channelFilter'));
|
||||
|
||||
$results->whereHas('channel', function($q) {
|
||||
$firstchannel = true;
|
||||
|
||||
foreach ($this->channelfilter as $channel)
|
||||
{
|
||||
if ($firstchannel) $q->where('slug', $channel);
|
||||
else $q->orWhere('slug', $channel);
|
||||
|
||||
$firstchannel = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$this->page['posts'] = $results->get();
|
||||
}
|
||||
}
|
||||
26
www/plugins/jasonwilliams/feed/components/TagList.php
Normal file
26
www/plugins/jasonwilliams/feed/components/TagList.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php namespace JasonWilliams\Feed\Components;
|
||||
|
||||
use Db;
|
||||
use Cms\Classes\ComponentBase;
|
||||
use JasonWilliams\Feed\Models\Tags;
|
||||
|
||||
class TagList extends ComponentBase
|
||||
{
|
||||
public function componentDetails()
|
||||
{
|
||||
return [
|
||||
'name' => 'Tag List',
|
||||
'description' => 'Displays a list of feed tags.'
|
||||
];
|
||||
}
|
||||
|
||||
public function defineProperties()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function onRun()
|
||||
{
|
||||
$this->page['tags'] = Tags::groupBy('tag')->select(Db::raw('tag, count(*) as count'))->orderBy('count', 'desc')->get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<ul>
|
||||
{% for channel in channels %}
|
||||
<li><a href="/feed/{{ channel.slug }}">{{ channel.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div id="feedarea">Loading...</div>
|
||||
{% put scripts %}
|
||||
<script type="text/javascript">const renderPartial = '{{ renderPartial }}'</script>
|
||||
{% endput %}
|
||||
@@ -0,0 +1,9 @@
|
||||
<ul>
|
||||
{% for post in posts %}
|
||||
{% if post.title %}
|
||||
<li>{{ post.title | raw }}</li>
|
||||
{% else %}
|
||||
<li>Post</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@@ -0,0 +1,9 @@
|
||||
<ul>
|
||||
{% for post in posts %}
|
||||
{% if post.title %}
|
||||
<li>{{ post.title | raw }}</li>
|
||||
{% else %}
|
||||
<li>Post</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
@@ -0,0 +1,5 @@
|
||||
<ul>
|
||||
{% for tag in tags %}
|
||||
<li><a href="{{ tag.tag }}">{{ tag.tag }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
19
www/plugins/jasonwilliams/feed/controllers/Channels.php
Normal file
19
www/plugins/jasonwilliams/feed/controllers/Channels.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php namespace jasonwilliams\feed\Controllers;
|
||||
|
||||
use Backend\Classes\Controller;
|
||||
use BackendMenu;
|
||||
|
||||
class Channels extends Controller
|
||||
{
|
||||
public $implement = [ 'Backend\Behaviors\ListController', 'Backend\Behaviors\FormController', 'Backend\Behaviors\ReorderController' ];
|
||||
|
||||
public $listConfig = 'config_list.yaml';
|
||||
public $formConfig = 'config_form.yaml';
|
||||
public $reorderConfig = 'config_reorder.yaml';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
BackendMenu::setContext('jasonwilliams.feed', 'main-menu-item');
|
||||
}
|
||||
}
|
||||
19
www/plugins/jasonwilliams/feed/controllers/Feed.php
Normal file
19
www/plugins/jasonwilliams/feed/controllers/Feed.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php namespace jasonwilliams\feed\Controllers;
|
||||
|
||||
use Backend\Classes\Controller;
|
||||
use BackendMenu;
|
||||
|
||||
class Feed extends Controller
|
||||
{
|
||||
public $implement = [ 'Backend\Behaviors\ListController', 'Backend\Behaviors\FormController', 'Backend\Behaviors\ReorderController' ];
|
||||
|
||||
public $listConfig = 'config_list.yaml';
|
||||
public $formConfig = 'config_form.yaml';
|
||||
public $reorderConfig = 'config_reorder.yaml';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
BackendMenu::setContext('jasonwilliams.feed', 'main-menu-item');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<div data-control="toolbar">
|
||||
<a href="<?= Backend::url('jasonwilliams/feed/channels/create') ?>" class="btn btn-primary oc-icon-plus"><?= e(trans('backend::lang.form.create')) ?></a>
|
||||
<a href="<?= Backend::url('jasonwilliams/feed/channels/reorder') ?>" class="btn btn-default oc-icon-list"><?= e(trans('backend::lang.reorder.default_title')) ?></a>
|
||||
<button
|
||||
class="btn btn-default oc-icon-trash-o"
|
||||
disabled="disabled"
|
||||
onclick="$(this).data('request-data', {
|
||||
checked: $('.control-list').listWidget('getChecked')
|
||||
})"
|
||||
data-request="onDelete"
|
||||
data-request-confirm="<?= e(trans('backend::lang.list.delete_selected_confirm')) ?>"
|
||||
data-trigger-action="enable"
|
||||
data-trigger=".control-list input[type=checkbox]"
|
||||
data-trigger-condition="checked"
|
||||
data-request-success="$(this).prop('disabled', true)"
|
||||
data-stripe-load-indicator>
|
||||
<?= e(trans('backend::lang.list.delete_selected')) ?>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<div data-control="toolbar">
|
||||
<a href="<?= Backend::url('jasonwilliams/feed/channels') ?>" class="btn btn-primary oc-icon-caret-left"><?= e(trans('backend::lang.form.return_to_list')) ?></a>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
name: Channels
|
||||
form: $/jasonwilliams/feed/models/channels/fields.yaml
|
||||
modelClass: jasonwilliams\feed\Models\Channels
|
||||
defaultRedirect: jasonwilliams/feed/channels
|
||||
create:
|
||||
redirect: 'jasonwilliams/feed/channels/update/:id'
|
||||
redirectClose: jasonwilliams/feed/channels
|
||||
update:
|
||||
redirect: jasonwilliams/feed/channels
|
||||
redirectClose: jasonwilliams/feed/channels
|
||||
@@ -0,0 +1,12 @@
|
||||
title: Channels
|
||||
modelClass: jasonwilliams\feed\Models\Channels
|
||||
list: $/jasonwilliams/feed/models/channels/columns.yaml
|
||||
recordUrl: 'jasonwilliams/feed/channels/update/:id'
|
||||
noRecordsMessage: 'backend::lang.list.no_records'
|
||||
recordsPerPage: 20
|
||||
showSetup: true
|
||||
showCheckboxes: true
|
||||
toolbar:
|
||||
buttons: list_toolbar
|
||||
search:
|
||||
prompt: 'backend::lang.list.search_prompt'
|
||||
@@ -0,0 +1,4 @@
|
||||
title: Channels
|
||||
modelClass: jasonwilliams\feed\Models\Channels
|
||||
toolbar:
|
||||
buttons: reorder_toolbar
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('jasonwilliams/feed/channels') ?>">Channels</a></li>
|
||||
<li><?= e($this->pageTitle) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['class' => 'layout']) ?>
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRender() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.create')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+enter, cmd+enter"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-default">
|
||||
<?= e(trans('backend::lang.form.create_and_close')) ?>
|
||||
</button>
|
||||
<span class="btn-text">
|
||||
<?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('jasonwilliams/feed/channels') ?>"><?= e(trans('backend::lang.form.cancel')) ?></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('jasonwilliams/feed/channels') ?>" class="btn btn-default"><?= e(trans('backend::lang.form.return_to_list')) ?></a></p>
|
||||
<?php endif ?>
|
||||
@@ -0,0 +1 @@
|
||||
<?= $this->listRender() ?>
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('jasonwilliams/feed/channels') ?>">Channels</a></li>
|
||||
<li><?= e($this->pageTitle) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<div class="form-preview">
|
||||
<?= $this->formRenderPreview() ?>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
|
||||
<?php endif ?>
|
||||
|
||||
<p>
|
||||
<a href="<?= Backend::url('jasonwilliams/feed/channels') ?>" class="btn btn-default oc-icon-chevron-left">
|
||||
<?= e(trans('backend::lang.form.return_to_list')) ?>
|
||||
</a>
|
||||
</p>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('jasonwilliams/feed/channels') ?>">Channels</a></li>
|
||||
<li><?= e($this->pageTitle) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?= $this->reorderRender() ?>
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('jasonwilliams/feed/channels') ?>">Channels</a></li>
|
||||
<li><?= e($this->pageTitle) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['class' => 'layout']) ?>
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRender() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-request-data="redirect:0"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.save')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+enter, cmd+enter"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-default">
|
||||
<?= e(trans('backend::lang.form.save_and_close')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="oc-icon-trash-o btn-icon danger pull-right"
|
||||
data-request="onDelete"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.deleting')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.form.confirm_delete')) ?>">
|
||||
</button>
|
||||
|
||||
<span class="btn-text">
|
||||
<?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('jasonwilliams/feed/channels') ?>"><?= e(trans('backend::lang.form.cancel')) ?></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('jasonwilliams/feed/channels') ?>" class="btn btn-default"><?= e(trans('backend::lang.form.return_to_list')) ?></a></p>
|
||||
<?php endif ?>
|
||||
@@ -0,0 +1,19 @@
|
||||
<div data-control="toolbar">
|
||||
<a href="<?= Backend::url('jasonwilliams/feed/feed/create') ?>" class="btn btn-primary oc-icon-plus"><?= e(trans('backend::lang.form.create')) ?></a>
|
||||
<a href="<?= Backend::url('jasonwilliams/feed/feed/reorder') ?>" class="btn btn-default oc-icon-list"><?= e(trans('backend::lang.reorder.default_title')) ?></a>
|
||||
<button
|
||||
class="btn btn-default oc-icon-trash-o"
|
||||
disabled="disabled"
|
||||
onclick="$(this).data('request-data', {
|
||||
checked: $('.control-list').listWidget('getChecked')
|
||||
})"
|
||||
data-request="onDelete"
|
||||
data-request-confirm="<?= e(trans('backend::lang.list.delete_selected_confirm')) ?>"
|
||||
data-trigger-action="enable"
|
||||
data-trigger=".control-list input[type=checkbox]"
|
||||
data-trigger-condition="checked"
|
||||
data-request-success="$(this).prop('disabled', true)"
|
||||
data-stripe-load-indicator>
|
||||
<?= e(trans('backend::lang.list.delete_selected')) ?>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<div data-control="toolbar">
|
||||
<a href="<?= Backend::url('jasonwilliams/feed/feed') ?>" class="btn btn-primary oc-icon-caret-left"><?= e(trans('backend::lang.form.return_to_list')) ?></a>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
name: Feed
|
||||
form: $/jasonwilliams/feed/models/feeditem/fields.yaml
|
||||
modelClass: jasonwilliams\feed\Models\FeedItem
|
||||
defaultRedirect: jasonwilliams/feed/feed
|
||||
create:
|
||||
redirect: 'jasonwilliams/feed/feed/update/:id'
|
||||
redirectClose: jasonwilliams/feed/feed
|
||||
update:
|
||||
redirect: jasonwilliams/feed/feed
|
||||
redirectClose: jasonwilliams/feed/feed
|
||||
@@ -0,0 +1,12 @@
|
||||
title: Feed
|
||||
modelClass: jasonwilliams\feed\Models\FeedItem
|
||||
list: $/jasonwilliams/feed/models/feeditem/columns.yaml
|
||||
recordUrl: 'jasonwilliams/feed/feed/update/:id'
|
||||
noRecordsMessage: 'backend::lang.list.no_records'
|
||||
recordsPerPage: 20
|
||||
showSetup: true
|
||||
showCheckboxes: true
|
||||
toolbar:
|
||||
buttons: list_toolbar
|
||||
search:
|
||||
prompt: 'backend::lang.list.search_prompt'
|
||||
@@ -0,0 +1,4 @@
|
||||
title: Feed
|
||||
modelClass: jasonwilliams\feed\Models\FeedItem
|
||||
toolbar:
|
||||
buttons: reorder_toolbar
|
||||
46
www/plugins/jasonwilliams/feed/controllers/feed/create.htm
Normal file
46
www/plugins/jasonwilliams/feed/controllers/feed/create.htm
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('jasonwilliams/feed/feed') ?>">Feed</a></li>
|
||||
<li><?= e($this->pageTitle) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['class' => 'layout']) ?>
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRender() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.create')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+enter, cmd+enter"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-default">
|
||||
<?= e(trans('backend::lang.form.create_and_close')) ?>
|
||||
</button>
|
||||
<span class="btn-text">
|
||||
<?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('jasonwilliams/feed/feed') ?>"><?= e(trans('backend::lang.form.cancel')) ?></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('jasonwilliams/feed/feed') ?>" class="btn btn-default"><?= e(trans('backend::lang.form.return_to_list')) ?></a></p>
|
||||
<?php endif ?>
|
||||
@@ -0,0 +1 @@
|
||||
<?= $this->listRender() ?>
|
||||
22
www/plugins/jasonwilliams/feed/controllers/feed/preview.htm
Normal file
22
www/plugins/jasonwilliams/feed/controllers/feed/preview.htm
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('jasonwilliams/feed/feed') ?>">Feed</a></li>
|
||||
<li><?= e($this->pageTitle) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<div class="form-preview">
|
||||
<?= $this->formRenderPreview() ?>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e($this->fatalError) ?></p>
|
||||
<?php endif ?>
|
||||
|
||||
<p>
|
||||
<a href="<?= Backend::url('jasonwilliams/feed/feed') ?>" class="btn btn-default oc-icon-chevron-left">
|
||||
<?= e(trans('backend::lang.form.return_to_list')) ?>
|
||||
</a>
|
||||
</p>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('jasonwilliams/feed/feed') ?>">Feed</a></li>
|
||||
<li><?= e($this->pageTitle) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?= $this->reorderRender() ?>
|
||||
54
www/plugins/jasonwilliams/feed/controllers/feed/update.htm
Normal file
54
www/plugins/jasonwilliams/feed/controllers/feed/update.htm
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php Block::put('breadcrumb') ?>
|
||||
<ul>
|
||||
<li><a href="<?= Backend::url('jasonwilliams/feed/feed') ?>">Feed</a></li>
|
||||
<li><?= e($this->pageTitle) ?></li>
|
||||
</ul>
|
||||
<?php Block::endPut() ?>
|
||||
|
||||
<?php if (!$this->fatalError): ?>
|
||||
|
||||
<?= Form::open(['class' => 'layout']) ?>
|
||||
|
||||
<div class="layout-row">
|
||||
<?= $this->formRender() ?>
|
||||
</div>
|
||||
|
||||
<div class="form-buttons">
|
||||
<div class="loading-indicator-container">
|
||||
<button
|
||||
type="submit"
|
||||
data-request="onSave"
|
||||
data-request-data="redirect:0"
|
||||
data-hotkey="ctrl+s, cmd+s"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-primary">
|
||||
<?= e(trans('backend::lang.form.save')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
data-request="onSave"
|
||||
data-request-data="close:1"
|
||||
data-hotkey="ctrl+enter, cmd+enter"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
||||
class="btn btn-default">
|
||||
<?= e(trans('backend::lang.form.save_and_close')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="oc-icon-trash-o btn-icon danger pull-right"
|
||||
data-request="onDelete"
|
||||
data-load-indicator="<?= e(trans('backend::lang.form.deleting')) ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.form.confirm_delete')) ?>">
|
||||
</button>
|
||||
|
||||
<span class="btn-text">
|
||||
<?= e(trans('backend::lang.form.or')) ?> <a href="<?= Backend::url('jasonwilliams/feed/feed') ?>"><?= e(trans('backend::lang.form.cancel')) ?></a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?= Form::close() ?>
|
||||
|
||||
<?php else: ?>
|
||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
||||
<p><a href="<?= Backend::url('jasonwilliams/feed/feed') ?>" class="btn btn-default"><?= e(trans('backend::lang.form.return_to_list')) ?></a></p>
|
||||
<?php endif ?>
|
||||
6
www/plugins/jasonwilliams/feed/lang/en-ca/lang.php
Normal file
6
www/plugins/jasonwilliams/feed/lang/en-ca/lang.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php return [
|
||||
'plugin' => [
|
||||
'name' => 'Social Feed',
|
||||
'description' => 'Captures social media posts from a variety of services and consolidates them into a single feed.'
|
||||
]
|
||||
];
|
||||
33
www/plugins/jasonwilliams/feed/models/Channels.php
Normal file
33
www/plugins/jasonwilliams/feed/models/Channels.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php namespace jasonwilliams\feed\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
/**
|
||||
* Model
|
||||
*/
|
||||
class Channels extends Model
|
||||
{
|
||||
use \October\Rain\Database\Traits\Validation;
|
||||
|
||||
/*
|
||||
* Disable timestamps by default.
|
||||
* Remove this line if timestamps are defined in the database table.
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'jasonwilliams_feed_channels';
|
||||
|
||||
/**
|
||||
* @var array Validation rules
|
||||
*/
|
||||
public $rules = [
|
||||
];
|
||||
|
||||
public $hasMany = [
|
||||
'feeditems' => ['jasonwilliams\feed\Models\FeedItem', 'key' => 'channel_id']
|
||||
];
|
||||
}
|
||||
65
www/plugins/jasonwilliams/feed/models/FeedItem.php
Normal file
65
www/plugins/jasonwilliams/feed/models/FeedItem.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php namespace jasonwilliams\feed\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
/**
|
||||
* Model
|
||||
*/
|
||||
class FeedItem extends Model
|
||||
{
|
||||
use \October\Rain\Database\Traits\Validation;
|
||||
|
||||
/*
|
||||
* Disable timestamps by default.
|
||||
* Remove this line if timestamps are defined in the database table.
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'jasonwilliams_feed_';
|
||||
|
||||
/**
|
||||
* @var array Validation rules
|
||||
*/
|
||||
public $rules = [
|
||||
];
|
||||
|
||||
public $hasMany = [
|
||||
'links' => 'jasonwilliams\feed\Models\Links',
|
||||
'tags' => 'jasonwilliams\feed\Models\Tags'
|
||||
];
|
||||
|
||||
public $belongsTo = [
|
||||
'channel' => ['jasonwilliams\feed\Models\Channels', 'key' => 'channel_id']
|
||||
];
|
||||
|
||||
public function afterFetch()
|
||||
{
|
||||
// Add clickable hashtags to the title field
|
||||
$this->title = preg_replace('/#(\w*[a-zA-Z]+\w*)/', '<a href="/feed/all/$1">#$1</a>', $this->title);
|
||||
|
||||
// Add a friendlytime field
|
||||
$this->friendlytime = date('M j, Y', $this->timestamp);
|
||||
|
||||
// Expand extras to an object
|
||||
if ($this->extra) $this->extra = json_decode($this->extra);
|
||||
|
||||
// Add twitter user links
|
||||
if ($this->channel_id == 2) $this->title = preg_replace('/@([a-zA-Z0-9_]+)/', '<a href="http://twitter.com/$1">@$1</a>', $this->title);
|
||||
|
||||
// Add instagram user links
|
||||
if ($this->channel_id == 3) $this->title = preg_replace('/@([a-zA-Z0-9_]+)/', '<a href="https://www.instagram.com/$1">@$1</a>', $this->title);
|
||||
|
||||
// Add foursquare user Links
|
||||
if ($this->channel_id == 6 && !empty($this->body)) $this->body = preg_replace('/@([a-zA-Z0-9_]+)/', '<a href="https://www.foursquare.com/$1">@$1</a>', $this->body);
|
||||
|
||||
// Find and replace links
|
||||
foreach($this->links as $link)
|
||||
{
|
||||
$this->title = str_replace($link->addr, "<a href=\"".$link->addr."\">".$link->display."</a>", $this->title);
|
||||
}
|
||||
}
|
||||
}
|
||||
35
www/plugins/jasonwilliams/feed/models/Links.php
Normal file
35
www/plugins/jasonwilliams/feed/models/Links.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php namespace jasonwilliams\feed\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
/**
|
||||
* Model
|
||||
*/
|
||||
class Links extends Model
|
||||
{
|
||||
use \October\Rain\Database\Traits\Validation;
|
||||
|
||||
/*
|
||||
* Disable timestamps by default.
|
||||
* Remove this line if timestamps are defined in the database table.
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'jasonwilliams_feed_links';
|
||||
|
||||
protected $fillable = ['addr', 'display'];
|
||||
|
||||
/**
|
||||
* @var array Validation rules
|
||||
*/
|
||||
public $rules = [
|
||||
];
|
||||
|
||||
public $belongsTo = [
|
||||
'links' => 'jasonwilliams\feed\Models\FeedItem'
|
||||
];
|
||||
}
|
||||
14
www/plugins/jasonwilliams/feed/models/Settings.php
Normal file
14
www/plugins/jasonwilliams/feed/models/Settings.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php namespace JasonWilliams\Feed\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
class Settings extends Model
|
||||
{
|
||||
public $implement = ['System.Behaviors.SettingsModel'];
|
||||
|
||||
// A unique code
|
||||
public $settingsCode = 'jasonwilliams_feed_settings';
|
||||
|
||||
// Reference to field configuration
|
||||
public $settingsFields = 'fields.yaml';
|
||||
}
|
||||
40
www/plugins/jasonwilliams/feed/models/Tags.php
Normal file
40
www/plugins/jasonwilliams/feed/models/Tags.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php namespace jasonwilliams\feed\Models;
|
||||
|
||||
use Model;
|
||||
|
||||
/**
|
||||
* Model
|
||||
*/
|
||||
class Tags extends Model
|
||||
{
|
||||
use \October\Rain\Database\Traits\Validation;
|
||||
|
||||
/*
|
||||
* Disable timestamps by default.
|
||||
* Remove this line if timestamps are defined in the database table.
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'jasonwilliams_feed_tags';
|
||||
|
||||
protected $fillable = ['tag'];
|
||||
|
||||
/**
|
||||
* @var array Validation rules
|
||||
*/
|
||||
public $rules = [
|
||||
];
|
||||
|
||||
public $belongsTo = [
|
||||
'feeditem' => ['jasonwilliams\feed\Models\FeedItem', 'key' => 'feed_item_id']
|
||||
];
|
||||
|
||||
public function afterFetch()
|
||||
{
|
||||
//dd($this->feeditem);
|
||||
}
|
||||
}
|
||||
10
www/plugins/jasonwilliams/feed/models/channels/columns.yaml
Normal file
10
www/plugins/jasonwilliams/feed/models/channels/columns.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
columns:
|
||||
id:
|
||||
label: 'Channel ID'
|
||||
type: number
|
||||
sortable: true
|
||||
title:
|
||||
label: Title
|
||||
type: text
|
||||
searchable: true
|
||||
sortable: false
|
||||
21
www/plugins/jasonwilliams/feed/models/channels/fields.yaml
Normal file
21
www/plugins/jasonwilliams/feed/models/channels/fields.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
fields:
|
||||
title:
|
||||
label: 'Channel Title'
|
||||
span: left
|
||||
type: text
|
||||
slug:
|
||||
label: Slug
|
||||
span: right
|
||||
preset:
|
||||
field: title
|
||||
type: slug
|
||||
type: text
|
||||
icon:
|
||||
label: Icon
|
||||
span: left
|
||||
type: text
|
||||
comment: 'Icon code from FontAwesome'
|
||||
colour:
|
||||
label: 'Icon Colour'
|
||||
span: auto
|
||||
type: colorpicker
|
||||
@@ -0,0 +1,9 @@
|
||||
columns:
|
||||
title:
|
||||
label: 'Post Title'
|
||||
type: text
|
||||
searchable: true
|
||||
timestamp:
|
||||
label: 'UNIX Timestamp'
|
||||
type: number
|
||||
sortable: true
|
||||
20
www/plugins/jasonwilliams/feed/models/feeditem/fields.yaml
Normal file
20
www/plugins/jasonwilliams/feed/models/feeditem/fields.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
fields:
|
||||
title:
|
||||
label: 'Post Title'
|
||||
span: full
|
||||
type: text
|
||||
body:
|
||||
label: 'Post Body'
|
||||
size: ''
|
||||
span: full
|
||||
type: richeditor
|
||||
timestamp:
|
||||
label: 'UNIX Timestamp'
|
||||
span: auto
|
||||
type: number
|
||||
channel:
|
||||
label: Channel
|
||||
nameFrom: title
|
||||
descriptionFrom: description
|
||||
span: auto
|
||||
type: relation
|
||||
51
www/plugins/jasonwilliams/feed/models/settings/fields.yaml
Normal file
51
www/plugins/jasonwilliams/feed/models/settings/fields.yaml
Normal file
@@ -0,0 +1,51 @@
|
||||
fields:
|
||||
twitter_section:
|
||||
label: Twitter API Settings
|
||||
type: section
|
||||
twitter_username:
|
||||
label: Username
|
||||
description: Your twitter username, excluding the @
|
||||
span: left
|
||||
twitter_latest_tweet:
|
||||
label: Latest Tweet ID
|
||||
description: The ID of the most recent tweet already fetched and stored
|
||||
span: right
|
||||
twitter_consumer_key:
|
||||
label: Consumer Key
|
||||
description: Your consumer key for accessing the twitter API
|
||||
span: left
|
||||
twitter_consumer_secret:
|
||||
label: Consumer Key Secret
|
||||
description: Your consumer key secret for accessing the twitter API
|
||||
span: right
|
||||
twitter_access_token:
|
||||
label: Access Token
|
||||
description: Your access token for accessing the twitter API
|
||||
span: left
|
||||
twitter_access_token_secret:
|
||||
label: Access Token Secret
|
||||
description: Your access token secret for accessing the twitter API
|
||||
span: right
|
||||
|
||||
instagram_section:
|
||||
label: Instagram API Settings
|
||||
type: section
|
||||
instagram_access_token:
|
||||
label: Access Token
|
||||
description: Your access token for accessing the instagram API
|
||||
span: full
|
||||
instagram_latest_post:
|
||||
label: Latest Post Timestamp
|
||||
description: The unix timestamp of the most recent post already fetched and stored
|
||||
span: left
|
||||
|
||||
foursquare_section:
|
||||
label: Foursquare API Settings
|
||||
type: section
|
||||
foursquare_access_token:
|
||||
description: Your access token for accessing the foursquare API
|
||||
span: full
|
||||
foursquare_latest_post:
|
||||
label: Latest Checkin Timestamp
|
||||
description: The unix timestamp of the most recent checkin already fetched and stored
|
||||
span: left
|
||||
20
www/plugins/jasonwilliams/feed/plugin.yaml
Normal file
20
www/plugins/jasonwilliams/feed/plugin.yaml
Normal file
@@ -0,0 +1,20 @@
|
||||
plugin:
|
||||
name: 'jasonwilliams.feed::lang.plugin.name'
|
||||
description: 'jasonwilliams.feed::lang.plugin.description'
|
||||
author: 'Jason Williams'
|
||||
icon: oc-icon-newspaper-o
|
||||
homepage: 'https://ja.son-williams.ca/'
|
||||
navigation:
|
||||
main-menu-item:
|
||||
label: Feed
|
||||
url: jasonwilliams/feed/feed
|
||||
icon: icon-newspaper-o
|
||||
sideMenu:
|
||||
side-menu-item:
|
||||
label: 'Social Feed'
|
||||
url: jasonwilliams/feed/feed
|
||||
icon: icon-sitemap
|
||||
side-menu-item2:
|
||||
label: 'Social Channels'
|
||||
url: jasonwilliams/feed/channels
|
||||
icon: icon-sitemap
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php namespace jasonwilliams\feed\Updates;
|
||||
|
||||
use Schema;
|
||||
use October\Rain\Database\Updates\Migration;
|
||||
|
||||
class JasonwilliamsFeedInitialSetup extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::create('jasonwilliams_feed_', function($table)
|
||||
{
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id')->unsigned();
|
||||
$table->integer('timestamp')->unsigned();
|
||||
$table->integer('channel_id')->unsigned();
|
||||
$table->string('title', 512)->nullable();
|
||||
$table->string('link', 256)->nullable();
|
||||
$table->text('body')->nullable();
|
||||
$table->text('extra');
|
||||
});
|
||||
|
||||
Schema::create('jasonwilliams_feed_tags', function($table)
|
||||
{
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id')->unsigned();
|
||||
$table->string('tag', 128);
|
||||
$table->integer('feed_item_id')->unsigned();
|
||||
});
|
||||
|
||||
Schema::create('jasonwilliams_feed_links', function($table)
|
||||
{
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id')->unsigned();
|
||||
$table->string('addr', 256);
|
||||
$table->string('display', 256);
|
||||
$table->integer('feed_item_id')->unsigned();
|
||||
});
|
||||
|
||||
Schema::create('jasonwilliams_feed_channels', function($table)
|
||||
{
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id')->unsigned();
|
||||
$table->string('title', 64);
|
||||
$table->string('slug', 64);
|
||||
$table->string('icon', 128)->nullable();
|
||||
$table->string('colour', 7)->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('jasonwilliams_feed_');
|
||||
Schema::dropIfExists('jasonwilliams_feed_tags');
|
||||
Schema::dropIfExists('jasonwilliams_feed_links');
|
||||
Schema::dropIfExists('jasonwilliams_feed_channels');
|
||||
}
|
||||
}
|
||||
3
www/plugins/jasonwilliams/feed/updates/version.yaml
Normal file
3
www/plugins/jasonwilliams/feed/updates/version.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
1.0.1:
|
||||
- 'Initialize plugin and create database tables.'
|
||||
- jasonwilliams_feed_initial_setup.php
|
||||
Reference in New Issue
Block a user