update plugins to allow listing via API

This commit is contained in:
Lee Lawlor 2014-10-17 14:51:58 -04:00
parent c527515d4a
commit 1b44dfbd4b
10 changed files with 336 additions and 10 deletions

View File

@ -39,6 +39,9 @@ class ChannelsController < ApplicationController
# list public channels
def public
# error if page 0
respond_with_error(:error_resource_not_found) and return if params[:page] == '0'
@domain = domain
# default blank response
@channels = Channel.where(:id => 0).paginate :page => params[:page]
@ -63,7 +66,6 @@ class ChannelsController < ApplicationController
# normal channel list
else
@header = t(:featured_channels)
respond_with_error(:error_resource_not_found) and return if params[:page] == '0'
@channels = Channel.public_viewable.active.order('ranking desc, updated_at DESC').paginate :page => params[:page]
end

View File

@ -1,5 +1,6 @@
class PluginsController < ApplicationController
before_filter :require_user, :except => [:show_public, :show]
before_filter :authenticate_via_api_key!, :only => [:index]
before_filter :require_user, :except => [:show_public, :show, :public]
before_filter :set_plugins_menu
before_filter :check_permission, :only => ['edit', 'update', 'ajax_update', 'destroy']
@ -11,8 +12,31 @@ class PluginsController < ApplicationController
def new; ; end
def edit; ; end
# get list of public plugins
def public
# error if page 0
respond_with_error(:error_resource_not_found) and return if params[:page] == '0'
# default blank response
@plugins = Plugin.where(:id => 0).paginate :page => params[:page]
# get plugins
@plugins = Plugin.where("public_flag = true").order('updated_at DESC').paginate :page => params[:page]
respond_to do |format|
format.html
format.json { render :json => Plugin.paginated_hash(@plugins).to_json }
format.xml { render :xml => Plugin.paginated_hash(@plugins).to_xml(:root => 'response') }
end
end
def index
@plugins = current_user.plugins
respond_to do |format|
format.html
format.json { render :json => @plugins.to_json(Plugin.public_options) }
format.xml { render :xml => @plugins.to_xml(Plugin.public_options) }
end
end
def public_plugins

View File

@ -18,6 +18,44 @@ class Plugin < ActiveRecord::Base
has_many :windows, -> { where window_type: 'plugin' }, :foreign_key => :content_id, :source => :window
before_destroy { |record| record.windows.each { |window| window.delete } }
# pagination variables
cattr_reader :per_page
@@per_page = 15
# paginated hash for json and xml output
# plugins input must be paginated
def self.paginated_hash(plugins)
{
pagination:
{
current_page: plugins.current_page,
per_page: plugins.per_page,
total_entries: plugins.total_entries,
},
plugins: plugins.as_json(Plugin.public_options)
}
end
# for to_json or to_xml, return only the public attributes
def self.public_options
{
:root => false,
:only => [:id, :name, :created_at, :public_flag],
:methods => [:username, :url]
}
end
# login name of the user who created the plugin
def username; self.user.try(:login); end
# url for the plugin
def url
domain = 'https://thingspeak.com'
domain = 'http://staging.thingspeak.com' if Rails.env.staging?
domain = 'http://127.0.0.1:3000' if Rails.env.development?
return "#{domain}/plugins/#{self.id}"
end
def destroy_window
window_id = Window.where(content_id: self.id, window_type: 'plugin').first.id
Window.delete(window_id)

View File

@ -4,10 +4,10 @@
<div class="panel panel-primary">
<div class="panel-heading">
<%= link_to channel_path(channel.id), :id => "showsite_#{channel.id}", class: 'link-no-hover' do %>
<%= link_to channel_path(channel.id), class: 'link-no-hover' do %>
<i class="fa fa-bar-chart-o"></i>
<% end %>
<%= link_to channel_path(channel.id), :id => "showsite_#{channel.id}" do %>
<%= link_to channel_path(channel.id) do %>
<%= truncate(channel.name, length: 23) %>
<% end %>
</div>

View File

@ -46,7 +46,14 @@
<li><a href="/docs/users">Users</a></li>
<% end %>
<li class="<%= 'active' if params[:action] == 'plugins' %>"><a href="/docs/plugins">Plugins</a></li>
<% if params[:action] == 'plugins' %>
<li><a href="#plugins">Plugins</a></li>
<li class="subitem"><a href="#example">Example</a></li>
<li class="subitem"><a href="#index">List Plugins</a></li>
<% else %>
<li><a href="/docs/plugins">Plugins</a></li>
<% end %>
<li class="<%= 'active' if params[:action] == 'tutorials' %>"><a href="/docs/tutorials">Tutorials</a></li>
<li class="<%= 'active' if params[:action] == 'errors' %>"><a href="/docs/errors">Error Codes</a></li>
</ul>

View File

@ -12,14 +12,16 @@
<br><br>
<hr />
<h2>Example Plugin</h2>
<h2 id="example">Example Plugin</h2>
<p><a title="Display a Google Gauge Visualization using ThingSpeak Plugins" href="http://community.thingspeak.com/tutorials/google/display-a-google-gauge-visualization-using-thingspeak-plugins/">Display a Google Gauge Visualization using ThingSpeak Plugins</a> [<a title="Source ode for Google Gauge ThingSpeak Plugin" href="http://community.thingspeak.com/code/Google_Gauge.html">Source Code</a>]</p>
<p style="text-align: center;">
<iframe width="100%" height="120" marginwidth="0" marginheight="0" scrolling="auto" frameborder="0" src="http://community.thingspeak.com/code/Google_Gauge.html"></iframe>
</p>
<br><br>
<br><br><br><br><br><br><br><br><br><br><br><br>
<hr />
<%= render 'docs/plugins/index' %>
</div>
</div>

View File

@ -0,0 +1,182 @@
<div>
<%= render 'response' %>
<h2 id="index">List Public Plugins</h2>
</div>
<br>
To view a list of public plugins, send an HTTP GET to
<br>
<code><%= @ssl_api_domain %>plugins/public<span class="format format-json">.json</span><span class="format format-xml">.xml</span></code> .
<br><br>
Valid parameters:
<ul>
<li><b>page</b> (integer) Page number to retrieve (optional)</li>
</ul>
<br>
Example GET:
<pre>GET <span class="str"><%= @ssl_api_domain %>plugins/public<span class="format format-json">.json</span><span class="format format-xml">.xml</span></span></pre>
<br>
<div class="format format-block-xxl format-text">
The response will be a webpage with a <a href="/plugins/public">list of public plugins</a>.
</div>
<div class="format format-block-xxl format-json">
The response will be a JSON object of public plugins, for example:
<pre class="prettyprint">
{
"pagination":
{
"current_page": 1,
"per_page":15,
"total_entries": 2
},
"plugins":
[
{
"id": 8,
"name": "google gauge",
"created_at": "2014-01-05T16:35:26-05:00",
"public_flag": true,
"username": "hans",
"url": "https://thingspeak.com/plugins/8"
},
{
"id": 13,
"name": "Plugin 13",
"created_at": "2014-10-09T14:45:31-04:00",
"public_flag": true,
"username": "hans",
"url": "https://thingspeak.com/plugins/13"
}
]
}
</pre>
</div>
<div class="format format-block-xxl format-xml">
The response will be an XML object of public plugins, for example:
<pre class="prettyprint">
&lt;response>
&lt;pagination>
&lt;current-page type="WillPaginate::PageNumber">1&lt;/current-page>
&lt;per-page type="integer">15&lt;/per-page>
&lt;total-entries type="integer">2&lt;/total-entries>
&lt;/pagination>
&lt;plugins type="array">
&lt;plugin>
&lt;id type="integer">8&lt;/id>
&lt;name>google gauge&lt;/name>
&lt;created-at type="dateTime">2014-01-05T16:35:26-05:00&lt;/created-at>
&lt;public-flag type="boolean">true&lt;/public-flag>
&lt;username>hans&lt;/username>
&lt;url>https://thingspeak.com/plugins/8&lt;/url>
&lt;/plugin>
&lt;plugin>
&lt;id type="integer">13&lt;/id>
&lt;name>Plugin 13&lt;/name>
&lt;created-at type="dateTime">2014-10-09T14:45:31-04:00&lt;/created-at>
&lt;public-flag type="boolean">true&lt;/public-flag>
&lt;username>hans&lt;/username>
&lt;url>https://thingspeak.com/plugins/13&lt;/url>
&lt;/plugin>
&lt;/plugins>
&lt;/response>
</pre>
</div>
<div>
<%= render 'response' %>
<h2>List My Plugins</h2>
</div>
<br>
To view a list of your plugins, send an HTTP GET to
<br>
<code><%= @ssl_api_domain %>plugins<span class="format format-json">.json</span><span class="format format-xml">.xml</span></code> .
<br><br>
Valid parameters:
<ul>
<li><b>api_key</b> (string) - Your Account API Key, which can be found in your Account settings. (required)</li>
</ul>
<br>
Example GET:
<pre>GET <span class="str"><%= @ssl_api_domain %>plugins<span class="format format-json">.json</span><span class="format format-xml">.xml</span></span></pre>
<br>
<div class="format format-block-xxl format-text">
The response will be a webpage with a <a href="/plugins">list of your plugins</a>.
</div>
<div class="format format-block-xxl format-json">
The response will be a JSON object of your plugins, for example:
<pre class="prettyprint">
[
{
"id": 8,
"name": "google gauge",
"created_at": "2014-01-05T16:35:26-05:00",
"public_flag": false,
"username": "hans",
"url": "https://thingspeak.com/plugins/8"
},
{
"id": 13,
"name": "Plugin 13",
"created_at": "2014-10-09T14:45:31-04:00",
"public_flag": false,
"username": "hans",
"url": "https://thingspeak.com/plugins/13"
}
]
</pre>
</div>
<div class="format format-block-xxl format-xml">
The response will be an XML object of your plugins, for example:
<pre class="prettyprint">
&lt;response>
&lt;pagination>
&lt;current-page type="WillPaginate::PageNumber">1&lt;/current-page>
&lt;per-page type="integer">15&lt;/per-page>
&lt;total-entries type="integer">2&lt;/total-entries>
&lt;/pagination>
&lt;plugins type="array">
&lt;plugin>
&lt;id type="integer">8&lt;/id>
&lt;name>google gauge&lt;/name>
&lt;created-at type="dateTime">2014-01-05T16:35:26-05:00&lt;/created-at>
&lt;public-flag type="boolean">false&lt;/public-flag>
&lt;username>hans&lt;/username>
&lt;url>https://thingspeak.com/plugins/8&lt;/url>
&lt;/plugin>
&lt;plugin>
&lt;id type="integer">13&lt;/id>
&lt;name>Plugin 13&lt;/name>
&lt;created-at type="dateTime">2014-10-09T14:45:31-04:00&lt;/created-at>
&lt;public-flag type="boolean">false&lt;/public-flag>
&lt;username>hans&lt;/username>
&lt;url>https://thingspeak.com/plugins/13&lt;/url>
&lt;/plugin>
&lt;/plugins>
&lt;/response>
</pre>
</div>

View File

@ -0,0 +1,34 @@
<div class="row">
<div class="col-xs-12 col-sm-9">
<h4 class="breadcrumb">Plugins</h4>
<% @plugins.each do |plugin| %>
<div class="col-md-4 col-sm-6 col-xs-12">
<div class="panel panel-primary">
<div class="panel-heading">
<%= link_to plugin_path(plugin.id), class: 'link-no-hover' do %>
<i class="fa fa-plug"></i>
<% end %>
<%= link_to plugin_path(plugin.id) do %>
<%= truncate(plugin.name, length: 23) %>
<% end %>
</div>
<div class="panel-body">
<p class="small">by <%= link_to(plugin.user.login, user_profile_path(plugin.user.login)) if plugin.user.present? %></p>
</div>
</div>
</div>
<% end %>
<div class="clearfix"></div>
<div class="col-pad">
<%= will_paginate @plugins, renderer: BootstrapPagination::Rails %>
</div>
</div>
</div>

View File

@ -127,6 +127,7 @@ Thingspeak::Application.routes.draw do
collection do
get 'private_plugins'
get 'public_plugins'
get 'public'
end
end

View File

@ -3,18 +3,54 @@ require 'spec_helper'
describe PluginsController do
before :each do
@user = FactoryGirl.create(:user)
controller.stub(:current_user).and_return(@user)
controller.stub(:current_user_session).and_return(true)
@plugin = FactoryGirl.create(:plugin, :user => @user)
@channel = FactoryGirl.create(:channel, :user => @user)
end
describe "GET 'private_plugins' for plugin" do
before :each do
controller.stub(:current_user).and_return(@user)
controller.stub(:current_user_session).and_return(true)
end
it "should return plugin windows" do
get 'private_plugins', :channel_id => @channel.id
response.should be_successful
end
end
describe "Not Logged In" do
it "should display public plugins" do
get :public
response.should render_template('public')
end
it "should show paginated list of public plugins as json" do
@plugin.update_column(:public_flag, true)
get :public, :format => :json
JSON.parse(response.body).keys.include?('pagination').should be_true
JSON.parse(response.body)['plugins'].length.should eq(1)
end
it "should not show private plugins" do
@plugin.update_column(:public_flag, false)
get :public, :format => :json
JSON.parse(response.body)['plugins'].length.should eq(0)
end
end
describe "API" do
describe "list plugins" do
it "should not list my plugins" do
get :index, {:api_key => 'INVALID', :format => 'json'}
response.status.should eq(401)
end
it "lists my plugins" do
get :index, {:api_key => @user.api_key, :format => 'json'}
response.should be_successful
end
end
end
end