update plugins to allow listing via API
This commit is contained in:
		@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										182
									
								
								app/views/docs/plugins/_index.html.erb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								app/views/docs/plugins/_index.html.erb
									
									
									
									
									
										Normal 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">
 | 
			
		||||
<response>
 | 
			
		||||
  <pagination>
 | 
			
		||||
    <current-page type="WillPaginate::PageNumber">1</current-page>
 | 
			
		||||
    <per-page type="integer">15</per-page>
 | 
			
		||||
    <total-entries type="integer">2</total-entries>
 | 
			
		||||
  </pagination>
 | 
			
		||||
  <plugins type="array">
 | 
			
		||||
    <plugin>
 | 
			
		||||
      <id type="integer">8</id>
 | 
			
		||||
      <name>google gauge</name>
 | 
			
		||||
      <created-at type="dateTime">2014-01-05T16:35:26-05:00</created-at>
 | 
			
		||||
      <public-flag type="boolean">true</public-flag>
 | 
			
		||||
      <username>hans</username>
 | 
			
		||||
      <url>https://thingspeak.com/plugins/8</url>
 | 
			
		||||
    </plugin>
 | 
			
		||||
    <plugin>
 | 
			
		||||
      <id type="integer">13</id>
 | 
			
		||||
      <name>Plugin 13</name>
 | 
			
		||||
      <created-at type="dateTime">2014-10-09T14:45:31-04:00</created-at>
 | 
			
		||||
      <public-flag type="boolean">true</public-flag>
 | 
			
		||||
      <username>hans</username>
 | 
			
		||||
      <url>https://thingspeak.com/plugins/13</url>
 | 
			
		||||
    </plugin>
 | 
			
		||||
  </plugins>
 | 
			
		||||
</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">
 | 
			
		||||
<response>
 | 
			
		||||
  <pagination>
 | 
			
		||||
    <current-page type="WillPaginate::PageNumber">1</current-page>
 | 
			
		||||
    <per-page type="integer">15</per-page>
 | 
			
		||||
    <total-entries type="integer">2</total-entries>
 | 
			
		||||
  </pagination>
 | 
			
		||||
  <plugins type="array">
 | 
			
		||||
    <plugin>
 | 
			
		||||
      <id type="integer">8</id>
 | 
			
		||||
      <name>google gauge</name>
 | 
			
		||||
      <created-at type="dateTime">2014-01-05T16:35:26-05:00</created-at>
 | 
			
		||||
      <public-flag type="boolean">false</public-flag>
 | 
			
		||||
      <username>hans</username>
 | 
			
		||||
      <url>https://thingspeak.com/plugins/8</url>
 | 
			
		||||
    </plugin>
 | 
			
		||||
    <plugin>
 | 
			
		||||
      <id type="integer">13</id>
 | 
			
		||||
      <name>Plugin 13</name>
 | 
			
		||||
      <created-at type="dateTime">2014-10-09T14:45:31-04:00</created-at>
 | 
			
		||||
      <public-flag type="boolean">false</public-flag>
 | 
			
		||||
      <username>hans</username>
 | 
			
		||||
      <url>https://thingspeak.com/plugins/13</url>
 | 
			
		||||
    </plugin>
 | 
			
		||||
  </plugins>
 | 
			
		||||
</response>
 | 
			
		||||
</pre>
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										34
									
								
								app/views/plugins/public.html.erb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								app/views/plugins/public.html.erb
									
									
									
									
									
										Normal 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>
 | 
			
		||||
 | 
			
		||||
@@ -127,6 +127,7 @@ Thingspeak::Application.routes.draw do
 | 
			
		||||
    collection do
 | 
			
		||||
      get 'private_plugins'
 | 
			
		||||
      get 'public_plugins'
 | 
			
		||||
      get 'public'
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user