Skip to content

Commit

Permalink
Improve channel, user and api_key models with basic scopes, correct r…
Browse files Browse the repository at this point in the history
…eferences and protect attributes.

Simplify channels & user controllers and models, moving code to the models.
Remove catch-all route and ensure all actions are specified, fixing url paths.
Change clone to dup in feed_controller as using clone seems to affect the cloned object (problem only in ruby 1.9.3?)
  • Loading branch information
abradburne committed Feb 9, 2012
1 parent bfd5b29 commit 4f03543
Show file tree
Hide file tree
Showing 21 changed files with 207 additions and 181 deletions.
27 changes: 12 additions & 15 deletions app/controllers/api_keys_controller.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,23 +1,22 @@
class ApiKeysController < ApplicationController class ApiKeysController < ApplicationController
include KeyUtilities

before_filter :require_user, :set_channels_menu before_filter :require_user, :set_channels_menu


def index def index
get_channel_data @channel = current_user.channels.find(params[:channel_id])
@read_keys = ApiKey.find(:all, :conditions => { :channel_id => @channel.id, :user_id => current_user.id, :write_flag => 0 }) @write_key = @channel.api_keys.write_keys.first
@read_keys = @channel.api_keys.read_keys
end end


def destroy def destroy
@api_key = ApiKey.find_by_api_key(params[:api_key]) current_user.api_keys.find_by_api_key(params[:id]).try(:destroy)
@api_key.delete if @api_key.user_id == current_user.id
redirect_to :back redirect_to :back
end end


def create def create
@channel = Channel.find(params[:channel_id]) @channel = current_user.channels.find(params[:channel_id])
# make sure channel belongs to current user @api_key = @channel.api_keys.write_keys.first
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 no api key found or read api key
if (@api_key.nil? or params[:write] == '0') if (@api_key.nil? or params[:write] == '0')
Expand All @@ -32,14 +31,12 @@ def create
@api_key.save @api_key.save


# redirect # redirect
redirect_to channel_api_keys_path(@channel.id) and return redirect_to channel_api_keys_path(@channel)
end end


def update def update
@api_key = ApiKey.find_by_api_key(params[:api_key][:api_key]) @api_key = current_user.api_keys.find_by_api_key(params[:id])

@api_key.update_attributes(params[:api_key])
@api_key.note = params[:api_key][:note] redirect_to :back
@api_key.save if current_user.id == @api_key.user_id
redirect_to channel_api_keys_path(@api_key.channel)
end end
end end
43 changes: 13 additions & 30 deletions app/controllers/application_controller.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -85,24 +85,19 @@ def get_userkey


# get specified header value # get specified header value
def get_header_value(name) def get_header_value(name)
value = nil value = nil
for header in request.env for header in request.env
value = header[1] if (header[0].upcase.index(name.upcase)) value = header[1] if (header[0].upcase.index(name.upcase))
end end
return value return value
end end


# gets the same data for showing or editing # gets the same data for showing or editing
def get_channel_data def get_channel_data
@channel = Channel.find(params[:channel_id]) if params[:channel_id] @channel = current_user.channels.find(params[:channel_id]) if params[:channel_id]
@channel = Channel.find(params[:id]) if @channel.nil? and params[:id] @channel = current_user.channels.find(params[:id]) if @channel.nil? and params[:id]
@key = '' @key = @channel.api_keys.write_keys.first.try(:api_key) || ""
# make sure channel belongs to current user end
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) def check_permissions(channel)
render :text => t(:channel_permission) and return if (current_user.nil? || (channel.user_id != current_user.id)) render :text => t(:channel_permission) and return if (current_user.nil? || (channel.user_id != current_user.id))
Expand Down Expand Up @@ -131,18 +126,6 @@ def bad_feed_xml
return feed_unauthorized.to_xml(:only => :entry_id) return feed_unauthorized.to_xml(:only => :entry_id)
end 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 # options: days = how many days ago, start = start date, end = end date, offset = timezone offset
def get_date_range(params) def get_date_range(params)
# set timezone correctly # set timezone correctly
Expand Down
82 changes: 23 additions & 59 deletions app/controllers/channels_controller.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -21,72 +21,33 @@ def edit
end end


def update def update
@channel = Channel.find(params[:id]) @channel = current_user.channels.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.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 redirect_to channel_path(@channel.id)
end end


def create def create
# protect against bots channel = current_user.channels.create(:field1 => "#{t(:channel_default_field)} 1")
render :text => '' and return if params[:userlogin].length > 0 channel.add_write_api_key


# get default name for field # redirect to edit the newly created channel
@d = t(:channel_default_field) redirect_to edit_channel_path(channel)

end
# add channel with defaults
@channel = Channel.new(:field1 => "#{@d}1") # clear all data from a channel
@channel.user_id = current_user.id def clear
@channel.save channel = current_user.channels.find(params[:id])

channel.feeds.delete_all
# now that the channel is saved, we can create the default name channel.update_attribute(:last_entry_id, nil)
@channel.name = "#{t(:channel_default_name)} #{@channel.id}"
@channel.save redirect_to channels_path

# 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

# clear all data from a channel
def clear
channel = Channel.find(params[:id])
# make sure channel belongs to current user
check_permissions(channel)

# do the delete
channel.feeds.each do |f|
f.delete
end

# set the channel's last_entry_id to nil
channel.last_entry_id = nil
channel.save

redirect_to channels_path
end end


def destroy def destroy
@channel = Channel.find(params[:id]) channel = current_user.channels.find(params[:id])
# make sure channel belongs to current user channel.destroy
check_permissions(@channel)

# do the delete
@channel.delete
redirect_to channels_path redirect_to channels_path
end end


Expand Down Expand Up @@ -255,6 +216,9 @@ def upload
redirect_to channel_path(channel.id) redirect_to channel_path(channel.id)
end end



private

# determine if the date can be parsed # determine if the date can be parsed
def date_parsable?(date) def date_parsable?(date)
return !is_a_number?(date) return !is_a_number?(date)
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/feed_controller.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ def object_sum(object, comma_flag=false, round=nil)


# creates an empty clone of an object # creates an empty clone of an object
def create_empty_clone(object) def create_empty_clone(object)
empty_clone = object.clone empty_clone = object.dup
empty_clone.attribute_names.each { |attr| empty_clone[attr] = nil } empty_clone.attribute_names.each { |attr| empty_clone[attr] = nil }
return empty_clone return empty_clone
end end
Expand Down
9 changes: 3 additions & 6 deletions app/controllers/mailer_controller.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,23 +1,20 @@
class MailerController < ApplicationController class MailerController < ApplicationController


def resetpassword def resetpassword
# protect against bots
render :text => '' and return if params[:userlogin].length > 0

@user = User.find_by_login_or_email(params[:user][:login]) @user = User.find_by_login_or_email(params[:user][:login])

if @user.nil? if @user.nil?
sleep 2
session[:mail_message] = t(:account_not_found) session[:mail_message] = t(:account_not_found)
else else
begin begin
@user.reset_perishable_token! @user.reset_perishable_token!
#Mailer.password_reset(@user, "https://www.thingspeak.com/users/reset_password/#{@user.id}?token=#{@user.perishable_token}").deliver # Mailer.password_reset(@user, "https://www.thingspeak.com/users/#{@user.id}/reset_password?token=#{@user.perishable_token}").deliver
session[:mail_message] = t(:password_reset_mailed) session[:mail_message] = t(:password_reset_mailed)
rescue rescue
session[:mail_message] = t(:password_reset_error) session[:mail_message] = t(:password_reset_error)
end end
end end
redirect_to :controller => 'user_session', :action => 'new' redirect_to login_path
end end


end end
18 changes: 7 additions & 11 deletions app/controllers/users_controller.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -8,15 +8,12 @@ def new
end end


def create def create
# protect against bots
render :text => '' and return if params[:userlogin].length > 0

@user = User.new(params[:user]) @user = User.new(params[:user])


# save user # save user
if @user.valid? if @user.valid?
if @user.save if @user.save
redirect_back_or_default account_path and return redirect_back_or_default account_path
end end
else else
render :action => :new render :action => :new
Expand All @@ -26,25 +23,24 @@ def create


def show def show
@menu = 'account' @menu = 'account'
@user = @current_user @user = current_user
end end


def edit def edit
@menu = 'account' @menu = 'account'
@user = @current_user @user = current_user
end end


# displays forgot password page # displays forgot password page
def forgot_password def forgot_password
@user = User.new
end end


# this action is called from an email link when a password reset is requested # this action is called from an email link when a password reset is requested
def reset_password def reset_password
# if user has been logged in (due to previous form submission) # if user has been logged in (due to previous form submission)
if !current_user.nil? if !current_user.nil?
@user = current_user @user = current_user
@user.errors.add_to_base(t(:password_problem)) @user.errors.add(t(:password_problem))
@valid_link = true @valid_link = true
else else
@user = User.find_by_id(params[:id]) @user = User.find_by_id(params[:id])
Expand Down Expand Up @@ -76,13 +72,13 @@ def change_password


def update def update
@menu = 'account' @menu = 'account'
@user = @current_user # makes our views "cleaner" and more consistent @user = current_user # makes our views "cleaner" and more consistent
# check current password and update # check current password and update
if @user.valid_password?(params[:password_current]) && @user.update_attributes(params[:user]) if @user.valid_password?(params[:password_current]) && @user.update_attributes(params[:user])
redirect_to account_path redirect_to account_path
else else
@user.errors.add_to_base(t(:password_incorrect)) @user.errors.add :base, t(:password_incorrect)
render :action => :edit render :edit
end end
end end


Expand Down
19 changes: 17 additions & 2 deletions app/models/api_key.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,22 @@
class ApiKey < ActiveRecord::Base class ApiKey < ActiveRecord::Base
belongs_to :channel belongs_to :channel
belongs_to :user


validates_uniqueness_of :api_key validates_uniqueness_of :api_key

scope :write_keys, :conditions => { :write_flag => true }
scope :read_keys, :conditions => { :write_flag => false }

attr_readonly :created_at
attr_accessible :note

def to_s
api_key
end

def to_param
api_key
end
end end




Expand Down
35 changes: 34 additions & 1 deletion app/models/channel.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,40 @@
class Channel < ActiveRecord::Base class Channel < ActiveRecord::Base
belongs_to :user include KeyUtilities

belongs_to :user
has_many :feeds has_many :feeds
has_many :api_keys has_many :api_keys

attr_readonly :created_at
attr_protected :user_id, :last_entry_id

after_create :set_initial_default_name
before_validation :set_default_name

validates :name, :presence => true, :on => :update

def add_write_api_key
write_key = self.api_keys.new
write_key.user = self.user
write_key.write_flag = true
write_key.api_key = generate_api_key
write_key.save
end

def field_label(field_number)
self["field#{field_number}"]
end

private

def set_default_name
self.name = "#{I18n.t(:channel_default_name)} #{self.id}" if self.name.blank?
end

def set_initial_default_name
update_attribute(:name, "#{I18n.t(:channel_default_name)} #{self.id}")
end

end end




Expand Down
5 changes: 4 additions & 1 deletion app/models/feed.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,10 @@
class Feed < ActiveRecord::Base class Feed < ActiveRecord::Base
belongs_to :channel belongs_to :channel


self.include_root_in_json = false self.include_root_in_json = false

attr_readonly :created_at
attr_protected :channel_id
end end




Expand Down
Loading

0 comments on commit 4f03543

Please sign in to comment.