initial checkin of full application

This commit is contained in:
ioBridge
2011-03-27 16:56:15 -04:00
parent a36868bc86
commit 740a1b338c
127 changed files with 13777 additions and 0 deletions

View File

@ -0,0 +1,45 @@
class ApiKeysController < ApplicationController
before_filter :require_user, :set_channels_menu
def index
get_channel_data
@read_keys = ApiKey.find(:all, :conditions => { :channel_id => @channel.id, :user_id => current_user.id, :write_flag => 0 })
end
def destroy
@api_key = ApiKey.find_by_api_key(params[:api_key])
@api_key.delete if @api_key.user_id == current_user.id
redirect_to :back
end
def create
@channel = Channel.find(params[:channel_id])
# make sure channel belongs to current user
check_permissions(@channel)
@api_key = ApiKey.find(:first, :conditions => { :channel_id => @channel.id, :user_id => current_user.id, :write_flag => 1 } )
# if no api key found or read api key
if (@api_key.nil? or params[:write] == '0')
@api_key = ApiKey.new
@api_key.channel_id = @channel.id
@api_key.user_id = current_user.id
@api_key.write_flag = params[:write]
end
# set new api key and save
@api_key.api_key = generate_api_key
@api_key.save
# redirect
redirect_to channel_api_keys_path(@channel.id) and return
end
def update
@api_key = ApiKey.find_by_api_key(params[:api_key][:api_key])
@api_key.note = params[:api_key][:note]
@api_key.save if current_user.id == @api_key.user_id
redirect_to channel_api_keys_path(@api_key.channel)
end
end

View File

@ -0,0 +1,166 @@
class ApplicationController < ActionController::Base
# include all helpers for controllers
helper :all
# include these helper methods for views
helper_method :current_user_session, :current_user, :get_header_value
protect_from_forgery
before_filter :set_variables
# set up some variables across the entire application
def set_variables
# hard code locale as english
I18n.locale = 'en'
# sets timezone for current user, all DateTime outputs will be automatically formatted
Time.zone = current_user.time_zone if current_user
end
private
def set_channels_menu
@menu = 'channels'
end
def current_user_session
return @current_user_session if defined?(@current_user_session)
@current_user_session = UserSession.find
end
def current_user
return @current_user if defined?(@current_user)
@current_user = current_user_session && current_user_session.record
end
# check that user is logged in
def require_user
if current_user.nil?
redirect_to login_path
false
end
end
def require_no_user
if current_user
store_location
redirect_to account_path
false
end
end
def store_location
if params[:controller] != "user_sessions"
session[:return_to] = request.fullpath
end
end
def redirect_back_or_default(default)
redirect_to(session[:return_to] || default)
session[:return_to] = nil
end
def domain
u = request.url
begin
# the number 12 is the position at which to begin searching for '/', so we don't get the intitial '/' from http://
u = u[0..u.index('/', 12)]
rescue
u += '/'
end
# uncomment the line below for https support in a production environment
#u = u.sub(/http:/, 'https:') if Rails.env == 'production'
return u
end
# gets the api key
def get_userkey
return get_header_value('THINGSPEAKAPIKEY') || params[:key] || params[:api_key] || params[:apikey]
end
# get specified header value
def get_header_value(name)
value = nil
for header in request.env
value = header[1] if (header[0].upcase.index(name.upcase))
end
return value
end
# gets the same data for showing or editing
def get_channel_data
@channel = Channel.find(params[:channel_id]) if params[:channel_id]
@channel = Channel.find(params[:id]) if @channel.nil? and params[:id]
@key = ''
# make sure channel belongs to current user
check_permissions(@channel)
@api_key = ApiKey.find(:first, :conditions => { :channel_id => @channel.id, :user_id => current_user.id, :write_flag => 1 } )
@key = @api_key.api_key if @api_key
end
def check_permissions(channel)
render :text => t(:channel_permission) and return if (current_user.nil? || (channel.user_id != current_user.id))
end
# checks permission for channel using api_key
def channel_permission?(channel, api_key)
if channel.public_flag or (api_key and api_key.channel_id == channel.id) or (current_user and channel.user_id == current_user.id)
return true
else
return false
end
end
# outputs error for bad channel
def bad_channel_xml
channel_unauthorized = Channel.new
channel_unauthorized.id = -1
return channel_unauthorized.to_xml(:only => :id)
end
# outputs error for bad feed
def bad_feed_xml
feed_unauthorized = Feed.new
feedl_unauthorized.id = -1
return feed_unauthorized.to_xml(:only => :entry_id)
end
# generates a database unique api key
def generate_api_key(size = 16)
alphanumerics = ('0'..'9').to_a + ('A'..'Z').to_a
k = (0..size).map {alphanumerics[Kernel.rand(36)]}.join
# if key exists in database, regenerate key
k = generate_api_key if ApiKey.find_by_api_key(k)
# output the key
return k
end
# options: days = how many days ago, start = start date, end = end date, offset = timezone offset
def get_date_range(params)
# set timezone correctly
set_time_zone(params)
start_date = Time.now - 1.day
end_date = Time.now
start_date = (Time.now - params[:days].to_i.days) if params[:days]
start_date = DateTime.strptime(params[:start]) if params[:start]
end_date = DateTime.strptime(params[:end]) if params[:end]
date_range = (start_date..end_date)
# only get a maximum of 30 days worth of data
date_range = (end_date - 30.days..end_date) if (end_date - start_date) > 30.days
return date_range
end
def set_time_zone(params)
# set timezone correctly
if params[:offset]
Time.zone = params[:offset].to_i
elsif current_user
Time.zone = current_user.time_zone
else
Time.zone = 0
end
end
end

View File

@ -0,0 +1,125 @@
class ChannelsController < ApplicationController
before_filter :require_user, :except => [ :show, :post_data ]
before_filter :set_channels_menu
protect_from_forgery :except => :post_data
def index
@channels = current_user.channels
end
def show
@channel = Channel.find(params[:id]) if params[:id]
# if owner of channel
get_channel_data if current_user and @channel.user_id == current_user.id
end
def edit
get_channel_data
end
def update
@channel = Channel.find(params[:id])
# make sure channel belongs to current user
check_permissions(@channel)
# protect against bots
render :text => '' and return if params[:userlogin].length > 0
@channel.update_attributes(params[:channel])
@channel.name = "#{t(:channel_default_name)} #{@channel.id}" if params[:channel][:name].empty?
@channel.save
redirect_to channel_path(@channel.id) and return
end
def create
# protect against bots
render :text => '' and return if params[:userlogin].length > 0
# get default name for field
@d = t(:channel_default_field)
# add channel with defaults
@channel = Channel.new(:field1 => "#{@d}1")
@channel.user_id = current_user.id
@channel.save
# now that the channel is saved, we can create the default name
@channel.name = "#{t(:channel_default_name)} #{@channel.id}"
@channel.save
# create an api key for this channel
@api_key = ApiKey.new
@api_key.channel_id = @channel.id
@api_key.user_id = current_user.id
@api_key.write_flag = 1
@api_key.api_key = generate_api_key
@api_key.save
# redirect to edit the newly created channel
redirect_to edit_channel_path(@channel.id)
end
def destroy
@channel = Channel.find(params[:id])
# make sure channel belongs to current user
check_permissions(@channel)
# do the delete
@channel.delete
redirect_to channels_path
end
# response is '0' if failure, 'entry_id' if success
def post_data
status = '0'
feed = Feed.new
api_key = ApiKey.find_by_api_key(get_userkey)
# if write persmission, allow post
if (api_key && api_key.write_flag)
channel = Channel.find(api_key.channel_id)
# update entry_id for channel and feed
entry_id = channel.last_entry_id.nil? ? 1 : channel.last_entry_id + 1
channel.last_entry_id = entry_id
feed.entry_id = entry_id
# try to get created_at datetime if appropriate
if params[:created_at]
begin
@feed.created_at = DateTime.parse(params[:created_at])
# if invalid datetime, don't do anything--rails will set created_at
rescue
end
end
# strip line feeds from end of parameters
params.each do |key, value|
params[key] = value.sub(/\\n$/, '').sub(/\\r$/, '')
end
# set feed details
feed.channel_id = channel.id
feed.raw_data = params
feed.field1 = params[:field1] if params[:field1]
feed.field2 = params[:field2] if params[:field2]
feed.field3 = params[:field3] if params[:field3]
feed.field4 = params[:field4] if params[:field4]
feed.field5 = params[:field5] if params[:field5]
feed.field6 = params[:field6] if params[:field6]
feed.field7 = params[:field7] if params[:field7]
feed.field8 = params[:field8] if params[:field8]
feed.status = params[:status] if params[:status]
if channel.save && feed.save
status = entry_id
end
end
# output response code
render :text => '0', :status => 400 and return if status == '0'
render :text => status
end
end

View File

@ -0,0 +1,78 @@
class ChartsController < ApplicationController
def index
set_channels_menu
@channel = Channel.find(params[:channel_id])
@channel_id = params[:channel_id]
@domain = domain
# default chart size
@width = default_width
@height = default_height
check_permissions(@channel)
end
def show
# allow these parameters when creating feed querystring
feed_params = ['key','days','start','end','round','timescale','average','median','sum']
# default chart size
@width = default_width
@height = default_height
# add extra parameters to querystring
@qs = ''
params.each do |p|
@qs += "&#{p[0]}=#{p[1]}" if feed_params.include?(p[0])
end
# fix chart colors if necessary
params[:color] = fix_color(params[:color])
params[:bgcolor] = fix_color(params[:bgcolor])
@domain = domain
render :layout => false
end
# save chart options
def update
@channel = Channel.find(params[:channel_id])
@status = 0
# check permissions
if @channel.user_id == current_user.id
# save data
@channel["options#{params[:id]}"] = params[:options]
if @channel.save
@status = 1
end
end
# return response: 1=success, 0=failure
render :json => @status.to_json
end
private
def default_width
450
end
def default_height
250
end
# fixes chart color if user forgets the leading '#'
def fix_color(color)
# check for 3 or 6 character hexadecimal value
if (color and color.match(/^([0-9]|[a-f]|[A-F]){3}(([0-9]|[a-f]|[A-F]){3})?$/))
color = '#' + color
end
return color
end
end

View File

@ -0,0 +1,501 @@
class FeedController < ApplicationController
require 'csv'
def index
channel = Channel.find(params[:channel_id])
api_key = ApiKey.find_by_api_key(get_userkey)
@success = channel_permission?(channel, api_key)
# check for access
if @success
# create options hash
channel_options = { :only => channel_select_data(channel) }
select_options = feed_select_data(channel)
# get feed based on conditions
feeds = Feed.find(
:all,
:conditions => { :channel_id => channel.id, :created_at => get_date_range(params) },
:select => select_options,
:order => 'created_at'
)
# if a feed has data
if !feeds.empty?
# convert to timescales if necessary
if timeparam_valid?(params[:timescale])
feeds = feeds_into_timescales(feeds)
# convert to sums if necessary
elsif timeparam_valid?(params[:sum])
feeds = feeds_into_sums(feeds)
# convert to averages if necessary
elsif timeparam_valid?(params[:average])
feeds = feeds_into_averages(feeds)
# convert to medians if necessary
elsif timeparam_valid?(params[:median])
feeds = feeds_into_medians(feeds)
end
end
# set output correctly
if params[:format] == 'xml'
@channel_output = channel.to_xml(channel_options).sub('</channel>', '').strip
@feed_output = feeds.to_xml(:skip_instruct => true).gsub(/\n/, "\n ").chop.chop
elsif params[:format] == 'csv'
@feed_output = feeds
else
@channel_output = channel.to_json(channel_options).chop
@feed_output = feeds.to_json
end
# else no access, set error code
else
if params[:format] == 'xml'
@channel_output = bad_channel_xml
else
@channel_output = '-1'.to_json
end
end
# set callback for jsonp
@callback = params[:callback] if params[:callback]
# set csv headers if necessary
@csv_headers = select_options if params[:format] == 'csv'
# output proper http response if error
render :text => '-1', :status => 400 and return if !@success
# output data in proper format
respond_to do |format|
format.html
format.json
format.xml
format.csv
end
end
def show
@channel = Channel.find(params[:channel_id])
@api_key = ApiKey.find_by_api_key(get_userkey)
output = '-1'
# get most recent entry if necessary
params[:id] = @channel.last_entry_id if params[:id] == 'last'
# set timezone correctly
set_time_zone(params)
@feed = Feed.find(
:first,
:conditions => { :channel_id => @channel.id, :entry_id => params[:id] },
:select => feed_select_data(@channel)
)
@success = channel_permission?(@channel, @api_key)
# check for access
if @success
# set output correctly
if params[:format] == 'xml'
output = @feed.to_xml
elsif params[:format] == 'csv'
@csv_headers = feed_select_data(@channel)
elsif (params[:format] == 'txt' or params[:format] == 'text')
output = add_prepend_append(@feed["field#{params[:field_id]}"])
else
output = @feed.to_json
end
# else set error code
else
if params[:format] == 'xml'
output = bad_feed_xml
else
output = '-1'.to_json
end
end
# output data in proper format
respond_to do |format|
format.html { render :json => output }
format.json { render :json => output, :callback => params[:callback] }
format.xml { render :xml => output }
format.csv
format.text { render :text => output }
end
end
private
# only output these fields for channel
def channel_select_data(channel)
only = [:name, :created_at, :updated_at, :id, :last_entry_id]
only += [:description] unless channel.description.blank?
only += [:latitude] unless channel.latitude.blank?
only += [:longitude] unless channel.longitude.blank?
only += [:elevation] unless channel.elevation.blank?
only += [:field1] unless channel.field1.blank?
only += [:field2] unless channel.field2.blank?
only += [:field3] unless channel.field3.blank?
only += [:field4] unless channel.field4.blank?
only += [:field5] unless channel.field5.blank?
only += [:field6] unless channel.field6.blank?
only += [:field7] unless channel.field7.blank?
only += [:field8] unless channel.field8.blank?
return only
end
# only output these fields for feed
def feed_select_data(channel)
only = [:created_at]
only += [:entry_id] unless timeparam_valid?(params[:timescale]) or timeparam_valid?(params[:average]) or timeparam_valid?(params[:median]) or timeparam_valid?(params[:sum])
only += [:field1] unless channel.field1.blank? or (params[:field_id] and params[:field_id] != '1')
only += [:field2] unless channel.field2.blank? or (params[:field_id] and params[:field_id] != '2')
only += [:field3] unless channel.field3.blank? or (params[:field_id] and params[:field_id] != '3')
only += [:field4] unless channel.field4.blank? or (params[:field_id] and params[:field_id] != '4')
only += [:field5] unless channel.field5.blank? or (params[:field_id] and params[:field_id] != '5')
only += [:field6] unless channel.field6.blank? or (params[:field_id] and params[:field_id] != '6')
only += [:field7] unless channel.field7.blank? or (params[:field_id] and params[:field_id] != '7')
only += [:field8] unless channel.field8.blank? or (params[:field_id] and params[:field_id] != '8')
only += [:status] if params[:status] and params[:status].upcase == 'TRUE'
return only
end
# checks for valid timescale
def timeparam_valid?(timeparam)
valid_minutes = [10, 15, 20, 30, 60, 240, 720, 1440]
if timeparam and valid_minutes.include?(timeparam.to_i)
return true
else
return false
end
end
# slice feed into timescales
def feeds_into_timescales(feeds)
# convert timescale (minutes) into seconds
seconds = params[:timescale].to_i * 60
# get floored time ranges
start_time = get_floored_time(feeds.first.created_at, seconds)
end_time = get_floored_time(feeds.last.created_at, seconds)
# create empty array with appropriate size
timeslices = Array.new(((end_time - start_time) / seconds).floor)
# create a blank clone of the first feed so that we only get the necessary attributes
empty_feed = create_empty_clone(feeds.first)
# add feeds to array
feeds.each do |f|
i = ((f.created_at - start_time) / seconds).floor
f.created_at = start_time + i * seconds
timeslices[i] = f if timeslices[i].nil?
end
# fill in empty array elements
timeslices.each_index do |i|
if timeslices[i].nil?
current_feed = empty_feed.clone
current_feed.created_at = (start_time + (i * seconds))
timeslices[i] = current_feed
end
end
return timeslices
end
# slice feed into averages
def feeds_into_averages(feeds)
# convert timescale (minutes) into seconds
seconds = params[:average].to_i * 60
# get floored time ranges
start_time = get_floored_time(feeds.first.created_at, seconds)
end_time = get_floored_time(feeds.last.created_at, seconds)
# create empty array with appropriate size
timeslices = Array.new(((end_time - start_time) / seconds).floor)
# create a blank clone of the first feed so that we only get the necessary attributes
empty_feed = create_empty_clone(feeds.first)
# add feeds to array
feeds.each do |f|
i = ((f.created_at - start_time) / seconds).floor
f.created_at = start_time + i * seconds
# create multidimensional array
timeslices[i] = [] if timeslices[i].nil?
timeslices[i].push(f)
end
# keep track of whether numbers use commas as decimals
comma_flag = false
# fill in array
timeslices.each_index do |i|
# insert empty values
if timeslices[i].nil?
current_feed = empty_feed.clone
current_feed.created_at = (start_time + (i * seconds))
timeslices[i] = current_feed
# else average the inner array
else
sum_feed = empty_feed.clone
sum_feed.created_at = timeslices[i].first.created_at
# for each feed
timeslices[i].each do |f|
# for each attribute, add to sum_feed so that we have the total
sum_feed.attribute_names.each do |attr|
# only add non-null integer fields
if attr.index('field') and !f[attr].nil? and is_a_number?(f[attr])
# set comma_flag once if we find a number with a comma
comma_flag = true if !comma_flag and f[attr].to_s.index(',')
# set initial data
if sum_feed[attr].nil?
sum_feed[attr] = parsefloat(f[attr])
# add data
elsif f[attr]
sum_feed[attr] = parsefloat(sum_feed[attr]) + parsefloat(f[attr])
end
end
end
end
# set to the averaged feed
timeslices[i] = object_average(sum_feed, timeslices[i].length, comma_flag, params[:round])
end
end
return timeslices
end
# slice feed into medians
def feeds_into_medians(feeds)
# convert timescale (minutes) into seconds
seconds = params[:median].to_i * 60
# get floored time ranges
start_time = get_floored_time(feeds.first.created_at, seconds)
end_time = get_floored_time(feeds.last.created_at, seconds)
# create empty array with appropriate size
timeslices = Array.new(((end_time - start_time) / seconds).floor)
# create a blank clone of the first feed so that we only get the necessary attributes
empty_feed = create_empty_clone(feeds.first)
# add feeds to array
feeds.each do |f|
i = ((f.created_at - start_time) / seconds).floor
f.created_at = start_time + i * seconds
# create multidimensional array
timeslices[i] = [] if timeslices[i].nil?
timeslices[i].push(f)
end
# keep track of whether numbers use commas as decimals
comma_flag = false
# fill in array
timeslices.each_index do |i|
# insert empty values
if timeslices[i].nil?
current_feed = empty_feed.clone
current_feed.created_at = (start_time + (i * seconds))
timeslices[i] = current_feed
# else get median values for the inner array
else
# create blank hash called 'fields' to hold data
fields = {}
# for each feed
timeslices[i].each do |f|
# for each attribute
f.attribute_names.each do |attr|
if attr.index('field')
# create blank array for each field
fields["#{attr}"] = [] if fields["#{attr}"].nil?
# push numeric field data onto its array
if is_a_number?(f[attr])
# set comma_flag once if we find a number with a comma
comma_flag = true if !comma_flag and f[attr].to_s.index(',')
fields["#{attr}"].push(parsefloat(f[attr]))
end
end
end
end
# sort fields arrays
fields.each_key do |key|
fields[key] = fields[key].compact.sort
end
# get the median
median_feed = empty_feed.clone
median_feed.created_at = timeslices[i].first.created_at
median_feed.attribute_names.each do |attr|
median_feed[attr] = object_median(fields[attr], comma_flag, params[:round]) if attr.index('field')
end
timeslices[i] = median_feed
end
end
return timeslices
end
# slice feed into sums
def feeds_into_sums(feeds)
# convert timescale (minutes) into seconds
seconds = params[:sum].to_i * 60
# get floored time ranges
start_time = get_floored_time(feeds.first.created_at, seconds)
end_time = get_floored_time(feeds.last.created_at, seconds)
# create empty array with appropriate size
timeslices = Array.new(((end_time - start_time) / seconds).floor)
# create a blank clone of the first feed so that we only get the necessary attributes
empty_feed = create_empty_clone(feeds.first)
# add feeds to array
feeds.each do |f|
i = ((f.created_at - start_time) / seconds).floor
f.created_at = start_time + i * seconds
# create multidimensional array
timeslices[i] = [] if timeslices[i].nil?
timeslices[i].push(f)
end
# keep track of whether numbers use commas as decimals
comma_flag = false
# fill in array
timeslices.each_index do |i|
# insert empty values
if timeslices[i].nil?
current_feed = empty_feed.clone
current_feed.created_at = (start_time + (i * seconds))
timeslices[i] = current_feed
# else sum the inner array
else
sum_feed = empty_feed.clone
sum_feed.created_at = timeslices[i].first.created_at
# for each feed
timeslices[i].each do |f|
# for each attribute, add to sum_feed so that we have the total
sum_feed.attribute_names.each do |attr|
# only add non-null integer fields
if attr.index('field') and !f[attr].nil? and is_a_number?(f[attr])
# set comma_flag once if we find a number with a comma
comma_flag = true if !comma_flag and f[attr].to_s.index(',')
# set initial data
if sum_feed[attr].nil?
sum_feed[attr] = parsefloat(f[attr])
# add data
elsif f[attr]
sum_feed[attr] = parsefloat(sum_feed[attr]) + parsefloat(f[attr])
end
end
end
end
# set to the summed feed
timeslices[i] = object_sum(sum_feed, comma_flag, params[:round])
end
end
return timeslices
end
def is_a_number?(s)
s.to_s.gsub(/,/, '.').match(/\A[+-]?\d+?(\.\d+)?\Z/) == nil ? false : true
end
def parsefloat(number)
return number.to_s.gsub(/,/, '.').to_f
end
# gets the median for an object
def object_median(object, comma_flag=false, round=nil)
return nil if object.nil?
length = object.length
return nil if length == 0
output = ''
# do the calculation
if length % 2 == 0
output = (object[(length - 1) / 2] + object[length / 2]) / 2
else
output = object[(length - 1) / 2]
end
output = sprintf "%.#{round}f", output if round and is_a_number?(output)
# replace decimals with commas if appropriate
output = output.to_s.gsub(/\./, ',') if comma_flag
return output.to_s
end
# averages a summed object over length
def object_average(object, length, comma_flag=false, round=nil)
object.attribute_names.each do |attr|
# only average non-null integer fields
if !object[attr].nil? and is_a_number?(object[attr])
if round
object[attr] = sprintf "%.#{round}f", (parsefloat(object[attr]) / length)
else
object[attr] = (parsefloat(object[attr]) / length).to_s
end
# replace decimals with commas if appropriate
object[attr] = object[attr].gsub(/\./, ',') if comma_flag
end
end
return object
end
# formats a summed object correctly
def object_sum(object, comma_flag=false, round=nil)
object.attribute_names.each do |attr|
# only average non-null integer fields
if !object[attr].nil? and is_a_number?(object[attr])
if round
object[attr] = sprintf "%.#{round}f", parsefloat(object[attr])
else
object[attr] = parsefloat(object[attr]).to_s
end
# replace decimals with commas if appropriate
object[attr] = object[attr].gsub(/\./, ',') if comma_flag
end
end
return object
end
# creates an empty clone of an object
def create_empty_clone(object)
empty_clone = object.clone
empty_clone.attribute_names.each { |attr| empty_clone[attr] = nil }
return empty_clone
end
# gets time floored to proper interval
def get_floored_time(input_time, seconds)
return Time.zone.at((input_time.to_f / seconds).floor * seconds)
end
end

View File

@ -0,0 +1,23 @@
class MailerController < ApplicationController
def resetpassword
# protect against bots
render :text => '' and return if params[:userlogin].length > 0
@user = User.find_by_login_or_email(params[:user][:login])
if @user.nil?
sleep 2
session[:mail_message] = t(:account_not_found)
else
begin
@user.reset_perishable_token!
#Mailer.password_reset(@user, "https://www.thingspeak.com/users/reset_password/#{@user.id}?token=#{@user.perishable_token}").deliver
session[:mail_message] = t(:password_reset_mailed)
rescue
session[:mail_message] = t(:password_reset_error)
end
end
redirect_to :controller => 'user_session', :action => 'new'
end
end

View File

@ -0,0 +1,7 @@
class PagesController < ApplicationController
def home
@menu = 'home'
end
end

View File

@ -0,0 +1,113 @@
class StatusController < ApplicationController
require 'csv'
def index
@channel = Channel.find(params[:channel_id])
@api_key = ApiKey.find_by_api_key(get_userkey)
@success = channel_permission?(@channel, @api_key)
# check for access
if @success
# create options hash
channel_options = { :only => channel_select_terse(@channel) }
# display only 1 day by default
params[:days] = 1 if !params[:days]
# get feed based on conditions
@feeds = Feed.find(
:all,
:conditions => { :channel_id => @channel.id, :created_at => get_date_range(params) },
:select => [:created_at, :status],
:order => 'created_at'
)
# set output correctly
if params[:format] == 'xml'
@channel_xml = @channel.to_xml(channel_options).sub('</channel>', '').strip
@feed_xml = @feeds.to_xml(:skip_instruct => true).gsub(/\n/, "\n ").chop.chop
elsif params[:format] == 'csv'
@csv_headers = [:created_at, :status]
else
@channel_json = @channel.to_json(channel_options).chop
@feed_json = @feeds.to_json
end
# else set error code
else
if params[:format] == 'xml'
@channel_xml = bad_channel_xml
else
@channel_json = '-1'.to_json
end
end
# set callback for jsonp
@callback = params[:callback] if params[:callback]
# output data in proper format
respond_to do |format|
format.html { render :text => @feed_json }
format.json { render :action => 'feed/index' }
format.xml { render :action => 'feed/index' }
format.csv { render :action => 'feed/index' }
end
end
def show
@channel = Channel.find(params[:channel_id])
@api_key = ApiKey.find_by_api_key(params[:key])
output = '-1'
# get most recent entry if necessary
params[:id] = @channel.last_entry_id if params[:id] == 'last'
@feed = Feed.find(
:first,
:conditions => { :channel_id => @channel.id, :entry_id => params[:id] },
:select => [:created_at, :status]
)
@success = channel_permission?(@channel, @api_key)
# check for access
if @success
# set output correctly
if params[:format] == 'xml'
output = @feed.to_xml
elsif params[:format] == 'csv'
@csv_headers = [:created_at, :entry_id, :status]
elsif (params[:format] == 'txt' or params[:format] == 'text')
output = add_prepend_append(@feed.status)
else
output = @feed.to_json
end
# else set error code
else
if params[:format] == 'xml'
output = bad_feed_xml
else
output = '-1'.to_json
end
end
# output data in proper format
respond_to do |format|
format.html { render :json => output }
format.json { render :json => output, :callback => params[:callback] }
format.xml { render :xml => output }
format.csv { render :action => 'feed/show' }
format.text { render :text => output }
end
end
private
# only output these fields for channel
def channel_select_terse(channel)
only = [:name]
only += [:latitude] unless channel.latitude.nil?
only += [:longitude] unless channel.longitude.nil?
only += [:elevation] unless channel.elevation.nil? or channel.elevation.empty?
return only
end
end

View File

@ -0,0 +1,15 @@
class SubdomainsController < ApplicationController
# show a blank page if subdomain
def index
render :text => ''
end
# output the file crossdomain.xml.erb
def crossdomain
respond_to do |format|
format.xml
end
end
end

View File

@ -0,0 +1,44 @@
class UserSessionsController < ApplicationController
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => :destroy
def new
@title = t(:signin)
@user_session = UserSession.new
@mail_message = session[:mail_message] if !session[:mail_message].nil?
end
def show
redirect_to root_path
end
def create
if params[:userlogin].length > 0
render :text => ''
else
@user_session = UserSession.new(params[:user_session])
# remember user_id if checkbox is checked
if params[:user_session][:remember_id] == '1'
cookies['user_id'] = { :value => params[:user_session][:login], :expires => 1.month.from_now }
else
cookies.delete 'user_id'
end
if @user_session.save
redirect_to root_path and return
else
# prevent timing and brute force password attacks
sleep 1
@failed = true
render :action => :new
end
end
end
def destroy
current_user_session.destroy
reset_session
redirect_to root_path
end
end

View File

@ -0,0 +1,92 @@
class UsersController < ApplicationController
before_filter :require_no_user, :only => [:new, :create, :forgot_password]
before_filter :require_user, :only => [:show, :edit, :update, :change_password]
def new
@title = t(:signup)
@user = User.new
end
def create
# protect against bots
render :text => '' and return if params[:userlogin].length > 0
# check for invite code
render :text => 'Sorry, you currently need an invite code to sign up.' and return if params[:invite] != '4224'
@user = User.new(params[:user])
# save user
if @user.valid?
if @user.save
redirect_back_or_default account_path and return
end
else
render :action => :new
end
end
def show
@menu = 'account'
@user = @current_user
end
def edit
@menu = 'account'
@user = @current_user
end
# displays forgot password page
def forgot_password
@user = User.new
end
# this action is called from an email link when a password reset is requested
def reset_password
# if user has been logged in (due to previous form submission)
if !current_user.nil?
@user = current_user
@user.errors.add_to_base(t(:password_problem))
@valid_link = true
else
@user = User.find_by_id(params[:id])
# make sure tokens match and password reset is within last 10 minutes
if @user.perishable_token == params[:token] && @user.updated_at > 600.seconds.ago
@valid_link = true
# log the user in
@user_session = UserSession.new(@user)
@user_session.save
end
end
end
# do the actual password change
def change_password
# protect against bots
render :text => '' and return if params[:userlogin].length > 0
@user = current_user
# if no password entered, redirect
redirect_to reset_password_path and return if params[:user][:password].empty?
# check current password and update
if @user.update_attributes(params[:user])
redirect_to account_path
else
redirect_to reset_password_path
end
end
def update
@menu = 'account'
@user = @current_user # makes our views "cleaner" and more consistent
# check current password and update
if @user.valid_password?(params[:password_current]) && @user.update_attributes(params[:user])
redirect_to account_path
else
@user.errors.add_to_base(t(:password_incorrect))
render :action => :edit
end
end
end