update with changes from Production branch
This commit is contained in:
@ -1,14 +1,27 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: api_keys
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# api_key :string(16)
|
||||
# channel_id :integer
|
||||
# user_id :integer
|
||||
# write_flag :boolean default(FALSE)
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# note :string(255)
|
||||
#
|
||||
|
||||
class ApiKey < ActiveRecord::Base
|
||||
belongs_to :channel
|
||||
belongs_to :user
|
||||
|
||||
validates_uniqueness_of :api_key
|
||||
|
||||
scope :write_keys, :conditions => { :write_flag => true }
|
||||
scope :read_keys, :conditions => { :write_flag => false }
|
||||
scope :write_keys, lambda { where("write_flag = true") }
|
||||
scope :read_keys, lambda { where("write_flag = false") }
|
||||
|
||||
attr_readonly :created_at
|
||||
attr_accessible :note
|
||||
|
||||
def to_s
|
||||
api_key
|
||||
@ -22,18 +35,3 @@ end
|
||||
|
||||
|
||||
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: api_keys
|
||||
#
|
||||
# id :integer(4) not null, primary key
|
||||
# api_key :string(16)
|
||||
# channel_id :integer(4)
|
||||
# user_id :integer(4)
|
||||
# write_flag :boolean(1) default(FALSE)
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# note :string(255)
|
||||
#
|
||||
|
||||
|
@ -1,18 +1,392 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: channels
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer
|
||||
# name :string(255)
|
||||
# description :string(255)
|
||||
# latitude :decimal(15, 10)
|
||||
# longitude :decimal(15, 10)
|
||||
# field1 :string(255)
|
||||
# field2 :string(255)
|
||||
# field3 :string(255)
|
||||
# field4 :string(255)
|
||||
# field5 :string(255)
|
||||
# field6 :string(255)
|
||||
# field7 :string(255)
|
||||
# field8 :string(255)
|
||||
# scale1 :integer
|
||||
# scale2 :integer
|
||||
# scale3 :integer
|
||||
# scale4 :integer
|
||||
# scale5 :integer
|
||||
# scale6 :integer
|
||||
# scale7 :integer
|
||||
# scale8 :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# elevation :string(255)
|
||||
# last_entry_id :integer
|
||||
# public_flag :boolean default(FALSE)
|
||||
# options1 :string(255)
|
||||
# options2 :string(255)
|
||||
# options3 :string(255)
|
||||
# options4 :string(255)
|
||||
# options5 :string(255)
|
||||
# options6 :string(255)
|
||||
# options7 :string(255)
|
||||
# options8 :string(255)
|
||||
# social :boolean default(FALSE)
|
||||
# slug :string(255)
|
||||
# status :string(255)
|
||||
# url :string(255)
|
||||
# video_id :string(255)
|
||||
# video_type :string(255)
|
||||
# clearing :boolean default(FALSE), not null
|
||||
# ranking :integer
|
||||
#
|
||||
|
||||
class Channel < ActiveRecord::Base
|
||||
include KeyUtilities
|
||||
|
||||
|
||||
belongs_to :user
|
||||
has_many :feeds
|
||||
has_many :api_keys
|
||||
has_many :feeds
|
||||
has_many :daily_feeds
|
||||
has_many :api_keys, :dependent => :destroy
|
||||
has_many :taggings
|
||||
has_many :tags, :through => :taggings
|
||||
has_many :comments, :dependent => :destroy
|
||||
has_many :windows, :dependent => :destroy, :autosave => true
|
||||
|
||||
self.include_root_in_json = true
|
||||
|
||||
attr_readonly :created_at
|
||||
attr_protected :user_id, :last_entry_id
|
||||
|
||||
after_create :set_initial_default_name
|
||||
before_validation :set_default_name
|
||||
after_destroy :delete_feeds
|
||||
|
||||
validates :name, :presence => true, :on => :update
|
||||
after_commit :set_default_name
|
||||
after_commit :set_ranking, :unless => "ranking == calc_ranking"
|
||||
|
||||
before_destroy :delete_feeds
|
||||
|
||||
validates :video_type, :presence => true, :if => lambda{ |channel| !channel.video_id.nil? && !channel.video_id.empty?}
|
||||
|
||||
scope :public_viewable, lambda { where("public_flag = true AND social != true") }
|
||||
scope :is_public, lambda { where("public_flag = true") }
|
||||
scope :active, lambda { where("channels.last_entry_id > 1 and channels.updated_at > ?", DateTime.now.utc - 7.day) }
|
||||
scope :being_cleared, lambda { where("clearing = true") }
|
||||
scope :by_array, lambda {|ids| { :conditions => ["id in (?)", ids.uniq] } }
|
||||
scope :with_tag, lambda {|name| joins(:tags).where("tags.name = ?", name) }
|
||||
|
||||
# pagination variables
|
||||
cattr_reader :per_page
|
||||
@@per_page = 15
|
||||
|
||||
# select options
|
||||
def select_options
|
||||
only = [:name, :created_at, :updated_at, :id, :last_entry_id]
|
||||
only += [:description] unless self.description.blank?
|
||||
only += [:latitude] unless self.latitude.blank?
|
||||
only += [:longitude] unless self.longitude.blank?
|
||||
only += [:elevation] unless self.elevation.blank?
|
||||
only += [:field1] unless self.field1.blank?
|
||||
only += [:field2] unless self.field2.blank?
|
||||
only += [:field3] unless self.field3.blank?
|
||||
only += [:field4] unless self.field4.blank?
|
||||
only += [:field5] unless self.field5.blank?
|
||||
only += [:field6] unless self.field6.blank?
|
||||
only += [:field7] unless self.field7.blank?
|
||||
only += [:field8] unless self.field8.blank?
|
||||
|
||||
# return a hash
|
||||
return { :only => only }
|
||||
end
|
||||
|
||||
# adds a feed to the channel
|
||||
def add_status_feed(status)
|
||||
# update the entry_id for the channel
|
||||
entry_id = self.next_entry_id
|
||||
self.last_entry_id = entry_id
|
||||
self.save
|
||||
# create the new feed with the correct status and entry_id
|
||||
self.feeds.create(:status => status, :entry_id => entry_id)
|
||||
end
|
||||
|
||||
# get next last_entry_id for a channel
|
||||
def next_entry_id
|
||||
self.last_entry_id.nil? ? 1 : self.last_entry_id + 1
|
||||
end
|
||||
|
||||
# for internal admin use, shows the ids of a channel per month (useful as a proxy for growth)
|
||||
def show_growth
|
||||
output = []
|
||||
date = self.feeds.order("entry_id asc").first.created_at
|
||||
|
||||
# while the date is in the past
|
||||
while (date < Time.now)
|
||||
# get a feed on that day
|
||||
feed = self.feeds.where("created_at > ?", date).where("created_at < ?", date + 1.day).first
|
||||
# output the date and feed id
|
||||
output << "#{date.strftime('%Y-%m-%d')},#{feed.id}" if feed.present?
|
||||
# set the date 1 month further
|
||||
date = date + 1.month
|
||||
end
|
||||
|
||||
# show the output
|
||||
puts output.join("\n")
|
||||
end
|
||||
|
||||
# paginated hash for json and xml output
|
||||
# channels input must be paginated
|
||||
def self.paginated_hash(channels)
|
||||
{
|
||||
pagination:
|
||||
{
|
||||
current_page: channels.current_page,
|
||||
per_page: channels.per_page,
|
||||
total_entries: channels.total_entries,
|
||||
},
|
||||
channels: channels.as_json(Channel.public_options)
|
||||
}
|
||||
end
|
||||
|
||||
# for to_json or to_xml, return only the public attributes
|
||||
def self.public_options
|
||||
{
|
||||
:root => false,
|
||||
:only => [:id, :name, :description, :latitude, :longitude, :last_entry_id, :elevation, :created_at, :ranking],
|
||||
:methods => :username,
|
||||
:include => { :tags => {:only => [:id, :name]}}
|
||||
}
|
||||
end
|
||||
|
||||
# login name of the user who created the channel
|
||||
def username; self.user.try(:login); end
|
||||
|
||||
# custom as_json method to allow: root => false
|
||||
def as_json(options = nil)
|
||||
root = include_root_in_json
|
||||
root = options[:root] if options.try(:key?, :root)
|
||||
if root
|
||||
root = self.class.model_name.element if root == true
|
||||
{ root => serializable_hash(options) }
|
||||
else
|
||||
serializable_hash(options)
|
||||
end
|
||||
end
|
||||
|
||||
def private_windows *hidden
|
||||
if hidden.size >= 1
|
||||
return windows.where("private_flag = true and show_flag = #{hidden[0].to_s}")
|
||||
else
|
||||
return windows.where("private_flag = true" )
|
||||
end
|
||||
end
|
||||
|
||||
# overloaded version witthout private/public flag for the has_many dependent destroy action
|
||||
def public_windows hidden
|
||||
return windows.where("private_flag = false and show_flag = #{hidden}")
|
||||
end
|
||||
# measure of activity in terms of feeds per time period
|
||||
|
||||
def public?
|
||||
return public_flag
|
||||
end
|
||||
|
||||
def video_changed?
|
||||
video_id_changed? || video_type_changed?
|
||||
end
|
||||
|
||||
def location_changed?
|
||||
latitude_changed? || longitude_changed?
|
||||
end
|
||||
|
||||
def feeds_changed?
|
||||
field1_changed? ||
|
||||
field2_changed? ||
|
||||
field3_changed? ||
|
||||
field4_changed? ||
|
||||
field5_changed? ||
|
||||
field6_changed? ||
|
||||
field7_changed? ||
|
||||
field8_changed?
|
||||
end
|
||||
|
||||
def update_chart_portlets
|
||||
self.fields.each do |field|
|
||||
update_chart_portlet field, true
|
||||
update_chart_portlet field, false
|
||||
end
|
||||
#remove portlets for fields that don't exist
|
||||
#iterate all chart windows... and look for a matching field
|
||||
chartWindows = windows.where(:wtype => :chart )
|
||||
chartWindows.each do |window|
|
||||
if self.send(window.name).blank?
|
||||
window.destroy
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def update_status_portlet isPrivate
|
||||
|
||||
window = windows.where(:wtype => :status, :private_flag => isPrivate )
|
||||
|
||||
status_html = "<iframe class=\"statusIFrame\" width=\"450\" height=\"260\" frameborder=\"0\" src=\"/channels/#{id}/status/recent\"></iframe>"
|
||||
|
||||
if window.nil? || window[0].nil?
|
||||
|
||||
window = PortletWindow.new
|
||||
window.wtype = :status
|
||||
window.position = 1
|
||||
window.col = 1
|
||||
window.title = "window_status"
|
||||
else
|
||||
|
||||
window = window[0]
|
||||
end
|
||||
|
||||
window.private_flag = isPrivate
|
||||
window.html = status_html
|
||||
window.window_detail = PortletWindowDetail.new if window.window_detail.nil?
|
||||
self.windows.push window
|
||||
|
||||
end
|
||||
|
||||
def video_fields_valid?
|
||||
!video_id.nil? && !video_id.empty? && !video_type.nil? && !video_type.empty?
|
||||
end
|
||||
|
||||
def update_video_portlet isPrivate
|
||||
window = windows.where(:wtype => :video, :private_flag => isPrivate )
|
||||
if video_fields_valid?
|
||||
youtube_html = "<iframe class=\"youtube-player\" type=\"text/html\" width=\"452\" height=\"260\" src=\"https://www.youtube.com/embed/#{video_id}?wmode=transparent\" frameborder=\"0\" wmode=\"Opaque\" ></iframe>"
|
||||
vimeo_html = "<iframe class=\"vimeo-player\" type=\"text/html\" width=\"452\" height=\"260\" src=\"http://player.vimeo.com/video/#{video_id}\" frameborder=\"0\"></iframe>"
|
||||
if window.nil? || window[0].nil?
|
||||
window = PortletWindow.new
|
||||
window.wtype = :video
|
||||
window.position = 1
|
||||
window.col = 1
|
||||
window.title = "window_channel_video"
|
||||
else
|
||||
window = window[0]
|
||||
end
|
||||
window.private_flag = isPrivate
|
||||
window.html = youtube_html if video_type == 'youtube'
|
||||
window.html = vimeo_html if video_type == 'vimeo'
|
||||
window.window_detail = PortletWindowDetail.new if window.window_detail.nil?
|
||||
self.windows.push window
|
||||
else
|
||||
unless window[0].nil?
|
||||
window[0].delete
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update_location_portlet isPrivate
|
||||
window = windows.where(:wtype => :location, :private_flag => isPrivate )
|
||||
if !latitude.nil? && !longitude.nil?
|
||||
maps_html = "<iframe width=\"450\" height=\"260\" frameborder=\"0\" scrolling=\"no\" " +
|
||||
"src=\"/channels/#{id}/maps/channel_show?width=450&height=260\"></iframe>"
|
||||
if window.nil? || window[0].nil?
|
||||
window = PortletWindow.new
|
||||
window.wtype = :location
|
||||
window.position = 0
|
||||
window.col = 1
|
||||
window.title = "window_map"
|
||||
else
|
||||
window = window[0]
|
||||
end
|
||||
window.private_flag = isPrivate
|
||||
window.html = maps_html
|
||||
window.window_detail = PortletWindowDetail.new if window.window_detail.nil?
|
||||
|
||||
self.windows.push window
|
||||
|
||||
else
|
||||
unless window[0].nil?
|
||||
|
||||
window[0].delete
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# get recent status messages from channel
|
||||
def recent_statuses
|
||||
self.feeds.select('status, created_at, entry_id').order('created_at DESC').limit(30).collect {|f| f unless f.status.blank? }.compact
|
||||
end
|
||||
|
||||
def latest_feed
|
||||
self.feeds.where(:entry_id => self.last_entry_id).first
|
||||
end
|
||||
|
||||
def delete_feeds
|
||||
if self.feeds.count < 1000
|
||||
Feed.delete_all(["channel_id = ?", self.id])
|
||||
DailyFeed.delete_all(["channel_id = ?", self.id])
|
||||
begin
|
||||
self.update_attribute(:last_entry_id, nil)
|
||||
rescue Exception => e
|
||||
end
|
||||
|
||||
else
|
||||
self.update_attribute(:clearing, true)
|
||||
Resque.enqueue(ClearChannelJob, self.id)
|
||||
end
|
||||
end
|
||||
|
||||
# true if channel is active
|
||||
def active?
|
||||
return (last_entry_id and updated_at and last_entry_id > 1 and updated_at > DateTime.now.utc - 1.days)
|
||||
end
|
||||
|
||||
def list_tags
|
||||
(self.tags.collect { |t| t.name }).join(', ')
|
||||
end
|
||||
|
||||
def save_tags(tags)
|
||||
# for each tag
|
||||
tags.split(',').each do |name|
|
||||
tag = Tag.find_by_name(name.strip)
|
||||
# save if new tag
|
||||
if tag.nil?
|
||||
tag = Tag.new
|
||||
tag.name = name.strip
|
||||
tag.save
|
||||
end
|
||||
|
||||
tagging = Tagging.find(:first, :conditions => { :tag_id => tag.id, :channel_id => self.id})
|
||||
# save if new tagging
|
||||
if tagging.nil?
|
||||
tagging = Tagging.new
|
||||
tagging.channel_id = self.id
|
||||
tagging.tag_id = tag.id
|
||||
tagging.save
|
||||
end
|
||||
end
|
||||
|
||||
# delete any tags that were removed
|
||||
self.remove_tags(tags)
|
||||
end
|
||||
|
||||
# if tags don't exist anymore, remove them
|
||||
def remove_tags(tags)
|
||||
tag_array = tags.split(',')
|
||||
# remove white space
|
||||
tag_array = tag_array.collect {|t| t.strip }
|
||||
|
||||
# get all taggings for this channel
|
||||
taggings = Tagging.find(:all, :conditions => { :channel_id => self.id }, :include => :tag)
|
||||
|
||||
# check for existence
|
||||
taggings.each do |tagging|
|
||||
# if tagging is not in list
|
||||
if !tag_array.include?(tagging.tag.name)
|
||||
# delete tagging
|
||||
tagging.delete
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def add_write_api_key
|
||||
write_key = self.api_keys.new
|
||||
@ -22,61 +396,102 @@ class Channel < ActiveRecord::Base
|
||||
write_key.save
|
||||
end
|
||||
|
||||
def queue_react
|
||||
self.reacts.on_insertion.each do |react|
|
||||
begin
|
||||
Resque.enqueue(ReactJob, react.id)
|
||||
rescue Exception => e
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def field_label(field_number)
|
||||
self.attributes["field#{field_number}"]
|
||||
end
|
||||
|
||||
def delete_feeds
|
||||
Feed.delete_all(["channel_id = ?", self.id])
|
||||
|
||||
def fields
|
||||
fields = attribute_names.reject { |x|
|
||||
!(x.index('field') && self[x] && !self[x].empty?)
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
def calc_ranking
|
||||
result = 0
|
||||
result = result + 15 unless name.blank?
|
||||
result = result + 20 unless description.blank?
|
||||
result = result + 15 unless latitude.blank? || longitude.blank?
|
||||
result = result + 15 unless url.blank?
|
||||
result = result + 15 unless video_id.blank? || video_type.blank?
|
||||
|
||||
def set_default_name
|
||||
self.name = "#{I18n.t(:channel_default_name)} #{self.id}" if self.name.blank?
|
||||
result = result + 20 unless tags.empty?
|
||||
result
|
||||
end
|
||||
|
||||
def set_initial_default_name
|
||||
update_attribute(:name, "#{I18n.t(:channel_default_name)} #{self.id}")
|
||||
def set_windows
|
||||
#check for video window
|
||||
if video_changed?
|
||||
update_video_portlet true
|
||||
update_video_portlet false
|
||||
end
|
||||
|
||||
#does channel have a location and corresponding google map
|
||||
if location_changed?
|
||||
update_location_portlet true
|
||||
update_location_portlet false
|
||||
end
|
||||
|
||||
#does channel have status and corresponding status window. Add the status window no matter what. Only display if it has values
|
||||
update_status_portlet true
|
||||
update_status_portlet false
|
||||
|
||||
#does channel have a window for every chart element
|
||||
if feeds_changed?
|
||||
update_chart_portlets
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_ranking
|
||||
update_attribute(:ranking, calc_ranking) unless ranking == calc_ranking
|
||||
|
||||
end
|
||||
def update_chart_portlet (field, isPrivate)
|
||||
|
||||
chartWindows = windows.where(:type => "ChartWindow", :name => "field#{field.last.to_s}", :private_flag => isPrivate )
|
||||
if chartWindows.nil? || chartWindows[0].nil?
|
||||
window = ChartWindow.new
|
||||
window.wtype = :chart
|
||||
window.position = 0
|
||||
window.col = 0
|
||||
window.title = "window_field_chart"
|
||||
window.name = field.to_s
|
||||
window.window_detail = ChartWindowDetail.new
|
||||
window.window_detail.options = "&results=60&dynamic=true"
|
||||
else
|
||||
window = chartWindows[0]
|
||||
# If there are options, use them.. if options are not available, then assign defaults
|
||||
window.window_detail.options ||= "&results=60&dynamic=true"
|
||||
end
|
||||
|
||||
window.window_detail.field_number = field.last
|
||||
window.private_flag = isPrivate
|
||||
windows.push window
|
||||
window.html ="<iframe id=\"iframe#{window.id}\" width=\"450\" height=\"260\" style=\"border: 1px solid #cccccc;\" src=\"/channels/#{id}/charts/#{field.last.to_s}?width=450&height=260::OPTIONS::\" ></iframe>"
|
||||
|
||||
if !window.save
|
||||
raise "The Window could not be saved"
|
||||
end
|
||||
end
|
||||
|
||||
def set_default_name
|
||||
update_attribute(:name, "#{I18n.t(:channel_default_name)} #{self.id}") if self.name.blank?
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: channels
|
||||
#
|
||||
# id :integer(4) not null, primary key
|
||||
# user_id :integer(4)
|
||||
# name :string(255)
|
||||
# description :string(255)
|
||||
# latitude :decimal(15, 10)
|
||||
# longitude :decimal(15, 10)
|
||||
# field1 :text
|
||||
# field2 :text
|
||||
# field3 :text
|
||||
# field4 :text
|
||||
# field5 :text
|
||||
# field6 :text
|
||||
# field7 :text
|
||||
# field8 :text
|
||||
# scale1 :integer(4)
|
||||
# scale2 :integer(4)
|
||||
# scale3 :integer(4)
|
||||
# scale4 :integer(4)
|
||||
# scale5 :integer(4)
|
||||
# scale6 :integer(4)
|
||||
# scale7 :integer(4)
|
||||
# scale8 :integer(4)
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# elevation :string(255)
|
||||
# last_entry_id :integer(4)
|
||||
# public_flag :boolean(1) default(FALSE)
|
||||
#
|
||||
|
||||
|
8
app/models/chart.rb
Normal file
8
app/models/chart.rb
Normal file
@ -0,0 +1,8 @@
|
||||
class Chart
|
||||
def self.default_width
|
||||
450
|
||||
end
|
||||
def self.default_height
|
||||
250
|
||||
end
|
||||
end
|
22
app/models/chart_window.rb
Normal file
22
app/models/chart_window.rb
Normal file
@ -0,0 +1,22 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: windows
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# channel_id :integer
|
||||
# position :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# html :text
|
||||
# col :integer
|
||||
# title :string(255)
|
||||
# wtype :string(255)
|
||||
# name :string(255)
|
||||
# type :string(255)
|
||||
# private_flag :boolean default(FALSE)
|
||||
# show_flag :boolean default(TRUE)
|
||||
#
|
||||
|
||||
class ChartWindow < Window
|
||||
relate_to_details
|
||||
end
|
14
app/models/chart_window_detail.rb
Normal file
14
app/models/chart_window_detail.rb
Normal file
@ -0,0 +1,14 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: chart_window_details
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# chart_window_id :integer
|
||||
# field_number :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# options :string(255)
|
||||
#
|
||||
|
||||
class ChartWindowDetail < ActiveRecord::Base
|
||||
end
|
32
app/models/comment.rb
Normal file
32
app/models/comment.rb
Normal file
@ -0,0 +1,32 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: comments
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# parent_id :integer
|
||||
# body :text
|
||||
# flags :integer
|
||||
# user_id :integer
|
||||
# ip_address :string(255)
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# channel_id :integer
|
||||
#
|
||||
|
||||
class Comment < ActiveRecord::Base
|
||||
belongs_to :channel
|
||||
belongs_to :user
|
||||
acts_as_tree :order => 'created_at'
|
||||
|
||||
validates :body, :presence => true
|
||||
validates_associated :user
|
||||
|
||||
before_create :set_defaults
|
||||
|
||||
private
|
||||
|
||||
def set_defaults
|
||||
self.flags = 0
|
||||
end
|
||||
end
|
||||
|
47
app/models/daily_feed.rb
Normal file
47
app/models/daily_feed.rb
Normal file
@ -0,0 +1,47 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: daily_feeds
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# channel_id :integer
|
||||
# date :date
|
||||
# calculation :string(20)
|
||||
# result :string(255)
|
||||
# field :integer
|
||||
#
|
||||
|
||||
class DailyFeed < ActiveRecord::Base
|
||||
belongs_to :channel
|
||||
|
||||
self.include_root_in_json = false
|
||||
|
||||
# update a feed if it exists, or else create it
|
||||
def self.my_create_or_update(attributes)
|
||||
# try to get daily feed
|
||||
daily_feed = DailyFeed.where(attributes).first
|
||||
# if there is an existing daily feed
|
||||
if daily_feed.present?
|
||||
# update it
|
||||
daily_feed.update_attributes(attributes)
|
||||
# else create it
|
||||
else
|
||||
daily_feed = DailyFeed.create(attributes)
|
||||
end
|
||||
end
|
||||
|
||||
# gets the calculation type
|
||||
def self.calculation_type(params)
|
||||
output = nil
|
||||
output = 'timescale' if params[:timescale].present?
|
||||
output = 'sum' if params[:sum].present?
|
||||
output = 'average' if params[:average].present?
|
||||
output = 'median' if params[:median].present?
|
||||
return output
|
||||
end
|
||||
|
||||
# checks to see if this is a daily feed
|
||||
def self.valid_params(params)
|
||||
(params[:timescale] == '1440' || params[:sum] == '1440' || params[:average] == '1440' || params[:median] == '1440') ? true : false
|
||||
end
|
||||
|
||||
end
|
41
app/models/error_response.rb
Normal file
41
app/models/error_response.rb
Normal file
@ -0,0 +1,41 @@
|
||||
class ErrorResponse
|
||||
|
||||
def initialize(error_code)
|
||||
error_object = I18n.t(:error_codes)[error_code]
|
||||
@error_code = error_code.to_s
|
||||
@http_status = error_object[:http_status]
|
||||
@message = error_object[:message]
|
||||
@details = error_object[:details]
|
||||
end
|
||||
|
||||
# attributes that can be read
|
||||
attr_reader :error_code, :http_status, :message, :details
|
||||
|
||||
# custom json format
|
||||
def as_json(options = nil)
|
||||
{
|
||||
:status => "#{http_status}",
|
||||
:error => {
|
||||
:error_code => error_code,
|
||||
:message => message,
|
||||
:details => details
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# custom xml format
|
||||
def to_xml
|
||||
output = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||
output += "<hash>\n"
|
||||
output += " <status>#{http_status}</status>\n"
|
||||
output += " <error>\n"
|
||||
output += " <error-code>#{error_code}</error-code>\n"
|
||||
output += " <message>#{message}</message>\n"
|
||||
output += " <details>#{details}</details>\n"
|
||||
output += " </error>\n"
|
||||
output += "</hash>"
|
||||
return output
|
||||
end
|
||||
|
||||
end
|
||||
|
14
app/models/failedlogin.rb
Normal file
14
app/models/failedlogin.rb
Normal file
@ -0,0 +1,14 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: failedlogins
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# login :string(255)
|
||||
# password :string(255)
|
||||
# ip_address :string(255)
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
class Failedlogin < ActiveRecord::Base
|
||||
end
|
@ -1,33 +1,137 @@
|
||||
class Feed < ActiveRecord::Base
|
||||
belongs_to :channel
|
||||
|
||||
self.include_root_in_json = false
|
||||
|
||||
attr_readonly :created_at
|
||||
attr_protected :channel_id
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: feeds
|
||||
#
|
||||
# id :integer(4) not null, primary key
|
||||
# channel_id :integer(4)
|
||||
# raw_data :text
|
||||
# field1 :text
|
||||
# field2 :text
|
||||
# field3 :text
|
||||
# field4 :text
|
||||
# field5 :text
|
||||
# field6 :text
|
||||
# field7 :text
|
||||
# field8 :text
|
||||
# id :integer not null, primary key
|
||||
# channel_id :integer
|
||||
# field1 :string(255)
|
||||
# field2 :string(255)
|
||||
# field3 :string(255)
|
||||
# field4 :string(255)
|
||||
# field5 :string(255)
|
||||
# field6 :string(255)
|
||||
# field7 :string(255)
|
||||
# field8 :string(255)
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# entry_id :integer(4)
|
||||
# entry_id :integer
|
||||
# status :string(255)
|
||||
# latitude :decimal(15, 10)
|
||||
# longitude :decimal(15, 10)
|
||||
# elevation :string(255)
|
||||
# location :string(255)
|
||||
#
|
||||
|
||||
class Feed < ActiveRecord::Base
|
||||
extend FeedHelper
|
||||
belongs_to :channel
|
||||
|
||||
after_commit :queue_react
|
||||
delegate :queue_react, :to => :channel
|
||||
|
||||
self.include_root_in_json = false
|
||||
|
||||
attr_readonly :created_at
|
||||
|
||||
# only output these fields for feed
|
||||
def self.select_options(channel, params)
|
||||
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].index('1'))
|
||||
only += [:field2] unless channel.field2.blank? or (params[:field_id] and !params[:field_id].index('2'))
|
||||
only += [:field3] unless channel.field3.blank? or (params[:field_id] and !params[:field_id].index('3'))
|
||||
only += [:field4] unless channel.field4.blank? or (params[:field_id] and !params[:field_id].index('4'))
|
||||
only += [:field5] unless channel.field5.blank? or (params[:field_id] and !params[:field_id].index('5'))
|
||||
only += [:field6] unless channel.field6.blank? or (params[:field_id] and !params[:field_id].index('6'))
|
||||
only += [:field7] unless channel.field7.blank? or (params[:field_id] and !params[:field_id].index('7'))
|
||||
only += [:field8] unless channel.field8.blank? or (params[:field_id] and !params[:field_id].index('8'))
|
||||
|
||||
# add geolocation data if necessary
|
||||
if params[:location] and params[:location].upcase == 'TRUE'
|
||||
only += [:latitude]
|
||||
only += [:longitude]
|
||||
only += [:elevation]
|
||||
only += [:location]
|
||||
end
|
||||
|
||||
# add status if necessary
|
||||
only += [:status] if params[:status] and params[:status].upcase == 'TRUE'
|
||||
return only
|
||||
end
|
||||
|
||||
# outputs feed info correctly, used by daily_feeds
|
||||
def self.normalize_feeds(daily_feeds)
|
||||
output = []
|
||||
hash = {}
|
||||
|
||||
# for each daily feed
|
||||
daily_feeds.each do |daily_feed|
|
||||
# check if the feed already exists
|
||||
existing_feed = hash[daily_feed['date']]
|
||||
|
||||
# skip blank feeds
|
||||
next if daily_feed['date'].blank?
|
||||
|
||||
# if the feed exists
|
||||
if existing_feed.present?
|
||||
# add the new field
|
||||
existing_feed["field#{daily_feed['field']}"] = daily_feed['result']
|
||||
# else add a new feed
|
||||
else
|
||||
new_feed = Feed.new(:created_at => daily_feed['date'])
|
||||
# set the field attribute correctly
|
||||
new_feed["field#{daily_feed['field']}"] = daily_feed['result']
|
||||
# add the feed
|
||||
hash[daily_feed['date']] = new_feed
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# turn the hash into an array
|
||||
output = hash.values
|
||||
|
||||
# sort by date
|
||||
return output
|
||||
end
|
||||
|
||||
# custom json output
|
||||
def as_json(options = {})
|
||||
super(options.merge(:except => [:updated_at, :id]))
|
||||
end
|
||||
|
||||
# check if a field value is a number
|
||||
# usage: Feed.numeric?(field_value)
|
||||
def self.numeric?(object)
|
||||
true if Float(object) rescue false
|
||||
end
|
||||
|
||||
def field(number)
|
||||
self.attributes["field#{number.to_i}"]
|
||||
end
|
||||
|
||||
# make sure any selected fields are greater than a minimum
|
||||
def greater_than?(minimum)
|
||||
output = true
|
||||
self.attributes.each do |attribute|
|
||||
# if this attribute is a numeric field with a value
|
||||
if attribute[0].to_s.index('field') == 0 && attribute[1].present? && Feed.numeric?(attribute[1])
|
||||
output = false if attribute[1].to_f < minimum.to_f
|
||||
end
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
# make sure any selected fields are less than a minimum
|
||||
def less_than?(maximum)
|
||||
output = true
|
||||
self.attributes.each do |attribute|
|
||||
# if this attribute is a numeric field with a value
|
||||
if attribute[0].to_s.index('field') == 0 && attribute[1].present? && Feed.numeric?(attribute[1])
|
||||
output = false if attribute[1].to_f > maximum.to_f
|
||||
end
|
||||
end
|
||||
return output
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
197
app/models/feed_factory.rb
Normal file
197
app/models/feed_factory.rb
Normal file
@ -0,0 +1,197 @@
|
||||
class FeedFactory < ApplicationController
|
||||
include FeedHelper
|
||||
|
||||
def initialize(options = {})
|
||||
@options = options # alias for params
|
||||
@feeds = nil
|
||||
@daily_feeds = nil
|
||||
@output_feeds = nil
|
||||
@rounded = false
|
||||
@channel = Channel.find(options[:channel_id])
|
||||
@date_range = get_date_range(options)
|
||||
@daily_date_range = @date_range.first.to_date..@date_range.last.to_date
|
||||
@limit = calculate_limit
|
||||
@use_daily_feed = DailyFeed.valid_params(options) # determine whether daily feed should be used
|
||||
@calculation_type = DailyFeed.calculation_type(options) # set the calculation type
|
||||
@feed_select_options = Feed.select_options(@channel, @options)
|
||||
@cache_feeds = cache_feeds?
|
||||
end
|
||||
|
||||
# attributes that can be read
|
||||
attr_reader :feeds, :daily_feeds, :limit, :use_daily_feed, :feed_select_options, :cache_feeds
|
||||
|
||||
# calculate the limit that should be used
|
||||
def calculate_limit
|
||||
limit = 100
|
||||
limit = 8000 if @options[:results].present? || @options[:days].present? || @options[:start].present? || @options[:end].present?
|
||||
limit = @options[:results].to_i if (@options[:results].present? && @options[:results].to_i < 8000)
|
||||
return limit
|
||||
end
|
||||
|
||||
# determine if data should be cached
|
||||
def cache_feeds?
|
||||
cache = false
|
||||
cache = true if (@channel.last_entry_id.present? && @channel.last_entry_id > 100 && @limit > 100)
|
||||
cache = true if @options[:days].present?
|
||||
return cache
|
||||
end
|
||||
|
||||
# if daily feeds exist, use that first, or else use regular feeds
|
||||
def get_output_feeds
|
||||
# get daily feeds
|
||||
get_daily_feeds if @use_daily_feed == true
|
||||
|
||||
# get feeds normally if no daily feeds
|
||||
get_feeds if @daily_feeds.blank?
|
||||
|
||||
# set minimum and maximum parameters, and round output feeds
|
||||
format_output_feeds
|
||||
|
||||
return @output_feeds
|
||||
end
|
||||
|
||||
# get feed for a date
|
||||
def get_feed_data_for_date(date)
|
||||
# get feeds for this date
|
||||
feeds = Feed.where(:channel_id => @channel.id, :created_at => date..(date + 1.day))
|
||||
.select(@feed_select_options).order('created_at asc').load
|
||||
|
||||
# calculate the feed
|
||||
feed = calculate_feeds(feeds).first
|
||||
|
||||
# add blank feed for this date if necessary
|
||||
feed = Feed.new(:created_at => date) if feed.nil?
|
||||
|
||||
return feed
|
||||
end
|
||||
|
||||
# add a daily feed for a specific date
|
||||
def add_daily_feed_for_date(date)
|
||||
# get the feed data
|
||||
feed = get_feed_data_for_date(date)
|
||||
|
||||
# for each attribute
|
||||
@feed_select_options.each do |attr|
|
||||
key = attr.to_s
|
||||
# if this attribute is a field
|
||||
if key.index('field') == 0
|
||||
# get the field number
|
||||
field_number = key.sub('field', '').to_i
|
||||
# add the feed; replace with Rails 4 create_or_update if appropriate
|
||||
DailyFeed.my_create_or_update({:channel_id => @channel.id, :date => feed.created_at, :calculation => @calculation_type, :field => field_number, :result => feed[key]})
|
||||
end
|
||||
end
|
||||
|
||||
# add to existing daily feeds
|
||||
@daily_feeds << feed
|
||||
end
|
||||
|
||||
# get feeds
|
||||
def get_feeds
|
||||
# get feed based on conditions
|
||||
@feeds = Feed.where(:channel_id => @channel.id, :created_at => @date_range)
|
||||
.select(@feed_select_options)
|
||||
.order('created_at desc')
|
||||
.limit(@limit)
|
||||
.load
|
||||
|
||||
# sort properly
|
||||
@feeds.reverse!
|
||||
|
||||
# calculate feeds
|
||||
@feeds = calculate_feeds(@feeds)
|
||||
end
|
||||
|
||||
# gets daily feeds
|
||||
def get_daily_feeds
|
||||
sql_date_range = (@daily_date_range.first + 1.day)..(@daily_date_range.last + 1.day)
|
||||
# if this is for a specific field
|
||||
if @options[:field_id].present?
|
||||
@daily_feeds = DailyFeed.where(:channel_id => @channel.id, :calculation => @calculation_type, :date => sql_date_range, :field => @options[:field_id]).order('date desc').load
|
||||
# else get daily feeds for all fields
|
||||
else
|
||||
@daily_feeds = DailyFeed.where(:channel_id => @channel.id, :calculation => @calculation_type, :date => sql_date_range).order('date desc').load
|
||||
end
|
||||
|
||||
# normalize if there are daily feeds
|
||||
@daily_feeds = Feed.normalize_feeds(@daily_feeds) if @daily_feeds.present?
|
||||
|
||||
# get dates that are missing from daily feed
|
||||
add_missing_daily_feeds
|
||||
|
||||
# add todays data
|
||||
add_daily_feed_for_today
|
||||
|
||||
# sort correctly
|
||||
@daily_feeds.sort!{ |x, y| x.created_at <=> y.created_at }
|
||||
end
|
||||
|
||||
# add feed data for today
|
||||
def add_daily_feed_for_today
|
||||
@daily_feeds << get_feed_data_for_date(Time.now.to_date) if @options[:days].present?
|
||||
end
|
||||
|
||||
# get dates that are missing from daily feed
|
||||
def add_missing_daily_feeds
|
||||
missing_dates = []
|
||||
current_date = @daily_date_range.first + 1.day
|
||||
# if current date is older than channel date, set it to channel date
|
||||
current_date = @channel.created_at.to_date if @date_range.first < @channel.created_at
|
||||
end_date = @daily_date_range.last
|
||||
|
||||
# get dates that exist in daily feeds
|
||||
daily_feed_dates = {}
|
||||
@daily_feeds.each { |feed| daily_feed_dates[feed.created_at.to_date] = true }
|
||||
|
||||
# iterate through each date
|
||||
while current_date < end_date
|
||||
# add missing dates
|
||||
missing_dates << current_date if daily_feed_dates[current_date] != true
|
||||
# go to the next day
|
||||
current_date += 1.day
|
||||
end
|
||||
|
||||
# add daily feeds for any missing days
|
||||
missing_dates.each { |date| add_daily_feed_for_date(date) }
|
||||
end
|
||||
|
||||
# apply rounding and min/max
|
||||
def format_output_feeds
|
||||
# set output feeds
|
||||
@output_feeds = (@daily_feeds.present? ? @daily_feeds : @feeds)
|
||||
|
||||
# only get feeds that match min and max values
|
||||
@output_feeds = @output_feeds.select{ |x| x.greater_than?(@options[:min]) } if @options[:min].present?
|
||||
@output_feeds = @output_feeds.select{ |x| x.less_than?(@options[:max]) } if @options[:max].present?
|
||||
|
||||
# round feeds if necessary
|
||||
@output_feeds = object_round(@output_feeds, @options[:round].to_i) if @options[:round] && !@rounded
|
||||
end
|
||||
|
||||
# calculate feeds
|
||||
def calculate_feeds(feeds)
|
||||
# if a feed has data
|
||||
if feeds.present?
|
||||
# convert to timescales if necessary
|
||||
if timeparam_valid?(@options[:timescale])
|
||||
feeds = feeds_into_timescales(feeds, @options)
|
||||
# convert to sums if necessary
|
||||
elsif timeparam_valid?(@options[:sum])
|
||||
feeds = feeds_into_sums(feeds, @options)
|
||||
@rounded = true
|
||||
# convert to averages if necessary
|
||||
elsif timeparam_valid?(@options[:average])
|
||||
feeds = feeds_into_averages(feeds, @options)
|
||||
@rounded = true
|
||||
# convert to medians if necessary
|
||||
elsif timeparam_valid?(@options[:median])
|
||||
feeds = feeds_into_medians(feeds, @options)
|
||||
@rounded = true
|
||||
end
|
||||
end
|
||||
|
||||
return feeds
|
||||
end
|
||||
|
||||
end
|
||||
|
16
app/models/header.rb
Normal file
16
app/models/header.rb
Normal file
@ -0,0 +1,16 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: headers
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string(255)
|
||||
# value :string(255)
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# thinghttp_id :integer
|
||||
#
|
||||
|
||||
class Header < ActiveRecord::Base
|
||||
belongs_to :thinghttp
|
||||
end
|
||||
|
@ -1,11 +1,11 @@
|
||||
class Mailer < ActionMailer::Base
|
||||
#default :from => 'support@thingspeak.com'
|
||||
default :from => 'support@thingspeak.com'
|
||||
|
||||
def password_reset(user, webpage)
|
||||
@user = user
|
||||
@webpage = webpage
|
||||
mail(:to => @user.email,
|
||||
:subject => t(:password_reset_subject))
|
||||
end
|
||||
@user = user
|
||||
@webpage = webpage
|
||||
mail(:to => @user.email,
|
||||
:subject => t(:password_reset_subject))
|
||||
end
|
||||
|
||||
end
|
||||
|
22
app/models/pipe.rb
Normal file
22
app/models/pipe.rb
Normal file
@ -0,0 +1,22 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: pipes
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string(255) not null
|
||||
# url :string(255) not null
|
||||
# slug :string(255) not null
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# parse :string(255)
|
||||
# cache :integer
|
||||
#
|
||||
|
||||
class Pipe < ActiveRecord::Base
|
||||
|
||||
# pagination variables
|
||||
cattr_reader :per_page
|
||||
@@per_page = 50
|
||||
|
||||
end
|
||||
|
134
app/models/plugin.rb
Normal file
134
app/models/plugin.rb
Normal file
@ -0,0 +1,134 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: plugins
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string(255)
|
||||
# user_id :integer
|
||||
# html :text
|
||||
# css :text
|
||||
# js :text
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# private_flag :boolean default(TRUE)
|
||||
#
|
||||
|
||||
class Plugin < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
has_many :plugin_window_details
|
||||
has_many :windows, :through => :plugin_window_details, :source => :plugin_window
|
||||
before_destroy { |record| record.windows.each { |window| window.delete } }
|
||||
|
||||
def destroy_window
|
||||
window_id = PluginWindowDetail.find_by_plugin_id(self.id).plugin_window_id
|
||||
Window.delete(window_id)
|
||||
end
|
||||
|
||||
def private?
|
||||
private_flag
|
||||
end
|
||||
|
||||
def public?
|
||||
!private_flag
|
||||
end
|
||||
|
||||
def has_private_windows(channel_id)
|
||||
has_private_windows = false
|
||||
windows.each do |window|
|
||||
|
||||
if window.private? && window.channel_id == channel_id
|
||||
has_private_windows = true
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return has_private_windows
|
||||
end
|
||||
|
||||
def has_public_windows(channel_id)
|
||||
has_public_windows = false
|
||||
windows.each do |window|
|
||||
has_public_windows = true if !window.private? && window.channel_id == channel_id
|
||||
end
|
||||
return has_public_windows
|
||||
end
|
||||
|
||||
#private_dashboard_visibility
|
||||
def private_dashboard_windows(channel_id)
|
||||
dashboard_windows channel_id, true
|
||||
end
|
||||
|
||||
def public_dashboard_windows(channel_id)
|
||||
dashboard_windows channel_id, false
|
||||
end
|
||||
def dashboard_windows(channel_id, privacy)
|
||||
dashboard_windows = []
|
||||
windows.each do |window|
|
||||
if window.private_flag == privacy && !window.show_flag && channel_id == window.channel_id
|
||||
dashboard_windows << window
|
||||
end
|
||||
end
|
||||
dashboard_windows
|
||||
end
|
||||
|
||||
#public_dashboard_visibility
|
||||
def public_window
|
||||
public_window = nil
|
||||
windows.each do |window|
|
||||
if !window.private_flag # && !window.show_flag
|
||||
public_window = window
|
||||
end
|
||||
end
|
||||
unless public_window.nil?
|
||||
public_window
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def make_windows(channel_id, api_domain)
|
||||
pluginWindows = []
|
||||
#create all the windows as appropriate
|
||||
#Private plugins have one window..
|
||||
#Public plugins have a private/private windows, private/public window and a public window
|
||||
if !has_public_windows(channel_id) && self.public?
|
||||
windows << PluginWindow.new_from(self, channel_id, :public, api_domain)
|
||||
else
|
||||
update_windows(channel_id)
|
||||
end
|
||||
|
||||
if !has_private_windows(channel_id)
|
||||
windows << Window.new_from(self, channel_id, :private, api_domain)
|
||||
end
|
||||
save
|
||||
end
|
||||
|
||||
def update_windows(channel_id)
|
||||
|
||||
windows.each do |window|
|
||||
window.name = self.name
|
||||
window.save
|
||||
end
|
||||
|
||||
if has_public_windows(channel_id) && self.private?
|
||||
windows.delete(public_window.destroy) unless public_window.nil?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def update_all_windows
|
||||
channel_ids = Set.new
|
||||
windows.each do |window|
|
||||
window.name = self.name
|
||||
channel_ids.add( window.channel_id)
|
||||
window.save
|
||||
end
|
||||
channel_ids.each do |id|
|
||||
if has_public_windows(id) && self.private?
|
||||
windows.delete(public_window.destroy) unless public_window.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
23
app/models/plugin_window.rb
Normal file
23
app/models/plugin_window.rb
Normal file
@ -0,0 +1,23 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: windows
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# channel_id :integer
|
||||
# position :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# html :text
|
||||
# col :integer
|
||||
# title :string(255)
|
||||
# wtype :string(255)
|
||||
# name :string(255)
|
||||
# type :string(255)
|
||||
# private_flag :boolean default(FALSE)
|
||||
# show_flag :boolean default(TRUE)
|
||||
#
|
||||
|
||||
class PluginWindow < Window
|
||||
relate_to_details
|
||||
end
|
||||
|
16
app/models/plugin_window_detail.rb
Normal file
16
app/models/plugin_window_detail.rb
Normal file
@ -0,0 +1,16 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: plugin_window_details
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# plugin_id :integer
|
||||
# plugin_window_id :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
class PluginWindowDetail < ActiveRecord::Base
|
||||
belongs_to :plugin_window
|
||||
belongs_to :plugin
|
||||
|
||||
end
|
22
app/models/portlet_window.rb
Normal file
22
app/models/portlet_window.rb
Normal file
@ -0,0 +1,22 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: windows
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# channel_id :integer
|
||||
# position :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# html :text
|
||||
# col :integer
|
||||
# title :string(255)
|
||||
# wtype :string(255)
|
||||
# name :string(255)
|
||||
# type :string(255)
|
||||
# private_flag :boolean default(FALSE)
|
||||
# show_flag :boolean default(TRUE)
|
||||
#
|
||||
|
||||
class PortletWindow < Window
|
||||
relate_to_details
|
||||
end
|
12
app/models/portlet_window_detail.rb
Normal file
12
app/models/portlet_window_detail.rb
Normal file
@ -0,0 +1,12 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: portlet_window_details
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# portlet_window_id :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
class PortletWindowDetail < ActiveRecord::Base
|
||||
end
|
19
app/models/tag.rb
Normal file
19
app/models/tag.rb
Normal file
@ -0,0 +1,19 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: tags
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# name :string(255)
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
class Tag < ActiveRecord::Base
|
||||
has_many :taggings
|
||||
has_many :channels, :through => :taggings
|
||||
|
||||
validates_presence_of :name
|
||||
|
||||
self.include_root_in_json = false
|
||||
|
||||
end
|
15
app/models/tagging.rb
Normal file
15
app/models/tagging.rb
Normal file
@ -0,0 +1,15 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: taggings
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# tag_id :integer
|
||||
# channel_id :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
class Tagging < ActiveRecord::Base
|
||||
belongs_to :tag
|
||||
belongs_to :channel
|
||||
end
|
57
app/models/twitter_account.rb
Normal file
57
app/models/twitter_account.rb
Normal file
@ -0,0 +1,57 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: twitter_accounts
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# screen_name :string(255)
|
||||
# user_id :integer
|
||||
# twitter_id :integer
|
||||
# token :string(255)
|
||||
# secret :string(255)
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# api_key :string(17) not null
|
||||
#
|
||||
|
||||
class TwitterAccount < ActiveRecord::Base
|
||||
include KeyUtilities
|
||||
|
||||
belongs_to :user
|
||||
has_many :reacts, :as => :actionable, :dependent => :restrict_with_exception
|
||||
|
||||
# pagination variables
|
||||
cattr_reader :per_page
|
||||
@@per_page = 50
|
||||
|
||||
before_create :set_api_key
|
||||
|
||||
def renew_api_key
|
||||
self.update_attribute(:api_key, generate_api_key(16, 'twitter'))
|
||||
end
|
||||
|
||||
def tweet(status, opts = {})
|
||||
opts.delete('api_key')
|
||||
opts.delete('controller')
|
||||
opts.delete('action')
|
||||
|
||||
client = TwitterOAuth::Client.new(
|
||||
:consumer_key => CONSUMER_KEY,
|
||||
:consumer_secret => CONSUMER_SECRET,
|
||||
:token => self.token,
|
||||
:secret => self.secret
|
||||
)
|
||||
|
||||
client.update(status, opts)
|
||||
|
||||
rescue Twitter::Error::Unauthorized
|
||||
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_api_key
|
||||
self.api_key = generate_api_key(16, 'twitter')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,26 +1,14 @@
|
||||
class User < ActiveRecord::Base
|
||||
has_many :channels
|
||||
has_many :api_keys
|
||||
|
||||
acts_as_authentic
|
||||
|
||||
def self.find_by_login_or_email(login)
|
||||
User.find_by_login(login) || User.find_by_email(login)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: users
|
||||
#
|
||||
# id :integer(4) not null, primary key
|
||||
# login :string(255) not null
|
||||
# email :string(255) not null
|
||||
# crypted_password :string(255) not null
|
||||
# password_salt :string(255) not null
|
||||
# persistence_token :string(255) not null
|
||||
# perishable_token :string(255) not null
|
||||
# id :integer not null, primary key
|
||||
# login :string(255) not null
|
||||
# email :string(255) not null
|
||||
# crypted_password :string(255) not null
|
||||
# password_salt :string(255) not null
|
||||
# persistence_token :string(255) not null
|
||||
# perishable_token :string(255) not null
|
||||
# current_login_at :datetime
|
||||
# last_login_at :datetime
|
||||
# current_login_ip :string(255)
|
||||
@ -28,5 +16,78 @@ end
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# time_zone :string(255)
|
||||
# public_flag :boolean default(FALSE)
|
||||
# bio :text
|
||||
# website :string(255)
|
||||
# api_key :string(16)
|
||||
#
|
||||
|
||||
####### NOTE #######
|
||||
# user.api_keys is a collection of channel api_keys (read and write)
|
||||
# user.api_key is a single api_key that allows control of a user's account
|
||||
####################
|
||||
class User < ActiveRecord::Base
|
||||
include KeyUtilities
|
||||
has_many :channels
|
||||
has_many :twitter_accounts, :dependent => :destroy
|
||||
has_many :thinghttps, :dependent => :destroy
|
||||
has_many :tweetcontrols, :dependent => :destroy
|
||||
has_many :reacts, :dependent => :destroy
|
||||
has_many :scheduled_thinghttps, :dependent => :destroy
|
||||
has_many :talkbacks, :dependent => :destroy
|
||||
has_many :plugins
|
||||
has_many :devices
|
||||
has_many :api_keys
|
||||
has_many :watchings, :dependent => :destroy
|
||||
has_many :watched_channels, :through => :watchings, :source => :channel
|
||||
has_many :comments
|
||||
|
||||
acts_as_authentic
|
||||
|
||||
self.include_root_in_json = false
|
||||
|
||||
# pagination variables
|
||||
cattr_reader :per_page
|
||||
@@per_page = 50
|
||||
|
||||
# find a user using login or email
|
||||
def self.find_by_login_or_email(login)
|
||||
User.find_by_login(login) || User.find_by_email(login)
|
||||
end
|
||||
|
||||
# get user signups per day
|
||||
def self.signups_per_day
|
||||
sql = 'select DATE_FORMAT(created_at,"%Y-%m-%d") as day, count(id) as signups from users group by day'
|
||||
days = ActiveRecord::Base.connection.execute(sql)
|
||||
return days
|
||||
end
|
||||
|
||||
# for to_json or to_xml, return only the public attributes
|
||||
def self.public_options(user)
|
||||
output = { :only => [:id, :login, :created_at] }
|
||||
|
||||
# if the profile is public
|
||||
if user.public_flag == true
|
||||
additional_options = { :only => [:website, :bio] }
|
||||
# merge in the additional options by adding the values
|
||||
output.merge!(additional_options){ |key, oldval, newval| oldval + newval }
|
||||
end
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
# for to_json or to_xml, return the correct private attributes
|
||||
def self.private_options
|
||||
{ :only => [:id, :login, :created_at, :email, :website, :bio] }
|
||||
end
|
||||
|
||||
# set new api key
|
||||
def set_new_api_key!
|
||||
new_api_key = generate_api_key(16, 'user')
|
||||
self.update_column(:api_key, new_api_key)
|
||||
return new_api_key
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
class UserSession < Authlogic::Session::Base
|
||||
find_by_login_method :find_by_login_or_email
|
||||
find_by_login_method :find_by_login_or_email
|
||||
|
||||
def to_key
|
||||
new_record? ? nil : [ self.send(self.class.primary_key) ]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
22
app/models/watching.rb
Normal file
22
app/models/watching.rb
Normal file
@ -0,0 +1,22 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: watchings
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer
|
||||
# channel_id :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
class Watching < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
belongs_to :channel
|
||||
|
||||
# check if the channel is being watched by this user
|
||||
def self.check(user_id, channel_id)
|
||||
@watching = Watching.find_by_user_id_and_channel_id(user_id, channel_id)
|
||||
return @watching.nil? ? false : true
|
||||
end
|
||||
|
||||
end
|
50
app/models/window.rb
Normal file
50
app/models/window.rb
Normal file
@ -0,0 +1,50 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: windows
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# channel_id :integer
|
||||
# position :integer
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
# html :text
|
||||
# col :integer
|
||||
# title :string(255)
|
||||
# wtype :string(255)
|
||||
# name :string(255)
|
||||
# type :string(255)
|
||||
# private_flag :boolean default(FALSE)
|
||||
# show_flag :boolean default(TRUE)
|
||||
#
|
||||
|
||||
class Window < ActiveRecord::Base
|
||||
belongs_to :channel
|
||||
|
||||
self.include_root_in_json = true
|
||||
|
||||
def self.relate_to_details
|
||||
class_eval <<-EOF
|
||||
has_one :window_detail, :class_name => "#{self.name}Detail"
|
||||
accepts_nested_attributes_for :window_detail
|
||||
default_scope { includes(:window_detail) }
|
||||
EOF
|
||||
end
|
||||
def private?
|
||||
return private_flag
|
||||
end
|
||||
|
||||
def self.new_from( plugin, channel_id, privacy_flag, api_domain )
|
||||
window = PluginWindow.new
|
||||
window.wtype = :plugin
|
||||
window.position = 0
|
||||
window.col = 0
|
||||
window.title = "window_plugin"
|
||||
window.name = plugin.name
|
||||
window.private_flag = (privacy_flag == :private)
|
||||
window.channel = Channel.find(channel_id)
|
||||
window.html ="<iframe width=\"450\" height=\"260\" style=\"border: 1px solid #cccccc;\" src=\"/plugins/#{plugin.id}\" ></iframe>"
|
||||
window.show_flag = false
|
||||
window if window.save
|
||||
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user