add API to create/clear/delete Channels

This commit is contained in:
Lee Lawlor 2014-03-26 11:10:26 -04:00
parent 156f4147ef
commit 1343f72f7a
19 changed files with 439 additions and 29 deletions

View File

@ -32,7 +32,7 @@ body { padding-top: 70px; }
.format-block-lg { min-height: 350px; }
.format-block-xl { min-height: 400px; }
.format-block-xxl { min-height: 600px; }
.format-block-xxxl { min-height: 1000px; }
/* Sticky footer styles
-------------------------------------------------- */

View File

@ -12,8 +12,8 @@
}
#bootstrap-sidebar li a {
padding: 2px 8px;
font-size: 16px;
padding: 1px 8px;
font-size: 15px;
}
#bootstrap-sidebar li a:hover {

View File

@ -131,7 +131,7 @@ class ApplicationController < ActionController::Base
def require_user
logger.info "Require User"
if current_user.nil?
if current_user.nil? && User.find_by_api_key(get_apikey).nil?
respond_to do |format|
format.html {
session[:link_back] = request.url

View File

@ -3,7 +3,7 @@ class ChannelsController < ApplicationController
before_filter :require_user, :except => [ :show, :post_data, :social_show, :social_feed, :public]
before_filter :set_channels_menu
layout 'application', :except => [:social_show, :social_feed]
protect_from_forgery :except => :post_data
protect_from_forgery :except => [:post_data, :create, :destroy, :clear]
require 'csv'
# view list of watched channels
@ -129,11 +129,10 @@ class ChannelsController < ApplicationController
end
def index
@channels = current_user.channels
respond_to do |format|
format.html
format.json { render :json => @channels }
format.json { render :json => @channels.to_json(:root => false) }
end
end
@ -190,29 +189,51 @@ class ChannelsController < ApplicationController
flash[:notice] = t(:channel_update_success)
redirect_to channel_path(@channel.id)
end
def create
channel = current_user.channels.create(:field1 => "#{t(:channel_default_field)} 1")
# get the current user or find the user via their api key
@user = current_user || User.find_by_api_key(get_apikey)
channel = @user.channels.create(:field1 => "#{t(:channel_default_field)} 1")
# make updating attributes easier
params[:channel] = params
channel.update_attributes(channel_params)
channel.set_windows
channel.save
channel.add_write_api_key
@channel_id = channel.id
redirect_to channel_path(@channel_id, :anchor => "channelsettings")
respond_to do |format|
format.json { render :json => channel.to_json(Channel.public_options) }
format.xml { render :xml => channel.to_xml(Channel.public_options) }
format.any { redirect_to channel_path(@channel_id, :anchor => "channelsettings") }
end
end
# clear all data from a channel
def clear
channel = current_user.channels.find(params[:id])
# get the current user or find the user via their api key
@user = current_user || User.find_by_api_key(get_apikey)
channel = @user.channels.find(params[:id])
channel.delete_feeds
redirect_to channel_path(channel.id)
respond_to do |format|
format.json { render :json => [] }
format.xml { render :xml => [] }
format.any { redirect_to channel_path(channel.id) }
end
end
def destroy
channel = current_user.channels.find(params[:id])
channel.destroy
redirect_to channels_path
# get the current user or find the user via their api key
@user = current_user || User.find_by_api_key(get_apikey)
@channel = @user.channels.find(params[:id])
@channel.destroy
respond_to do |format|
format.json { render :json => @channel.to_json(Channel.public_options) }
format.xml { render :xml => @channel.to_xml(Channel.public_options) }
format.any { redirect_to channels_path, :status => 303 }
end
end
# response is '0' if failure, 'entry_id' if success

View File

@ -12,10 +12,12 @@ class DocsController < ApplicationController
def channels
# default values
@channel_api_key = 'XXXXXXXXXXXXXXXX'
@user_api_key = 'XXXXXXXXXXXXXXXX'
# if user is signed in
if current_user && current_user.channels.any?
@channel_api_key = current_user.channels.order('updated_at desc').first.write_api_key
@user_api_key = current_user.api_key
end
end

View File

@ -20,8 +20,10 @@ class UsersController < ApplicationController
respond_with_error(:error_auth_required) and return if user.blank? || !user.valid_password?(params[:password])
# save new authentication token
user.authentication_token = Devise.friendly_token
user.save
if user.authentication_token.blank?
user.authentication_token = Devise.friendly_token
user.save
end
# output the user with token
respond_to do |format|

View File

@ -8,11 +8,14 @@
<li class="subitem"><a href="#urls">Base URLs</a></li>
<li class="subitem"><a href="#api_keys">API Keys</a></li>
<li class="subitem"><a href="#rate_limits">Rate Limits / Caching</a></li>
<li class="subitem"><a href="#update">Update a Channel</a></li>
<li class="subitem"><a href="#update">Update Channel Feed</a></li>
<li class="subitem"><a href="#get_feed">Get Channel Feed</a></li>
<li class="subitem"><a href="#get_field">Get Channel Field Feed</a></li>
<li class="subitem"><a href="#get_status">Get Status Updates</a></li>
<li class="subitem"><a href="#list_public">List Public Channels</a></li>
<li class="subitem"><a href="#create">Create a Channel</a></li>
<li class="subitem"><a href="#clear">Clear a Channel</a></li>
<li class="subitem"><a href="#delete">Delete a Channel</a></li>
<li class="subitem"><a href="#importer">Importer</a></li>
<% else %>
<li><a href="/docs/channels">Channels</a></li>

View File

@ -116,6 +116,15 @@
<hr />
<%= render 'docs/channels/public_index' %>
<hr />
<%= render 'docs/channels/create' %>
<hr />
<%= render 'docs/channels/clear' %>
<hr />
<%= render 'docs/channels/destroy' %>
<br><br>
<hr />
<%= render 'docs/channels/importer' %>

View File

@ -0,0 +1,47 @@
<div>
<%= render 'response' %>
<h2 id="clear">Clear a Channel</h2>
</div>
<br>
To clear all feed data from a Channel, send an HTTP DELETE to <code><%= @ssl_api_domain %>channels/<span class="customcode">CHANNEL_ID</span>/feeds<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) - User's API Key; please note that this is different than a Channel API key, and can be found in <a href="/account">your account details</a>. (required).</li>
</ul>
<br>
Example DELETE:
<pre>
DELETE <span class="str"><%= @ssl_api_domain %>channels/<span class="customcode">4</span>/feeds<span class="format format-json">.json</span><span class="format format-xml">.xml</span></span>
api_key=<span class="customcode"><%= @user_api_key %></span>
</pre>
<br>
<div class="format format-block format-text">
The response will be a webpage with your Channel.
</div>
<div class="format format-block format-json">
The response will be an empty JSON array, for example:
<pre class="prettyprint">
[]
</pre>
</div>
<div class="format format-block format-xml">
The response will be an empty XML array, for example:
<pre class="prettyprint">
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;nil-classes type="array" />
</pre>
</div>

View File

@ -0,0 +1,87 @@
<div>
<%= render 'response' %>
<h2 id="create">Create a Channel</h2>
</div>
<br>
To create a new Channel, send an HTTP POST to <code><%= @ssl_api_domain %>channels<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) - User's API Key; please note that this is different than a Channel API key, and can be found in <a href="/account">your account details</a>. (required).</li>
<li><b>description</b> (string) - Description of the Channel (optional)</li>
<li><b>elevation</b> (integer) - Elevation in meters (optional)</li>
<li><b>field1</b> (string) - Field1 name (optional)</li>
<li><b>field2</b> (string) - Field2 name (optional)</li>
<li><b>field3</b> (string) - Field3 name (optional)</li>
<li><b>field4</b> (string) - Field4 name (optional)</li>
<li><b>field5</b> (string) - Field5 name (optional)</li>
<li><b>field6</b> (string) - Field6 name (optional)</li>
<li><b>field7</b> (string) - Field7 name (optional)</li>
<li><b>field8</b> (string) - Field8 name (optional)</li>
<li><b>latitude</b> (decimal) - Latitude in degrees (optional)</li>
<li><b>longitude</b> (decimal) - Longitude in degrees (optional)</li>
<li><b>name</b> (string) - Name of the Channel (optional)</li>
<li><b>public_flag</b> (true/false) - Whether the Channel should be public, default false (optional)</li>
<li><b>url</b> (string) - Webpage URL for the Channel (optional)</li>
</ul>
<br>
Example POST:
<pre>
POST <span class="str"><%= @ssl_api_domain %>channels<span class="format format-json">.json</span><span class="format format-xml">.xml</span></span>
api_key=<span class="customcode"><%= @user_api_key %></span>
name=<span class="customcode">My New Channel</span>
</pre>
<br>
<div class="format format-block-xl format-text">
The response will be a webpage with your newly created Channel.
</div>
<div class="format format-block-xl format-json">
The response will be a JSON object of the new channel, for example:
<pre class="prettyprint">
{
"id": 4,
"name": "My New Channel",
"description": null,
"latitude": null,
"longitude": null,
"created_at": "2014-03-25T13:12:50-04:00",
"elevation": null,
"last_entry_id": null,
"ranking": 15,
"username": "hans",
"tags": []
}
</pre>
</div>
<div class="format format-block-xl format-xml">
The response will be an XML object of the new channel, for example:
<pre class="prettyprint">
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;channel>
&lt;id type="integer">4&lt;/id>
&lt;name>My New Channel&lt;/name>
&lt;description nil="true" />
&lt;latitude type="decimal" nil="true" />
&lt;longitude type="decimal" nil="true" />
&lt;created-at type="dateTime">2014-03-25T20:17:44-04:00&lt;/created-at>
&lt;elevation nil="true" />
&lt;last-entry-id type="integer" nil="true" />
&lt;ranking type="integer">15&lt;/ranking>
&lt;username>hans&lt;/username>
&lt;tags type="array" />
&lt;/channel>
</pre>
</div>

View File

@ -0,0 +1,72 @@
<div>
<%= render 'response' %>
<h2 id="delete">Delete a Channel</h2>
</div>
<br>
To create a new Channel, send an HTTP DELETE to <code><%= @ssl_api_domain %>channels/<span class="customcode">CHANNEL_ID</span><span class="format format-json">.json</span><span class="format format-xml">.xml</span></code> ,
replacing <span class="customcode">CHANNEL_ID</span> with the ID of your Channel.
<br><br>
Valid parameters:
<ul>
<li><b>api_key</b> (string) - User's API Key; please note that this is different than a Channel API key, and can be found in <a href="/account">your account details</a>. (required).</li>
</ul>
<br>
Example DELETE:
<pre>
DELETE <span class="str"><%= @ssl_api_domain %>channels/<span class="customcode">4</span><span class="format format-json">.json</span><span class="format format-xml">.xml</span></span>
api_key=<span class="customcode"><%= @user_api_key %></span>
</pre>
<br>
<div class="format format-block-xl format-text">
The response will be a webpage with a list of Channels.
</div>
<div class="format format-block-xl format-json">
The response will be a JSON object of the Channel before it was deleted, for example:
<pre class="prettyprint">
{
"id": 4,
"name": "My New Channel",
"description": null,
"latitude": null,
"longitude": null,
"created_at": "2014-03-25T13:12:50-04:00",
"elevation": null,
"last_entry_id": null,
"ranking": 15,
"username": "hans",
"tags": []
}
</pre>
</div>
<div class="format format-block-xl format-xml">
The response will be an XML object of the Channel before it was deleted, for example:
<pre class="prettyprint">
&lt;?xml version="1.0" encoding="UTF-8"?>
&lt;channel>
&lt;id type="integer">4&lt;/id>
&lt;name>My New Channel&lt;/name>
&lt;description nil="true" />
&lt;latitude type="decimal" nil="true" />
&lt;longitude type="decimal" nil="true" />
&lt;created-at type="dateTime">2014-03-25T20:17:44-04:00&lt;/created-at>
&lt;elevation nil="true" />
&lt;last-entry-id type="integer" nil="true" />
&lt;ranking type="integer">15&lt;/ranking>
&lt;username>hans&lt;/username>
&lt;tags type="array" />
&lt;/channel>
</pre>
</div>

View File

@ -23,11 +23,11 @@ Example GET:
<br>
<div class="format format-block-xxl format-text">
<div class="format format-block-xxxl format-text">
The response will be a webpage with a <a href="/channels/public">list of public Channels</a>.
</div>
<div class="format format-block-xxl format-json">
<div class="format format-block-xxxl format-json">
The response will be a JSON object of public Channels, for example:
<pre class="prettyprint">
@ -87,7 +87,7 @@ Example GET:
</div>
<div class="format format-block-xxl format-xml">
<div class="format format-block-xxxl format-xml">
The response will be an XML object of public Channels, for example:
<pre class="prettyprint">

View File

@ -1,10 +1,10 @@
<div>
<%= render 'response' %>
<h2 id="update">Update a Channel</h2>
<h2 id="update">Update Channel Feed</h2>
</div>
<br>
To update a Channel, send an HTTP GET or POST to <code><%= @ssl_api_domain %>update<span class="format format-json">.json</span><span class="format format-xml">.xml</span></code> .
To update a Channel feed, send an HTTP GET or POST to <code><%= @ssl_api_domain %>update<span class="format format-json">.json</span><span class="format format-xml">.xml</span></code> .
<br><br>
Valid parameters:

View File

@ -67,6 +67,7 @@ Thingspeak::Application.routes.draw do
get 'channels/:channel_id/feeds/entry/:id(.:format)' => 'feed#show' # not sure why this doesn't work with (s)
get 'channels/:channel_id/social_feed' => 'channels#social_feed'
get 'channels/:channel_id/feed(s)/debug' => 'feed#debug'
delete 'channels/:id/feeds' => 'channels#clear'
# maps
get 'channels/:channel_id/maps/channel_show' => 'maps#channel_show'

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -21,7 +21,7 @@ describe ChannelsController do
it "should allow a new channel to be created" do
post :create
response.should be_redirect
channel_id = Channel.find(:all).last.id
channel_id = Channel.all.last.id
response.should redirect_to( channel_path(channel_id, :anchor => "channelsettings"))
end
@ -38,8 +38,6 @@ describe ChannelsController do
@channel_no_more = Channel.find_by_id(@channel.id)
@channel_no_more.should be_nil
end
end
describe "Not Logged In" do
@ -109,5 +107,72 @@ describe ChannelsController do
end
describe "API" do
before :each do
@user = FactoryGirl.create(:user)
@channel = FactoryGirl.create(:channel)
@feed = FactoryGirl.create(:feed, :field1 => 10, :channel => @channel)
end
describe "create channel" do
it 'creates a channel' do
post :create, {:key => @user.api_key, :name => 'mychannel'}
response.should be_redirect
channel_id = Channel.all.last.id
response.should redirect_to(channel_path(channel_id, :anchor => "channelsettings"))
end
it 'returns JSON' do
post :create, {:key => @user.api_key, :name => 'mychannel', :format => 'json'}
JSON.parse(response.body)['name'].should eq("mychannel")
end
it 'returns XML' do
post :create, {:key => @user.api_key, :name => 'mychannel', :description => 'mydesc', :format => 'xml'}
Nokogiri::XML(response.body).css('description').text.should eq("mydesc")
end
end
describe "clear channel" do
it 'clears a channel' do
@channel.feeds.count.should eq(1)
delete :clear, {:id => @channel.id, :key => @user.api_key}
@channel.feeds.count.should eq(0)
response.should be_redirect
response.should redirect_to(channel_path(@channel.id))
end
it 'returns JSON' do
@channel.feeds.count.should eq(1)
delete :clear, {:id => @channel.id, :key => @user.api_key, :format => 'json'}
@channel.feeds.count.should eq(0)
JSON.parse(response.body).should eq([])
end
it 'returns XML' do
@channel.feeds.count.should eq(1)
delete :clear, {:id => @channel.id, :key => @user.api_key, :format => 'xml'}
@channel.feeds.count.should eq(0)
Nokogiri::XML(response.body).css('nil-classes').text.should eq('')
end
end
describe "delete channel" do
it 'deletes a channel' do
delete :destroy, {:id => @channel.id, :key => @user.api_key}
Channel.find_by_id(@channel.id).should be_nil
response.should be_redirect
response.should redirect_to(channels_path)
end
it 'returns JSON' do
delete :destroy, {:id => @channel.id, :key => @user.api_key, :format => 'json'}
Channel.find_by_id(@channel.id).should be_nil
JSON.parse(response.body)['name'].should eq(@channel.name)
end
it 'returns XML' do
delete :destroy, {:id => @channel.id, :key => @user.api_key, :format => 'xml'}
Channel.find_by_id(@channel.id).should be_nil
Nokogiri::XML(response.body).css('name').text.should eq(@channel.name)
end
end
end
end

View File

@ -6,7 +6,6 @@ describe FeedController do
@channel = FactoryGirl.create(:channel)
now = Time.utc(2013,1,1)
@feed1 = FactoryGirl.create(:feed, :field1 => 10, :channel => @channel, :created_at => now, :entry_id => 1)
@feed = FactoryGirl.create(:feed, :field1 => 10, :channel => @channel, :created_at => now, :entry_id => 2)
@feed = FactoryGirl.create(:feed, :field1 => 9, :channel => @channel, :created_at => now, :entry_id => 3)
@feed = FactoryGirl.create(:feed, :field1 => 7, :channel => @channel, :created_at => now, :entry_id => 4)
@ -59,6 +58,5 @@ describe FeedController do
jsonResponse["field1"].should eq("51.0")
end
end